Bug 1671034 - Avoid creating CTFonts from CGFonts. r=lsalzman

The CGFonts end up in a cache that we don't want. Creating the CTFonts
directly should avoid this.

Notes:
add_native_font normally takes a CGFont and we need a CTFontDescriptor
so we convert to postscript name and then postscript name to
CTFontDescriptor. This is wasteful but avoids needing to change the
external API.

To avoid copying the data in the Vec we use a CFAllocator to wrap the
Vec for use by CFData

Differential Revision: https://phabricator.services.mozilla.com/D93518
This commit is contained in:
Jeff Muizelaar 2020-10-14 20:42:25 +00:00
Родитель b4aecd470f
Коммит 25c5cd2354
7 изменённых файлов: 154 добавлений и 51 удалений

4
Cargo.lock сгенерированный
Просмотреть файл

@ -688,9 +688,9 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
version = "0.8.0"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]]
name = "core-graphics"

6
gfx/wr/Cargo.lock сгенерированный
Просмотреть файл

@ -288,7 +288,7 @@ name = "core-foundation"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -304,7 +304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "core-foundation-sys"
version = "0.8.0"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -2083,7 +2083,7 @@ dependencies = [
"checksum core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5ed8e7e76c45974e15e41bfa8d5b0483cd90191639e01d8f5f1e606299d3fb"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
"checksum core-foundation-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"
"checksum core-foundation-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
"checksum core-graphics 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6082396a349fa49674ba1bda4077332a18bf150e8fa75745ece07085e29a113"
"checksum core-graphics-types 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e92f5d519093a4178296707dbaa3880eae85a5ef5386675f361a1cf25376e93c"

Просмотреть файл

@ -4,7 +4,7 @@
use api::{ColorU, FontKey, FontRenderMode, FontSize, GlyphDimensions};
use api::{FontInstanceFlags, FontVariation, NativeFontHandle};
use core_foundation::array::{CFArray, CFArrayRef};
use core_foundation::{array::{CFArray, CFArrayRef}, data::CFData};
use core_foundation::base::TCFType;
use core_foundation::dictionary::CFDictionary;
use core_foundation::number::{CFNumber, CFNumberRef};
@ -14,12 +14,12 @@ use core_graphics::base::{kCGBitmapByteOrder32Little};
use core_graphics::color_space::CGColorSpace;
use core_graphics::context::CGContext;
use core_graphics::context::{CGBlendMode, CGTextDrawingMode};
use core_graphics::data_provider::CGDataProvider;
use core_graphics::font::{CGFont, CGGlyph};
use core_graphics::font::CGGlyph;
use core_graphics::geometry::{CGAffineTransform, CGPoint, CGSize};
use core_graphics::geometry::{CG_AFFINE_TRANSFORM_IDENTITY, CGRect};
use core_text;
use core_text::{self, font_descriptor::CTFontDescriptorCreateCopyWithAttributes};
use core_text::font::{CTFont, CTFontRef};
use core_text::font_descriptor::CTFontDescriptor;
use core_text::font_descriptor::{kCTFontDefaultOrientation, kCTFontColorGlyphsTrait};
use euclid::default::Size2D;
use crate::gamma_lut::{ColorLut, GammaLut};
@ -32,7 +32,7 @@ use std::sync::Arc;
const INITIAL_CG_CONTEXT_SIDE_LENGTH: u32 = 32;
pub struct FontContext {
cg_fonts: FastHashMap<FontKey, CGFont>,
ct_font_descs: FastHashMap<FontKey, CTFontDescriptor>,
ct_fonts: FastHashMap<(FontKey, FontSize, Vec<FontVariation>), CTFont>,
#[allow(dead_code)]
graphics_context: GraphicsContext,
@ -206,13 +206,14 @@ extern {
static kCTFontVariationAxisMinimumValueKey: CFStringRef;
static kCTFontVariationAxisMaximumValueKey: CFStringRef;
static kCTFontVariationAxisDefaultValueKey: CFStringRef;
static kCTFontVariationAttribute: CFStringRef;
fn CTFontCopyVariationAxes(font: CTFontRef) -> CFArrayRef;
}
fn new_ct_font_with_variations(cg_font: &CGFont, size: f64, variations: &[FontVariation]) -> CTFont {
fn new_ct_font_with_variations(ct_font_desc: &CTFontDescriptor, size: f64, variations: &[FontVariation]) -> CTFont {
unsafe {
let ct_font = core_text::font::new_from_CGFont(cg_font, size);
let ct_font = core_text::font::new_from_descriptor(ct_font_desc, size);
if variations.is_empty() {
return ct_font;
}
@ -301,8 +302,9 @@ fn new_ct_font_with_variations(cg_font: &CGFont, size: f64, variations: &[FontVa
return ct_font;
}
let vals_dict = CFDictionary::from_CFType_pairs(&vals);
let cg_var_font = cg_font.create_copy_from_variations(&vals_dict).unwrap();
core_text::font::new_from_CGFont_with_variations(&cg_var_font, size, &vals_dict)
let attrs_dict = CFDictionary::from_CFType_pairs(&[(CFString::wrap_under_get_rule(kCTFontVariationAttribute), vals_dict)]);
let ct_var_font_desc = create_copy_with_attributes(ct_font_desc, attrs_dict.to_untyped()).unwrap();
core_text::font::new_from_descriptor(&ct_var_font_desc, size)
}
}
@ -320,7 +322,7 @@ impl FontContext {
let gamma = 0.0;
Ok(FontContext {
cg_fonts: FastHashMap::default(),
ct_font_descs: FastHashMap::default(),
ct_fonts: FastHashMap::default(),
graphics_context: GraphicsContext::new(),
gamma_lut: GammaLut::new(contrast, gamma, gamma),
@ -328,34 +330,40 @@ impl FontContext {
}
pub fn has_font(&self, font_key: &FontKey) -> bool {
self.cg_fonts.contains_key(font_key)
self.ct_font_descs.contains_key(font_key)
}
pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: Arc<Vec<u8>>, index: u32) {
if self.cg_fonts.contains_key(font_key) {
if self.ct_font_descs.contains_key(font_key) {
return;
}
assert_eq!(index, 0);
let data_provider = CGDataProvider::from_buffer(bytes);
let cg_font = match CGFont::from_data_provider(data_provider) {
let data = CFData_wrapping_arc_vec(bytes);
let ct_font_desc = match create_font_descriptor(data) {
Err(_) => return,
Ok(cg_font) => cg_font,
};
self.cg_fonts.insert(*font_key, cg_font);
self.ct_font_descs.insert(*font_key, ct_font_desc);
}
pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) {
if self.cg_fonts.contains_key(font_key) {
if self.ct_font_descs.contains_key(font_key) {
return;
}
self.cg_fonts
.insert(*font_key, native_font_handle.0);
// there's no way great way to go from a CGFont to a CTFontDescriptor
// so we use the postscript name. Ideally NativeFontHandle would
// just use a CTFontDescriptor
let name = native_font_handle.0.postscript_name();
let font = core_text::font_descriptor::new_from_postscript_name(&name);
self.ct_font_descs
.insert(*font_key, font);
}
pub fn delete_font(&mut self, font_key: &FontKey) {
if let Some(_) = self.cg_fonts.remove(font_key) {
if let Some(_) = self.ct_font_descs.remove(font_key) {
self.ct_fonts.retain(|k, _| k.0 != *font_key);
}
}
@ -375,7 +383,7 @@ impl FontContext {
match self.ct_fonts.entry((font_key, FontSize::from_f64_px(size), variations.to_vec())) {
Entry::Occupied(entry) => Some((*entry.get()).clone()),
Entry::Vacant(entry) => {
let cg_font = self.cg_fonts.get(&font_key)?;
let cg_font = self.ct_font_descs.get(&font_key)?;
let ct_font = new_ct_font_with_variations(cg_font, size, variations);
entry.insert(ct_font.clone());
Some(ct_font)
@ -909,3 +917,72 @@ enum GlyphType {
Vector,
Bitmap,
}
// This stuff should eventually migrate to upstream core-foundation
#[allow(non_snake_case)]
fn CFData_wrapping_arc_vec(buffer: Arc<Vec<u8>>) -> CFData {
use core_foundation::base::*;
use core_foundation::data::CFDataRef;
use std::os::raw::c_void;
extern "C" {
pub fn CFDataCreateWithBytesNoCopy(
allocator: CFAllocatorRef,
bytes: *const u8,
length: CFIndex,
allocator: CFAllocatorRef,
) -> CFDataRef;
}
unsafe {
let ptr = (*buffer).as_ptr() as *const _;
let len = buffer.len().to_CFIndex();
let info = Arc::into_raw(buffer) as *mut c_void;
extern "C" fn deallocate(_: *mut c_void, info: *mut c_void) {
unsafe {
drop(Arc::from_raw(info as *mut Vec<u8>));
}
}
// CFAllocatorContext doesn't have nullable members so we transmute
let allocator = CFAllocator::new(CFAllocatorContext {
info: info,
version: 0,
retain: None,
reallocate: None,
release: None,
copyDescription: None,
allocate: None,
deallocate: Some(deallocate),
preferredSize: None,
});
let data_ref =
CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, ptr, len, allocator.as_CFTypeRef());
TCFType::wrap_under_create_rule(data_ref)
}
}
fn create_font_descriptor(cf_data: CFData) -> Result<CTFontDescriptor, ()> {
use core_text::font_descriptor::CTFontDescriptorRef;
use core_foundation::data::CFDataRef;
extern {
pub fn CTFontManagerCreateFontDescriptorFromData(data: CFDataRef) -> CTFontDescriptorRef;
}
unsafe {
let ct_font_descriptor_ref = CTFontManagerCreateFontDescriptorFromData(cf_data.as_concrete_TypeRef());
if ct_font_descriptor_ref.is_null() {
return Err(());
}
Ok(CTFontDescriptor::wrap_under_create_rule(ct_font_descriptor_ref))
}
}
fn create_copy_with_attributes(desc: &CTFontDescriptor, attr: CFDictionary) -> Result<CTFontDescriptor, ()> {
unsafe {
let ct_font_descriptor_ref = CTFontDescriptorCreateCopyWithAttributes(desc.as_concrete_TypeRef(), attr.as_concrete_TypeRef());
if ct_font_descriptor_ref.is_null() {
return Err(());
}
Ok(CTFontDescriptor::wrap_under_create_rule(ct_font_descriptor_ref))
}
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"5ba3b2c798c5356efabdfda97134a18c2a46cf5ead197701db879beb56360ee0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","build.rs":"9433ed3b20cc99e716dda4c6d8507c29bc04882544cbbea8d4e48ba80fd0fa12","src/array.rs":"40c305658e16b07d86353a5ad34e7b5fb98720f19cc2b5173360d6a61ce2642f","src/attributed_string.rs":"48c2d161d6f54136ae895a9f52efad1f831718ea331b875d25498039158a2d51","src/base.rs":"d926b5cdf46eb93f2d15a7c8940dc9b6dc4691c5efd350b6dce35836d452248e","src/bundle.rs":"be1ce281cb415b3a46a0f961e5a30ded5d295a09c0a4c7f27efa6721e2516c69","src/characterset.rs":"a10bbb42ddc74b3dc50b43ae6a50cc9d9a1cd08b975a1ce1b092be4bf64448a6","src/data.rs":"7cf4ddbc62635434fd3552739ffae9dde5f5d34f0ad0bb818068d3ac26403784","src/date.rs":"c064ee4c3ebd1927532c34871e2e41179d6e3c3e400f6b409a18ad9e2337477f","src/dictionary.rs":"3327a6f90f1e0db5e3fde1973e2df4143ca896716a816d03f2b17c8e988c5159","src/error.rs":"6205ebeb7631daa8bcd560862b6daa10f640c8c117ce5f6f7184f268dcbcb42a","src/filedescriptor.rs":"49580654b657811fade7adaa256f5f895cb011c9baa4731e2f44a6ec7fdba235","src/lib.rs":"f815234d32327532da600f47e9a006550d8993dcd695b803d0660316899f9319","src/messageport.rs":"e9227d5907cba8e29cdeea41bcb3ae5c7840220442953ab19aace31a84542f47","src/number.rs":"b1154203e74cb2258ba5520e20bcd4d524f1a957e09a19dd026b18d23baa3868","src/propertylist.rs":"7ec928438826c4ce40befedf3de0a37c8ecbc0fc17896dfa629d5864000b2cfe","src/runloop.rs":"26ca33e2472d191f583e01c24e8cd262f54de8b542fbe7278f33ab08b2925794","src/set.rs":"116c2f18008bfbeecac570d366dbd95b8fe5b9373e3e1bdd2c1d588314d776c5","src/string.rs":"ef2c408bf1fcea5d9106329fc48d659aabbdbca05eb121dfa27a221829bc4b89","src/timezone.rs":"c7dd9557646b7ff2bfd6a98bf92142b8304125b4e78dd651b687abc8da191159","src/url.rs":"4358f756ed3d5e9afd5a7f3e2e9115adc6133b47dc7ce59d6ebb32c6610b0e8f","src/uuid.rs":"82f75efa73d0842dff2e13d299c166c6593a77fcb69c4b7629a2df1c17ae507d"},"package":"9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"}
{"files":{"Cargo.toml":"380a7141d91af6d200eece8c518d2b60e98818025302982d733e459ccf2cde19","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","build.rs":"9433ed3b20cc99e716dda4c6d8507c29bc04882544cbbea8d4e48ba80fd0fa12","src/array.rs":"40c305658e16b07d86353a5ad34e7b5fb98720f19cc2b5173360d6a61ce2642f","src/attributed_string.rs":"48c2d161d6f54136ae895a9f52efad1f831718ea331b875d25498039158a2d51","src/base.rs":"7b21281e9a01903c79a7891ee4e1865a11504b281b468815d1a3838e1744a3c2","src/bundle.rs":"be1ce281cb415b3a46a0f961e5a30ded5d295a09c0a4c7f27efa6721e2516c69","src/characterset.rs":"a10bbb42ddc74b3dc50b43ae6a50cc9d9a1cd08b975a1ce1b092be4bf64448a6","src/data.rs":"7cf4ddbc62635434fd3552739ffae9dde5f5d34f0ad0bb818068d3ac26403784","src/date.rs":"c064ee4c3ebd1927532c34871e2e41179d6e3c3e400f6b409a18ad9e2337477f","src/dictionary.rs":"3327a6f90f1e0db5e3fde1973e2df4143ca896716a816d03f2b17c8e988c5159","src/error.rs":"6205ebeb7631daa8bcd560862b6daa10f640c8c117ce5f6f7184f268dcbcb42a","src/filedescriptor.rs":"49580654b657811fade7adaa256f5f895cb011c9baa4731e2f44a6ec7fdba235","src/lib.rs":"f815234d32327532da600f47e9a006550d8993dcd695b803d0660316899f9319","src/messageport.rs":"e9227d5907cba8e29cdeea41bcb3ae5c7840220442953ab19aace31a84542f47","src/number.rs":"f28040accfbbec99c4e55f411facac7cde4ad89298af2d7d907312f18e4263bf","src/propertylist.rs":"7ec928438826c4ce40befedf3de0a37c8ecbc0fc17896dfa629d5864000b2cfe","src/runloop.rs":"26ca33e2472d191f583e01c24e8cd262f54de8b542fbe7278f33ab08b2925794","src/set.rs":"116c2f18008bfbeecac570d366dbd95b8fe5b9373e3e1bdd2c1d588314d776c5","src/string.rs":"ef2c408bf1fcea5d9106329fc48d659aabbdbca05eb121dfa27a221829bc4b89","src/timezone.rs":"c7dd9557646b7ff2bfd6a98bf92142b8304125b4e78dd651b687abc8da191159","src/url.rs":"4358f756ed3d5e9afd5a7f3e2e9115adc6133b47dc7ce59d6ebb32c6610b0e8f","src/uuid.rs":"82f75efa73d0842dff2e13d299c166c6593a77fcb69c4b7629a2df1c17ae507d"},"package":"ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"}

Просмотреть файл

@ -12,13 +12,15 @@
[package]
name = "core-foundation-sys"
version = "0.8.0"
version = "0.8.2"
authors = ["The Servo Project Developers"]
build = "build.rs"
description = "Bindings to Core Foundation for macOS"
homepage = "https://github.com/servo/core-foundation-rs"
license = "MIT / Apache-2.0"
repository = "https://github.com/servo/core-foundation-rs"
[package.metadata.docs.rs]
default-target = "x86_64-apple-darwin"
[dependencies]

Просмотреть файл

@ -71,13 +71,13 @@ pub type CFAllocatorPreferredSizeCallBack = extern "C" fn(size: CFIndex, hint: C
pub struct CFAllocatorContext {
pub version: CFIndex,
pub info: *mut c_void,
pub retain: CFAllocatorRetainCallBack,
pub release: CFAllocatorReleaseCallBack,
pub copyDescription: CFAllocatorCopyDescriptionCallBack,
pub allocate: CFAllocatorAllocateCallBack,
pub reallocate: CFAllocatorReallocateCallBack,
pub deallocate: CFAllocatorDeallocateCallBack,
pub preferredSize: CFAllocatorPreferredSizeCallBack
pub retain: Option<CFAllocatorRetainCallBack>,
pub release: Option<CFAllocatorReleaseCallBack>,
pub copyDescription: Option<CFAllocatorCopyDescriptionCallBack>,
pub allocate: Option<CFAllocatorAllocateCallBack>,
pub reallocate: Option<CFAllocatorReallocateCallBack>,
pub deallocate: Option<CFAllocatorDeallocateCallBack>,
pub preferredSize: Option<CFAllocatorPreferredSizeCallBack>
}
/// Trait for all types which are Core Foundation reference types.

Просмотреть файл

@ -19,23 +19,23 @@ pub type CFBooleanRef = *const __CFBoolean;
pub type CFNumberType = u32;
// members of enum CFNumberType
// static kCFNumberSInt8Type: CFNumberType = 1;
// static kCFNumberSInt16Type: CFNumberType = 2;
pub static kCFNumberSInt32Type: CFNumberType = 3;
pub static kCFNumberSInt64Type: CFNumberType = 4;
pub static kCFNumberFloat32Type: CFNumberType = 5;
pub static kCFNumberFloat64Type: CFNumberType = 6;
// static kCFNumberCharType: CFNumberType = 7;
// static kCFNumberShortType: CFNumberType = 8;
// static kCFNumberIntType: CFNumberType = 9;
// static kCFNumberLongType: CFNumberType = 10;
// static kCFNumberLongLongType: CFNumberType = 11;
// static kCFNumberFloatType: CFNumberType = 12;
// static kCFNumberDoubleType: CFNumberType = 13;
// static kCFNumberCFIndexType: CFNumberType = 14;
// static kCFNumberNSIntegerType: CFNumberType = 15;
// static kCFNumberCGFloatType: CFNumberType = 16;
// static kCFNumberMaxType: CFNumberType = 16;
pub const kCFNumberSInt8Type: CFNumberType = 1;
pub const kCFNumberSInt16Type: CFNumberType = 2;
pub const kCFNumberSInt32Type: CFNumberType = 3;
pub const kCFNumberSInt64Type: CFNumberType = 4;
pub const kCFNumberFloat32Type: CFNumberType = 5;
pub const kCFNumberFloat64Type: CFNumberType = 6;
pub const kCFNumberCharType: CFNumberType = 7;
pub const kCFNumberShortType: CFNumberType = 8;
pub const kCFNumberIntType: CFNumberType = 9;
pub const kCFNumberLongType: CFNumberType = 10;
pub const kCFNumberLongLongType: CFNumberType = 11;
pub const kCFNumberFloatType: CFNumberType = 12;
pub const kCFNumberDoubleType: CFNumberType = 13;
pub const kCFNumberCFIndexType: CFNumberType = 14;
pub const kCFNumberNSIntegerType: CFNumberType = 15;
pub const kCFNumberCGFloatType: CFNumberType = 16;
pub const kCFNumberMaxType: CFNumberType = 16;
// This is an enum due to zero-sized types warnings.
// For more details see https://github.com/rust-lang/rust/issues/27303
@ -51,10 +51,34 @@ extern {
pub static kCFBooleanFalse: CFBooleanRef;
pub fn CFBooleanGetTypeID() -> CFTypeID;
pub fn CFBooleanGetValue(boolean: CFBooleanRef) -> bool;
pub fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *const c_void)
-> CFNumberRef;
//fn CFNumberGetByteSize
pub fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *mut c_void) -> bool;
pub fn CFNumberCompare(date: CFNumberRef, other: CFNumberRef, context: *mut c_void) -> CFComparisonResult;
pub fn CFNumberGetTypeID() -> CFTypeID;
pub fn CFNumberGetType(number: CFNumberRef) -> CFNumberType;
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn match_for_type_id_should_be_backwards_compatible() {
let type_id = kCFNumberFloat32Type;
// this is the old style of matching for static variables
match type_id {
vf64 if vf64 == kCFNumberFloat32Type => assert!(true),
_ => panic!("should not happen"),
};
// this is new new style of matching for consts
match type_id {
kCFNumberFloat32Type => assert!(true),
_ => panic!("should not happen"),
};
}
}