summaryrefslogtreecommitdiffstats
path: root/third_party/rust/core-text/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/core-text/src
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/core-text/src')
-rw-r--r--third_party/rust/core-text/src/font.rs1160
-rw-r--r--third_party/rust/core-text/src/font_collection.rs136
-rw-r--r--third_party/rust/core-text/src/font_descriptor.rs441
-rw-r--r--third_party/rust/core-text/src/font_manager.rs76
-rw-r--r--third_party/rust/core-text/src/frame.rs94
-rw-r--r--third_party/rust/core-text/src/framesetter.rs94
-rw-r--r--third_party/rust/core-text/src/lib.rs34
-rw-r--r--third_party/rust/core-text/src/line.rs125
-rw-r--r--third_party/rust/core-text/src/run.rs159
-rw-r--r--third_party/rust/core-text/src/string_attributes.rs19
10 files changed, 2338 insertions, 0 deletions
diff --git a/third_party/rust/core-text/src/font.rs b/third_party/rust/core-text/src/font.rs
new file mode 100644
index 0000000000..0d303a63fe
--- /dev/null
+++ b/third_party/rust/core-text/src/font.rs
@@ -0,0 +1,1160 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_upper_case_globals)]
+
+use font_descriptor;
+use font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, CTFontOrientation};
+use font_descriptor::{CTFontSymbolicTraits, CTFontTraits, SymbolicTraitAccessors, TraitAccessors};
+use font_manager::create_font_descriptor;
+
+use core_foundation::array::{CFArray, CFArrayRef};
+use core_foundation::base::{CFIndex, CFOptionFlags, CFType, CFTypeID, CFTypeRef, TCFType};
+use core_foundation::data::{CFData, CFDataRef};
+use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
+use core_foundation::number::CFNumber;
+use core_foundation::string::{CFString, CFStringRef, UniChar};
+use core_foundation::url::{CFURLRef, CFURL};
+use core_graphics::base::CGFloat;
+use core_graphics::context::CGContext;
+use core_graphics::font::{CGFont, CGGlyph};
+use core_graphics::geometry::{CGAffineTransform, CGPoint, CGRect, CGSize};
+use core_graphics::path::CGPath;
+
+use foreign_types::ForeignType;
+use libc::{self, size_t};
+use std::os::raw::c_void;
+use std::ptr;
+
+type CGContextRef = *mut <CGContext as ForeignType>::CType;
+type CGFontRef = *mut <CGFont as ForeignType>::CType;
+type CGPathRef = *mut <CGPath as ForeignType>::CType;
+
+pub type CTFontUIFontType = u32;
+// kCTFontNoFontType: CTFontUIFontType = -1;
+pub const kCTFontUserFontType: CTFontUIFontType = 0;
+pub const kCTFontUserFixedPitchFontType: CTFontUIFontType = 1;
+pub const kCTFontSystemFontType: CTFontUIFontType = 2;
+pub const kCTFontEmphasizedSystemFontType: CTFontUIFontType = 3;
+pub const kCTFontSmallSystemFontType: CTFontUIFontType = 4;
+pub const kCTFontSmallEmphasizedSystemFontType: CTFontUIFontType = 5;
+pub const kCTFontMiniSystemFontType: CTFontUIFontType = 6;
+pub const kCTFontMiniEmphasizedSystemFontType: CTFontUIFontType = 7;
+pub const kCTFontViewsFontType: CTFontUIFontType = 8;
+pub const kCTFontApplicationFontType: CTFontUIFontType = 9;
+pub const kCTFontLabelFontType: CTFontUIFontType = 10;
+pub const kCTFontMenuTitleFontType: CTFontUIFontType = 11;
+pub const kCTFontMenuItemFontType: CTFontUIFontType = 12;
+pub const kCTFontMenuItemMarkFontType: CTFontUIFontType = 13;
+pub const kCTFontMenuItemCmdKeyFontType: CTFontUIFontType = 14;
+pub const kCTFontWindowTitleFontType: CTFontUIFontType = 15;
+pub const kCTFontPushButtonFontType: CTFontUIFontType = 16;
+pub const kCTFontUtilityWindowTitleFontType: CTFontUIFontType = 17;
+pub const kCTFontAlertHeaderFontType: CTFontUIFontType = 18;
+pub const kCTFontSystemDetailFontType: CTFontUIFontType = 19;
+pub const kCTFontEmphasizedSystemDetailFontType: CTFontUIFontType = 20;
+pub const kCTFontToolbarFontType: CTFontUIFontType = 21;
+pub const kCTFontSmallToolbarFontType: CTFontUIFontType = 22;
+pub const kCTFontMessageFontType: CTFontUIFontType = 23;
+pub const kCTFontPaletteFontType: CTFontUIFontType = 24;
+pub const kCTFontToolTipFontType: CTFontUIFontType = 25;
+pub const kCTFontControlContentFontType: CTFontUIFontType = 26;
+
+pub type CTFontTableTag = u32;
+// TODO: create bindings for enum with 'chars' values
+
+pub type CTFontTableOptions = u32;
+pub const kCTFontTableOptionsNoOptions: CTFontTableOptions = 0;
+pub const kCTFontTableOptionsExcludeSynthetic: CTFontTableOptions = 1 << 0;
+
+pub type CTFontOptions = CFOptionFlags;
+pub const kCTFontOptionsDefault: CTFontOptions = 0;
+pub const kCTFontOptionsPreventAutoActivation: CTFontOptions = 1 << 0;
+pub const kCTFontOptionsPreferSystemFont: CTFontOptions = 1 << 2;
+
+pub enum CTFontNameSpecifier {
+ Copyright,
+ Family,
+ SubFamily,
+ Style,
+ Unique,
+ Full,
+ Version,
+ PostScript,
+ Trademark,
+ Manufacturer,
+ Designer,
+ Description,
+ VendorURL,
+ DesignerURL,
+ License,
+ LicenseURL,
+ SampleText,
+ PostScriptCID,
+}
+
+impl From<CTFontNameSpecifier> for CFStringRef {
+ fn from(val: CTFontNameSpecifier) -> Self {
+ unsafe {
+ match val {
+ CTFontNameSpecifier::Copyright => kCTFontCopyrightNameKey,
+ CTFontNameSpecifier::Family => kCTFontFamilyNameKey,
+ CTFontNameSpecifier::SubFamily => kCTFontSubFamilyNameKey,
+ CTFontNameSpecifier::Style => kCTFontStyleNameKey,
+ CTFontNameSpecifier::Unique => kCTFontUniqueNameKey,
+ CTFontNameSpecifier::Full => kCTFontFullNameKey,
+ CTFontNameSpecifier::Version => kCTFontVersionNameKey,
+ CTFontNameSpecifier::PostScript => kCTFontPostScriptNameKey,
+ CTFontNameSpecifier::Trademark => kCTFontTrademarkNameKey,
+ CTFontNameSpecifier::Manufacturer => kCTFontManufacturerNameKey,
+ CTFontNameSpecifier::Designer => kCTFontDesignerNameKey,
+ CTFontNameSpecifier::Description => kCTFontDescriptionNameKey,
+ CTFontNameSpecifier::VendorURL => kCTFontVendorURLNameKey,
+ CTFontNameSpecifier::DesignerURL => kCTFontDesignerURLNameKey,
+ CTFontNameSpecifier::License => kCTFontLicenseNameKey,
+ CTFontNameSpecifier::LicenseURL => kCTFontLicenseURLNameKey,
+ CTFontNameSpecifier::SampleText => kCTFontSampleTextNameKey,
+ CTFontNameSpecifier::PostScriptCID => kCTFontPostScriptCIDNameKey,
+ }
+ }
+ }
+}
+
+#[repr(C)]
+pub struct __CTFont(c_void);
+
+pub type CTFontRef = *const __CTFont;
+
+declare_TCFType! {
+ CTFont, CTFontRef
+}
+impl_TCFType!(CTFont, CTFontRef, CTFontGetTypeID);
+impl_CFTypeDescription!(CTFont);
+
+unsafe impl Send for CTFont {}
+unsafe impl Sync for CTFont {}
+
+pub fn new_from_CGFont(cgfont: &CGFont, pt_size: f64) -> CTFont {
+ unsafe {
+ let font_ref = CTFontCreateWithGraphicsFont(
+ cgfont.as_ptr() as *mut _,
+ pt_size as CGFloat,
+ ptr::null(),
+ ptr::null(),
+ );
+ CTFont::wrap_under_create_rule(font_ref)
+ }
+}
+
+pub fn new_from_CGFont_with_variations(
+ cgfont: &CGFont,
+ pt_size: f64,
+ variations: &CFDictionary<CFString, CFNumber>,
+) -> CTFont {
+ unsafe {
+ let font_desc = font_descriptor::new_from_variations(variations);
+ let font_ref = CTFontCreateWithGraphicsFont(
+ cgfont.as_ptr() as *mut _,
+ pt_size as CGFloat,
+ ptr::null(),
+ font_desc.as_concrete_TypeRef(),
+ );
+ CTFont::wrap_under_create_rule(font_ref)
+ }
+}
+
+pub fn new_from_descriptor(desc: &CTFontDescriptor, pt_size: f64) -> CTFont {
+ unsafe {
+ let font_ref = CTFontCreateWithFontDescriptor(
+ desc.as_concrete_TypeRef(),
+ pt_size as CGFloat,
+ ptr::null(),
+ );
+ CTFont::wrap_under_create_rule(font_ref)
+ }
+}
+
+pub fn new_from_descriptor_and_options(
+ desc: &CTFontDescriptor,
+ pt_size: f64,
+ options: CTFontOptions,
+) -> CTFont {
+ unsafe {
+ let font_ref = CTFontCreateWithFontDescriptorAndOptions(
+ desc.as_concrete_TypeRef(),
+ pt_size as CGFloat,
+ ptr::null(),
+ options,
+ );
+ CTFont::wrap_under_create_rule(font_ref)
+ }
+}
+
+pub fn new_from_buffer(buffer: &[u8]) -> Result<CTFont, ()> {
+ let ct_font_descriptor = create_font_descriptor(buffer)?;
+ Ok(new_from_descriptor(&ct_font_descriptor, 16.0))
+}
+
+pub fn new_from_name(name: &str, pt_size: f64) -> Result<CTFont, ()> {
+ unsafe {
+ let name: CFString = name.parse().unwrap();
+ let font_ref =
+ CTFontCreateWithName(name.as_concrete_TypeRef(), pt_size as CGFloat, ptr::null());
+ if font_ref.is_null() {
+ Err(())
+ } else {
+ Ok(CTFont::wrap_under_create_rule(font_ref))
+ }
+ }
+}
+
+pub fn new_from_name_and_options(
+ name: &str,
+ pt_size: f64,
+ options: CTFontOptions,
+) -> Result<CTFont, ()> {
+ unsafe {
+ let name: CFString = name.parse().unwrap();
+ let font_ref = CTFontCreateWithNameAndOptions(
+ name.as_concrete_TypeRef(),
+ pt_size as CGFloat,
+ ptr::null(),
+ options,
+ );
+ if font_ref.is_null() {
+ Err(())
+ } else {
+ Ok(CTFont::wrap_under_create_rule(font_ref))
+ }
+ }
+}
+
+pub fn new_ui_font_for_language(
+ ui_type: CTFontUIFontType,
+ size: f64,
+ language: Option<CFString>,
+) -> CTFont {
+ unsafe {
+ let font_ref = CTFontCreateUIFontForLanguage(
+ ui_type,
+ size,
+ language
+ .as_ref()
+ .map(|x| x.as_concrete_TypeRef())
+ .unwrap_or(std::ptr::null()),
+ );
+ if font_ref.is_null() {
+ // CTFontCreateUIFontForLanguage can fail, but is unlikely to do so during
+ // normal usage (if you pass a bad ui_type it will). To make things more
+ // convenient, just panic if it fails.
+ panic!();
+ } else {
+ CTFont::wrap_under_create_rule(font_ref)
+ }
+ }
+}
+
+impl CTFont {
+ // Properties
+ pub fn symbolic_traits(&self) -> CTFontSymbolicTraits {
+ unsafe { CTFontGetSymbolicTraits(self.0) }
+ }
+}
+
+impl CTFont {
+ // Creation methods
+ pub fn copy_to_CGFont(&self) -> CGFont {
+ unsafe {
+ let cgfont_ref = CTFontCopyGraphicsFont(self.0, ptr::null_mut());
+ CGFont::from_ptr(cgfont_ref as *mut _)
+ }
+ }
+
+ pub fn copy_descriptor(&self) -> CTFontDescriptor {
+ unsafe {
+ let desc = CTFontCopyFontDescriptor(self.0);
+ CTFontDescriptor::wrap_under_create_rule(desc)
+ }
+ }
+
+ pub fn clone_with_font_size(&self, size: f64) -> CTFont {
+ unsafe {
+ let font_ref =
+ CTFontCreateCopyWithAttributes(self.0, size as CGFloat, ptr::null(), ptr::null());
+ CTFont::wrap_under_create_rule(font_ref)
+ }
+ }
+
+ pub fn clone_with_symbolic_traits(
+ &self,
+ trait_value: CTFontSymbolicTraits,
+ trait_mask: CTFontSymbolicTraits,
+ ) -> Option<CTFont> {
+ unsafe {
+ let font_ref = CTFontCreateCopyWithSymbolicTraits(
+ self.0,
+ 0.0,
+ ptr::null(),
+ trait_value,
+ trait_mask,
+ );
+ if font_ref.is_null() {
+ None
+ } else {
+ Some(CTFont::wrap_under_create_rule(font_ref))
+ }
+ }
+ }
+
+ // Names
+ pub fn get_string_by_name_key(&self, name_key: CTFontNameSpecifier) -> Option<String> {
+ unsafe {
+ let result = CTFontCopyName(self.as_concrete_TypeRef(), name_key.into());
+ if result.is_null() {
+ None
+ } else {
+ Some(CFString::wrap_under_create_rule(result).to_string())
+ }
+ }
+ }
+
+ pub fn family_name(&self) -> String {
+ let value = self.get_string_by_name_key(CTFontNameSpecifier::Family);
+ value.expect("Fonts should always have a family name.")
+ }
+
+ pub fn face_name(&self) -> String {
+ let value = self.get_string_by_name_key(CTFontNameSpecifier::SubFamily);
+ value.expect("Fonts should always have a face name.")
+ }
+
+ pub fn unique_name(&self) -> String {
+ let value = self.get_string_by_name_key(CTFontNameSpecifier::Unique);
+ value.expect("Fonts should always have a unique name.")
+ }
+
+ pub fn postscript_name(&self) -> String {
+ let value = self.get_string_by_name_key(CTFontNameSpecifier::PostScript);
+ value.expect("Fonts should always have a PostScript name.")
+ }
+
+ pub fn display_name(&self) -> String {
+ let value = self.get_string_by_name_key(CTFontNameSpecifier::Full);
+ value.expect("Fonts should always have a PostScript name.")
+ }
+
+ pub fn style_name(&self) -> String {
+ let value = self.get_string_by_name_key(CTFontNameSpecifier::Style);
+ value.expect("Fonts should always have a style name.")
+ }
+
+ pub fn all_traits(&self) -> CTFontTraits {
+ unsafe { CTFontTraits::wrap_under_create_rule(CTFontCopyTraits(self.0)) }
+ }
+
+ // Font metrics
+ pub fn ascent(&self) -> CGFloat {
+ unsafe { CTFontGetAscent(self.0) }
+ }
+
+ pub fn descent(&self) -> CGFloat {
+ unsafe { CTFontGetDescent(self.0) }
+ }
+
+ pub fn underline_thickness(&self) -> CGFloat {
+ unsafe { CTFontGetUnderlineThickness(self.0) }
+ }
+
+ pub fn underline_position(&self) -> CGFloat {
+ unsafe { CTFontGetUnderlinePosition(self.0) }
+ }
+
+ pub fn slant_angle(&self) -> CGFloat {
+ unsafe { CTFontGetSlantAngle(self.0) }
+ }
+
+ pub fn cap_height(&self) -> CGFloat {
+ unsafe { CTFontGetCapHeight(self.0) }
+ }
+
+ pub fn bounding_box(&self) -> CGRect {
+ unsafe { CTFontGetBoundingBox(self.0) }
+ }
+
+ pub fn leading(&self) -> CGFloat {
+ unsafe { CTFontGetLeading(self.0) }
+ }
+
+ pub fn units_per_em(&self) -> libc::c_uint {
+ unsafe { CTFontGetUnitsPerEm(self.0) }
+ }
+
+ pub fn x_height(&self) -> CGFloat {
+ unsafe { CTFontGetXHeight(self.0) }
+ }
+
+ pub fn pt_size(&self) -> CGFloat {
+ unsafe { CTFontGetSize(self.0) }
+ }
+
+ pub fn get_glyph_with_name(&self, glyph_name: &str) -> CGGlyph {
+ let glyph_name = CFString::new(glyph_name);
+ unsafe { CTFontGetGlyphWithName(self.0, glyph_name.as_concrete_TypeRef()) }
+ }
+
+ pub unsafe fn get_glyphs_for_characters(
+ &self,
+ characters: *const UniChar,
+ glyphs: *mut CGGlyph,
+ count: CFIndex,
+ ) -> bool {
+ CTFontGetGlyphsForCharacters(self.0, characters, glyphs, count)
+ }
+
+ pub unsafe fn get_advances_for_glyphs(
+ &self,
+ orientation: CTFontOrientation,
+ glyphs: *const CGGlyph,
+ advances: *mut CGSize,
+ count: CFIndex,
+ ) -> f64 {
+ CTFontGetAdvancesForGlyphs(self.0, orientation, glyphs, advances, count)
+ }
+
+ pub unsafe fn get_vertical_translations_for_glyphs(
+ &self,
+ orientation: CTFontOrientation,
+ glyphs: *const CGGlyph,
+ translations: *mut CGSize,
+ count: CFIndex,
+ ) {
+ CTFontGetVerticalTranslationsForGlyphs(self.0, orientation, glyphs, translations, count)
+ }
+
+ pub fn get_font_table(&self, tag: u32) -> Option<CFData> {
+ unsafe {
+ let result = CTFontCopyTable(
+ self.0,
+ tag as CTFontTableTag,
+ kCTFontTableOptionsExcludeSynthetic,
+ );
+ if result.is_null() {
+ None
+ } else {
+ Some(CFData::wrap_under_create_rule(result))
+ }
+ }
+ }
+
+ pub fn get_available_font_tables(&self) -> Option<CFArray<CTFontTableTag>> {
+ unsafe {
+ let result = CTFontCopyAvailableTables(self.0, kCTFontTableOptionsExcludeSynthetic);
+ if result.is_null() {
+ None
+ } else {
+ Some(TCFType::wrap_under_create_rule(result))
+ }
+ }
+ }
+
+ pub fn get_bounding_rects_for_glyphs(
+ &self,
+ orientation: CTFontOrientation,
+ glyphs: &[CGGlyph],
+ ) -> CGRect {
+ unsafe {
+ CTFontGetBoundingRectsForGlyphs(
+ self.as_concrete_TypeRef(),
+ orientation,
+ glyphs.as_ptr(),
+ ptr::null_mut(),
+ glyphs.len() as CFIndex,
+ )
+ }
+ }
+
+ pub fn draw_glyphs(&self, glyphs: &[CGGlyph], positions: &[CGPoint], context: CGContext) {
+ assert_eq!(glyphs.len(), positions.len());
+ unsafe {
+ CTFontDrawGlyphs(
+ self.as_concrete_TypeRef(),
+ glyphs.as_ptr(),
+ positions.as_ptr(),
+ glyphs.len() as size_t,
+ context.as_ptr(),
+ )
+ }
+ }
+
+ pub fn url(&self) -> Option<CFURL> {
+ unsafe {
+ let result = CTFontCopyAttribute(self.0, kCTFontURLAttribute);
+ if result.is_null() {
+ None
+ } else {
+ Some(CFURL::wrap_under_create_rule(result as CFURLRef))
+ }
+ }
+ }
+
+ pub fn get_variation_axes(&self) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
+ unsafe {
+ let axes = CTFontCopyVariationAxes(self.0);
+ if axes.is_null() {
+ return None;
+ }
+ Some(TCFType::wrap_under_create_rule(axes))
+ }
+ }
+
+ pub fn create_path_for_glyph(
+ &self,
+ glyph: CGGlyph,
+ matrix: &CGAffineTransform,
+ ) -> Result<CGPath, ()> {
+ unsafe {
+ let path = CTFontCreatePathForGlyph(self.0, glyph, matrix);
+ if path.is_null() {
+ Err(())
+ } else {
+ Ok(CGPath::from_ptr(path))
+ }
+ }
+ }
+
+ #[inline]
+ pub fn glyph_count(&self) -> CFIndex {
+ unsafe { CTFontGetGlyphCount(self.0) }
+ }
+}
+
+// Helper methods
+pub fn debug_font_names(font: &CTFont) {
+ fn get_key(font: &CTFont, key: CTFontNameSpecifier) -> String {
+ font.get_string_by_name_key(key).unwrap()
+ }
+
+ println!(
+ "kCTFontFamilyNameKey: {}",
+ get_key(font, CTFontNameSpecifier::Family)
+ );
+ println!(
+ "kCTFontSubFamilyNameKey: {}",
+ get_key(font, CTFontNameSpecifier::SubFamily)
+ );
+ println!(
+ "kCTFontStyleNameKey: {}",
+ get_key(font, CTFontNameSpecifier::Style)
+ );
+ println!(
+ "kCTFontUniqueNameKey: {}",
+ get_key(font, CTFontNameSpecifier::Unique)
+ );
+ println!(
+ "kCTFontFullNameKey: {}",
+ get_key(font, CTFontNameSpecifier::Full)
+ );
+ println!(
+ "kCTFontPostScriptNameKey: {}",
+ get_key(font, CTFontNameSpecifier::PostScript)
+ );
+}
+
+pub fn debug_font_traits(font: &CTFont) {
+ let sym = font.symbolic_traits();
+ println!("kCTFontItalicTrait: {}", sym.is_italic());
+ println!("kCTFontBoldTrait: {}", sym.is_bold());
+ println!("kCTFontExpandedTrait: {}", sym.is_expanded());
+ println!("kCTFontCondensedTrait: {}", sym.is_condensed());
+ println!("kCTFontMonoSpaceTrait: {}", sym.is_monospace());
+
+ let traits = font.all_traits();
+ println!("kCTFontWeightTrait: {}", traits.normalized_weight());
+ println!("kCTFontWidthTrait: {}", traits.normalized_width());
+ // println!("kCTFontSlantTrait: {}", traits.normalized_slant());
+}
+
+#[cfg(feature = "mountainlion")]
+pub fn cascade_list_for_languages(
+ font: &CTFont,
+ language_pref_list: &CFArray<CFString>,
+) -> CFArray<CTFontDescriptor> {
+ unsafe {
+ let font_collection_ref = CTFontCopyDefaultCascadeListForLanguages(
+ font.as_concrete_TypeRef(),
+ language_pref_list.as_concrete_TypeRef(),
+ );
+ CFArray::wrap_under_create_rule(font_collection_ref)
+ }
+}
+
+#[link(name = "CoreText", kind = "framework")]
+extern "C" {
+ /*
+ * CTFont.h
+ */
+
+ /* Name Specifier Constants */
+ static kCTFontCopyrightNameKey: CFStringRef;
+ static kCTFontFamilyNameKey: CFStringRef;
+ static kCTFontSubFamilyNameKey: CFStringRef;
+ static kCTFontStyleNameKey: CFStringRef;
+ static kCTFontUniqueNameKey: CFStringRef;
+ static kCTFontFullNameKey: CFStringRef;
+ static kCTFontVersionNameKey: CFStringRef;
+ static kCTFontPostScriptNameKey: CFStringRef;
+ static kCTFontTrademarkNameKey: CFStringRef;
+ static kCTFontManufacturerNameKey: CFStringRef;
+ static kCTFontDesignerNameKey: CFStringRef;
+ static kCTFontDescriptionNameKey: CFStringRef;
+ static kCTFontVendorURLNameKey: CFStringRef;
+ static kCTFontDesignerURLNameKey: CFStringRef;
+ static kCTFontLicenseNameKey: CFStringRef;
+ static kCTFontLicenseURLNameKey: CFStringRef;
+ static kCTFontSampleTextNameKey: CFStringRef;
+ static kCTFontPostScriptCIDNameKey: CFStringRef;
+
+ #[cfg(test)]
+ static kCTFontVariationAxisIdentifierKey: CFStringRef;
+ //static kCTFontVariationAxisMinimumValueKey: CFStringRef;
+ #[cfg(test)]
+ static kCTFontVariationAxisMaximumValueKey: CFStringRef;
+ //static kCTFontVariationAxisDefaultValueKey: CFStringRef;
+ //static kCTFontVariationAxisNameKey: CFStringRef;
+
+ //static kCTFontFeatureTypeIdentifierKey: CFStringRef;
+ //static kCTFontFeatureTypeNameKey: CFStringRef;
+ //static kCTFontFeatureTypeExclusiveKey: CFStringRef;
+ //static kCTFontFeatureTypeSelectorsKey: CFStringRef;
+ //static kCTFontFeatureSelectorIdentifierKey: CFStringRef;
+ //static kCTFontFeatureSelectorNameKey: CFStringRef;
+ //static kCTFontFeatureSelectorDefaultKey: CFStringRef;
+ //static kCTFontFeatureSelectorSettingKey: CFStringRef;
+
+ static kCTFontURLAttribute: CFStringRef;
+
+ // N.B. Unlike most Cocoa bindings, this extern block is organized according
+ // to the documentation's Functions By Task listing, because there so many functions.
+
+ /* Creating Fonts */
+ fn CTFontCreateWithName(
+ name: CFStringRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ ) -> CTFontRef;
+ fn CTFontCreateWithNameAndOptions(
+ name: CFStringRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ options: CTFontOptions,
+ ) -> CTFontRef;
+ fn CTFontCreateWithFontDescriptor(
+ descriptor: CTFontDescriptorRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ ) -> CTFontRef;
+ fn CTFontCreateWithFontDescriptorAndOptions(
+ descriptor: CTFontDescriptorRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ options: CTFontOptions,
+ ) -> CTFontRef;
+ fn CTFontCreateUIFontForLanguage(
+ uiType: CTFontUIFontType,
+ size: CGFloat,
+ language: CFStringRef,
+ ) -> CTFontRef;
+ fn CTFontCreateCopyWithAttributes(
+ font: CTFontRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ attributes: CTFontDescriptorRef,
+ ) -> CTFontRef;
+ fn CTFontCreateCopyWithSymbolicTraits(
+ font: CTFontRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ symTraitValue: CTFontSymbolicTraits,
+ symTraitMask: CTFontSymbolicTraits,
+ ) -> CTFontRef;
+ //fn CTFontCreateCopyWithFamily
+ //fn CTFontCreateForString
+
+ /* Getting Font Data */
+ fn CTFontCopyFontDescriptor(font: CTFontRef) -> CTFontDescriptorRef;
+ fn CTFontCopyAttribute(font: CTFontRef, attribute: CFStringRef) -> CFTypeRef;
+ fn CTFontGetSize(font: CTFontRef) -> CGFloat;
+ //fn CTFontGetMatrix
+ fn CTFontGetSymbolicTraits(font: CTFontRef) -> CTFontSymbolicTraits;
+ fn CTFontCopyTraits(font: CTFontRef) -> CFDictionaryRef;
+
+ /* Getting Font Names */
+ //fn CTFontCopyPostScriptName(font: CTFontRef) -> CFStringRef;
+ //fn CTFontCopyFamilyName(font: CTFontRef) -> CFStringRef;
+ //fn CTFontCopyFullName(font: CTFontRef) -> CFStringRef;
+ //fn CTFontCopyDisplayName(font: CTFontRef) -> CFStringRef;
+ fn CTFontCopyName(font: CTFontRef, nameKey: CFStringRef) -> CFStringRef;
+ //fn CTFontCopyLocalizedName(font: CTFontRef, nameKey: CFStringRef,
+ // language: *CFStringRef) -> CFStringRef;
+ #[cfg(feature = "mountainlion")]
+ fn CTFontCopyDefaultCascadeListForLanguages(
+ font: CTFontRef,
+ languagePrefList: CFArrayRef,
+ ) -> CFArrayRef;
+
+ /* Working With Encoding */
+ //fn CTFontCopyCharacterSet
+ //fn CTFontGetStringEncoding
+ //fn CTFontCopySupportedLanguages
+
+ /* Getting Font Metrics */
+ fn CTFontGetAscent(font: CTFontRef) -> CGFloat;
+ fn CTFontGetDescent(font: CTFontRef) -> CGFloat;
+ fn CTFontGetLeading(font: CTFontRef) -> CGFloat;
+ fn CTFontGetUnitsPerEm(font: CTFontRef) -> libc::c_uint;
+ fn CTFontGetGlyphCount(font: CTFontRef) -> CFIndex;
+ fn CTFontGetBoundingBox(font: CTFontRef) -> CGRect;
+ fn CTFontGetUnderlinePosition(font: CTFontRef) -> CGFloat;
+ fn CTFontGetUnderlineThickness(font: CTFontRef) -> CGFloat;
+ fn CTFontGetSlantAngle(font: CTFontRef) -> CGFloat;
+ fn CTFontGetCapHeight(font: CTFontRef) -> CGFloat;
+ fn CTFontGetXHeight(font: CTFontRef) -> CGFloat;
+
+ /* Getting Glyph Data */
+ fn CTFontCreatePathForGlyph(
+ font: CTFontRef,
+ glyph: CGGlyph,
+ matrix: *const CGAffineTransform,
+ ) -> CGPathRef;
+ fn CTFontGetGlyphWithName(font: CTFontRef, glyphName: CFStringRef) -> CGGlyph;
+ fn CTFontGetBoundingRectsForGlyphs(
+ font: CTFontRef,
+ orientation: CTFontOrientation,
+ glyphs: *const CGGlyph,
+ boundingRects: *mut CGRect,
+ count: CFIndex,
+ ) -> CGRect;
+ fn CTFontGetAdvancesForGlyphs(
+ font: CTFontRef,
+ orientation: CTFontOrientation,
+ glyphs: *const CGGlyph,
+ advances: *mut CGSize,
+ count: CFIndex,
+ ) -> libc::c_double;
+ fn CTFontGetVerticalTranslationsForGlyphs(
+ font: CTFontRef,
+ orientation: CTFontOrientation,
+ glyphs: *const CGGlyph,
+ translations: *mut CGSize,
+ count: CFIndex,
+ );
+
+ /* Working With Font Variations */
+ fn CTFontCopyVariationAxes(font: CTFontRef) -> CFArrayRef;
+ //fn CTFontCopyVariation
+
+ /* Getting Font Features */
+ //fn CTFontCopyFeatures
+ //fn CTFontCopyFeatureSettings
+
+ /* Working with Glyphs */
+ fn CTFontGetGlyphsForCharacters(
+ font: CTFontRef,
+ characters: *const UniChar,
+ glyphs: *mut CGGlyph,
+ count: CFIndex,
+ ) -> bool;
+ fn CTFontDrawGlyphs(
+ font: CTFontRef,
+ glyphs: *const CGGlyph,
+ positions: *const CGPoint,
+ count: size_t,
+ context: CGContextRef,
+ );
+ //fn CTFontGetLigatureCaretPositions
+
+ /* Converting Fonts */
+ fn CTFontCopyGraphicsFont(font: CTFontRef, attributes: *mut CTFontDescriptorRef) -> CGFontRef;
+ fn CTFontCreateWithGraphicsFont(
+ graphicsFont: CGFontRef,
+ size: CGFloat,
+ matrix: *const CGAffineTransform,
+ attributes: CTFontDescriptorRef,
+ ) -> CTFontRef;
+ //fn CTFontGetPlatformFont
+ //fn CTFontCreateWithPlatformFont
+ //fn CTFontCreateWithQuickdrawInstance
+
+ /* Getting Font Table Data */
+ fn CTFontCopyAvailableTables(font: CTFontRef, options: CTFontTableOptions) -> CFArrayRef;
+ fn CTFontCopyTable(
+ font: CTFontRef,
+ table: CTFontTableTag,
+ options: CTFontTableOptions,
+ ) -> CFDataRef;
+
+ fn CTFontGetTypeID() -> CFTypeID;
+}
+
+#[test]
+fn copy_font() {
+ use std::io::Read;
+ let mut f = std::fs::File::open("/System/Library/Fonts/ZapfDingbats.ttf").unwrap();
+ let mut font_data = Vec::new();
+ f.read_to_end(&mut font_data).unwrap();
+ let desc = crate::font_manager::create_font_descriptor(&font_data).unwrap();
+ let font = new_from_descriptor(&desc, 12.);
+ drop(desc);
+ let desc = font.copy_descriptor();
+ drop(font);
+ let font = new_from_descriptor(&desc, 14.);
+ assert_eq!(font.family_name(), "Zapf Dingbats");
+}
+
+#[cfg(test)]
+fn macos_version() -> (i32, i32, i32) {
+ use std::io::Read;
+
+ // This is the same approach that Firefox uses for detecting versions
+ let file = "/System/Library/CoreServices/SystemVersion.plist";
+ let mut f = std::fs::File::open(file).unwrap();
+ let mut system_version_data = Vec::new();
+ f.read_to_end(&mut system_version_data).unwrap();
+
+ use core_foundation::propertylist;
+ let (list, _) = propertylist::create_with_data(
+ core_foundation::data::CFData::from_buffer(&system_version_data),
+ propertylist::kCFPropertyListImmutable,
+ )
+ .unwrap();
+ let k = unsafe { propertylist::CFPropertyList::wrap_under_create_rule(list) };
+
+ let dict = unsafe {
+ std::mem::transmute::<_, CFDictionary<CFType, CFType>>(
+ k.downcast::<CFDictionary>().unwrap(),
+ )
+ };
+
+ let version = dict
+ .find(&CFString::new("ProductVersion").as_CFType())
+ .as_ref()
+ .unwrap()
+ .downcast::<CFString>()
+ .unwrap()
+ .to_string();
+
+ match version
+ .split('.')
+ .map(|x| x.parse().unwrap())
+ .collect::<Vec<_>>()[..]
+ {
+ [a, b, c] => (a, b, c),
+ [a, b] => (a, b, 0),
+ _ => panic!(),
+ }
+}
+
+#[test]
+fn copy_system_font() {
+ use crate::*;
+
+ let small = new_ui_font_for_language(kCTFontSystemDetailFontType, 19., None);
+ let big = small.clone_with_font_size(20.);
+
+ // ensure that we end up with different fonts for the different sizes before 10.15
+ if macos_version() < (10, 15, 0) {
+ assert_ne!(big.url(), small.url());
+ } else {
+ assert_eq!(big.url(), small.url());
+ }
+
+ let ps = small.postscript_name();
+ let desc = small.copy_descriptor();
+
+ // check that we can construct a new vesion by descriptor
+ let ctfont = new_from_descriptor(&desc, 20.);
+ assert_eq!(big.postscript_name(), ctfont.postscript_name());
+
+ // check that we can construct a new version by attributes
+ let attr = desc.attributes();
+ let desc_from_attr = font_descriptor::new_from_attributes(&attr);
+ let font_from_attr = new_from_descriptor(&desc_from_attr, 19.);
+ assert_eq!(font_from_attr.postscript_name(), small.postscript_name());
+
+ // on newer versions of macos we can't construct by name anymore
+ if macos_version() < (10, 13, 0) {
+ let ui_font_by_name = new_from_name(&small.postscript_name(), 19.).unwrap();
+ assert_eq!(ui_font_by_name.postscript_name(), small.postscript_name());
+
+ let ui_font_by_name = new_from_name(&small.postscript_name(), 20.).unwrap();
+ assert_eq!(ui_font_by_name.postscript_name(), small.postscript_name());
+
+ let ui_font_by_name = new_from_name(&big.postscript_name(), 20.).unwrap();
+ assert_eq!(ui_font_by_name.postscript_name(), big.postscript_name());
+ }
+
+ // but we can still construct the CGFont by name
+ let cgfont = CGFont::from_name(&CFString::new(&ps)).unwrap();
+ let cgfont = new_from_CGFont(&cgfont, 0.);
+ println!("{:?}", cgfont);
+ let desc = cgfont.copy_descriptor();
+ let matching = unsafe {
+ crate::font_descriptor::CTFontDescriptorCreateMatchingFontDescriptor(
+ desc.as_concrete_TypeRef(),
+ std::ptr::null(),
+ )
+ };
+ let matching = unsafe { CTFontDescriptor::wrap_under_create_rule(matching) };
+
+ println!("{:?}", cgfont.copy_descriptor());
+ assert!(desc
+ .attributes()
+ .find(CFString::from_static_string("NSFontSizeAttribute"))
+ .is_some());
+
+ println!("{:?}", matching);
+ println!(
+ "{:?}",
+ matching
+ .attributes()
+ .find(CFString::from_static_string("NSFontSizeAttribute"))
+ );
+
+ assert!(matching
+ .attributes()
+ .find(CFString::from_static_string("NSFontSizeAttribute"))
+ .is_none());
+
+ assert_eq!(small.postscript_name(), cgfont.postscript_name());
+}
+
+// Tests what happens when variations have values not inbetween min and max
+#[test]
+fn out_of_range_variations() {
+ use crate::*;
+
+ let small = new_ui_font_for_language(kCTFontSystemDetailFontType, 19., None);
+
+ let axes = small.get_variation_axes();
+ if macos_version() < (10, 12, 0) {
+ assert!(axes.is_none());
+ return;
+ }
+ let axes = axes.unwrap();
+ let mut vals = Vec::new();
+ dbg!(&axes);
+ for axis in axes.iter() {
+ let tag = axis
+ .find(unsafe { kCTFontVariationAxisIdentifierKey })
+ .unwrap()
+ .downcast::<CFNumber>()
+ .unwrap()
+ .to_i64()
+ .unwrap();
+ let max = axis
+ .find(unsafe { kCTFontVariationAxisMaximumValueKey })
+ .unwrap()
+ .downcast::<CFNumber>()
+ .unwrap()
+ .to_f64()
+ .unwrap();
+ vals.push((CFNumber::from(tag), CFNumber::from(max + 1.)));
+ }
+ let vals_dict = CFDictionary::from_CFType_pairs(&vals);
+ let variation_attribute =
+ unsafe { CFString::wrap_under_get_rule(font_descriptor::kCTFontVariationAttribute) };
+ let attrs_dict = CFDictionary::from_CFType_pairs(&[(variation_attribute.clone(), vals_dict)]);
+ let ct_var_font_desc = small
+ .copy_descriptor()
+ .create_copy_with_attributes(attrs_dict.to_untyped())
+ .unwrap();
+ let variation_font = crate::font::new_from_descriptor(&ct_var_font_desc, 19.);
+ let var_desc = variation_font.copy_descriptor();
+ let var_attrs = var_desc.attributes();
+ dbg!(&var_attrs);
+ // attributes greater than max are dropped on macOS <= 11
+ // on macOS 12 they seem to be preserved as is.
+ let var_attrs = var_attrs.find(variation_attribute);
+ if macos_version() >= (12, 0, 0) && macos_version() < (13, 0, 0) {
+ let var_attrs = var_attrs.unwrap().downcast::<CFDictionary>().unwrap();
+ assert!(!var_attrs.is_empty());
+ let var_attrs: CFDictionary<CFType, CFType> = unsafe { std::mem::transmute(var_attrs) };
+ // attributes greater than max remain
+ for axis in axes.iter() {
+ let tag = axis
+ .find(unsafe { kCTFontVariationAxisIdentifierKey })
+ .unwrap();
+ let max = axis
+ .find(unsafe { kCTFontVariationAxisMaximumValueKey })
+ .unwrap()
+ .downcast::<CFNumber>()
+ .unwrap()
+ .to_f64()
+ .unwrap();
+ let val = var_attrs
+ .find(tag.clone())
+ .unwrap()
+ .downcast::<CFNumber>()
+ .unwrap()
+ .to_f64()
+ .unwrap();
+ assert_eq!(val, max + 1.);
+ }
+ } else if macos_version() >= (10, 15, 0) {
+ assert!(var_attrs.is_none());
+ } else {
+ let var_attrs = var_attrs.unwrap().downcast::<CFDictionary>().unwrap();
+ assert!(var_attrs.is_empty());
+ }
+}
+
+#[test]
+fn equal_descriptor_different_font() {
+ use crate::*;
+
+ let variation_attribute =
+ unsafe { CFString::wrap_under_get_rule(font_descriptor::kCTFontVariationAttribute) };
+ let size_attribute =
+ unsafe { CFString::wrap_under_get_rule(font_descriptor::kCTFontSizeAttribute) };
+
+ let sys_font = new_ui_font_for_language(kCTFontSystemDetailFontType, 19., None);
+
+ // but we can still construct the CGFont by name
+ let create_vars = |desc| {
+ let vals: Vec<(CFNumber, CFNumber)> =
+ vec![(CFNumber::from(0x6f70737a), CFNumber::from(17.))];
+ let vals_dict = CFDictionary::from_CFType_pairs(&vals);
+ let attrs_dict =
+ CFDictionary::from_CFType_pairs(&[(variation_attribute.clone(), vals_dict)]);
+ let size_attrs_dict =
+ CFDictionary::from_CFType_pairs(&[(size_attribute.clone(), CFNumber::from(120.))]);
+ dbg!(&desc);
+ let from_font_desc = new_from_descriptor(&desc, 120.).copy_descriptor();
+ let resized_font_desc = desc
+ .create_copy_with_attributes(size_attrs_dict.to_untyped())
+ .unwrap();
+ if macos_version() >= (11, 0, 0) {
+ assert_eq!(from_font_desc, resized_font_desc);
+ } else {
+ // we won't have a name if we're using system font desc
+ if from_font_desc
+ .attributes()
+ .find(unsafe { font_descriptor::kCTFontNameAttribute })
+ .is_none()
+ {
+ // it's surprising that desc's are the not equal but the attributes are
+ assert_ne!(from_font_desc, resized_font_desc);
+ assert_eq!(
+ from_font_desc.attributes().to_untyped(),
+ resized_font_desc.attributes().to_untyped()
+ );
+ } else if macos_version() >= (10, 13, 0) {
+ // this is unsurprising
+ assert_ne!(from_font_desc, resized_font_desc);
+ assert_ne!(
+ from_font_desc.attributes().to_untyped(),
+ resized_font_desc.attributes().to_untyped()
+ );
+ } else {
+ assert_ne!(from_font_desc, resized_font_desc);
+ assert_eq!(
+ from_font_desc.attributes().to_untyped(),
+ resized_font_desc.attributes().to_untyped()
+ );
+ }
+ }
+
+ let from_font_desc = from_font_desc
+ .create_copy_with_attributes(attrs_dict.to_untyped())
+ .unwrap();
+ let resized_font_desc = resized_font_desc
+ .create_copy_with_attributes(attrs_dict.to_untyped())
+ .unwrap();
+ (from_font_desc, resized_font_desc)
+ };
+
+ // setting the variation works properly if we use system font desc
+ let (from_font_desc, resized_font_desc) = create_vars(sys_font.copy_descriptor());
+ assert_eq!(from_font_desc, resized_font_desc);
+ assert!(resized_font_desc
+ .attributes()
+ .find(variation_attribute.clone())
+ .is_some());
+
+ // but doesn't if we refer to it by name
+ let ps = sys_font.postscript_name();
+ let cgfont = CGFont::from_name(&CFString::new(&ps)).unwrap();
+ let ctfont = new_from_CGFont(&cgfont, 0.);
+
+ let (from_font_desc, resized_font_desc) = create_vars(ctfont.copy_descriptor());
+ if macos_version() >= (10, 15, 0) {
+ assert_ne!(from_font_desc, resized_font_desc);
+ }
+
+ if macos_version() >= (10, 13, 0) {
+ assert!(from_font_desc
+ .attributes()
+ .find(variation_attribute.clone())
+ .is_some());
+ if macos_version() >= (11, 0, 0) {
+ assert!(resized_font_desc
+ .attributes()
+ .find(variation_attribute)
+ .is_none());
+ } else {
+ assert!(resized_font_desc
+ .attributes()
+ .find(variation_attribute)
+ .is_some());
+ };
+ }
+}
+
+#[test]
+fn system_font_variation() {
+ use crate::*;
+
+ let small = new_ui_font_for_language(kCTFontSystemDetailFontType, 19., None);
+
+ // but we can still construct the CGFont by name
+ let ps = small.postscript_name();
+ let cgfont = CGFont::from_name(&CFString::new(&ps)).unwrap();
+ let cgfont = new_from_CGFont(&cgfont, 0.);
+ let desc = cgfont.copy_descriptor();
+
+ let vals: Vec<(CFNumber, CFNumber)> =
+ vec![(CFNumber::from(0x6f70737a /* opsz */), CFNumber::from(17.))];
+ let vals_dict = CFDictionary::from_CFType_pairs(&vals);
+ let variation_attribute =
+ unsafe { CFString::wrap_under_get_rule(font_descriptor::kCTFontVariationAttribute) };
+ let attrs_dict = CFDictionary::from_CFType_pairs(&[(variation_attribute, vals_dict)]);
+ let ct_var_font_desc = desc
+ .create_copy_with_attributes(attrs_dict.to_untyped())
+ .unwrap();
+ let attrs = ct_var_font_desc.attributes();
+ let var_attr = attrs.find(CFString::from_static_string("NSCTFontVariationAttribute"));
+ if macos_version() >= (11, 0, 0) {
+ // the variation goes away
+ assert!(var_attr.is_none());
+ } else {
+ assert!(var_attr.is_some());
+ }
+
+ dbg!(ct_var_font_desc);
+}
+
+#[test]
+fn ui_font() {
+ // pass some garbagey inputs
+ new_ui_font_for_language(
+ kCTFontSystemDetailFontType,
+ 10000009.,
+ Some(CFString::from("Gofld")),
+ );
+}
diff --git a/third_party/rust/core-text/src/font_collection.rs b/third_party/rust/core-text/src/font_collection.rs
new file mode 100644
index 0000000000..bf5822249a
--- /dev/null
+++ b/third_party/rust/core-text/src/font_collection.rs
@@ -0,0 +1,136 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use font_descriptor;
+use font_descriptor::{CTFontDescriptor, CTFontDescriptorCreateMatchingFontDescriptors};
+use font_manager::{
+ CTFontManagerCopyAvailableFontFamilyNames, CTFontManagerCopyAvailablePostScriptNames,
+};
+
+use core_foundation::array::{CFArray, CFArrayRef};
+use core_foundation::base::{CFTypeID, TCFType};
+use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
+use core_foundation::number::CFNumber;
+use core_foundation::set::CFSet;
+use core_foundation::string::{CFString, CFStringRef};
+
+use std::os::raw::c_void;
+
+#[repr(C)]
+pub struct __CTFontCollection(c_void);
+
+pub type CTFontCollectionRef = *const __CTFontCollection;
+
+declare_TCFType! {
+ CTFontCollection, CTFontCollectionRef
+}
+impl_TCFType!(
+ CTFontCollection,
+ CTFontCollectionRef,
+ CTFontCollectionGetTypeID
+);
+impl_CFTypeDescription!(CTFontCollection);
+
+impl CTFontCollection {
+ pub fn get_descriptors(&self) -> Option<CFArray<CTFontDescriptor>> {
+ // surprise! this function follows the Get rule, despite being named *Create*.
+ // So we have to addRef it to avoid CTFontCollection from double freeing it later.
+ unsafe {
+ let font_descriptors = CTFontCollectionCreateMatchingFontDescriptors(self.0);
+ if font_descriptors.is_null() {
+ // This returns null if there are no matching font descriptors.
+ None
+ } else {
+ Some(CFArray::wrap_under_get_rule(font_descriptors))
+ }
+ }
+ }
+}
+
+pub fn new_from_descriptors(descs: &CFArray<CTFontDescriptor>) -> CTFontCollection {
+ unsafe {
+ let key = CFString::wrap_under_get_rule(kCTFontCollectionRemoveDuplicatesOption);
+ let value = CFNumber::from(1i64);
+ let options = CFDictionary::from_CFType_pairs(&[(key.as_CFType(), value.as_CFType())]);
+ let font_collection_ref = CTFontCollectionCreateWithFontDescriptors(
+ descs.as_concrete_TypeRef(),
+ options.as_concrete_TypeRef(),
+ );
+ CTFontCollection::wrap_under_create_rule(font_collection_ref)
+ }
+}
+
+pub fn create_for_all_families() -> CTFontCollection {
+ unsafe {
+ let key = CFString::wrap_under_get_rule(kCTFontCollectionRemoveDuplicatesOption);
+ let value = CFNumber::from(1i64);
+ let options = CFDictionary::from_CFType_pairs(&[(key.as_CFType(), value.as_CFType())]);
+ let font_collection_ref =
+ CTFontCollectionCreateFromAvailableFonts(options.as_concrete_TypeRef());
+ CTFontCollection::wrap_under_create_rule(font_collection_ref)
+ }
+}
+
+pub fn create_for_family(family: &str) -> Option<CTFontCollection> {
+ use font_descriptor::kCTFontFamilyNameAttribute;
+
+ unsafe {
+ let family_attr = CFString::wrap_under_get_rule(kCTFontFamilyNameAttribute);
+ let family_name: CFString = family.parse().unwrap();
+ let specified_attrs =
+ CFDictionary::from_CFType_pairs(&[(family_attr.clone(), family_name.as_CFType())]);
+
+ let wildcard_desc: CTFontDescriptor =
+ font_descriptor::new_from_attributes(&specified_attrs);
+ let mandatory_attrs = CFSet::from_slice(&[family_attr.as_CFType()]);
+ let matched_descs = CTFontDescriptorCreateMatchingFontDescriptors(
+ wildcard_desc.as_concrete_TypeRef(),
+ mandatory_attrs.as_concrete_TypeRef(),
+ );
+ if matched_descs.is_null() {
+ return None;
+ }
+ let matched_descs = CFArray::wrap_under_create_rule(matched_descs);
+ // I suppose one doesn't even need the CTFontCollection object at this point.
+ // But we stick descriptors into and out of it just to provide a nice wrapper API.
+ Some(new_from_descriptors(&matched_descs))
+ }
+}
+
+pub fn get_family_names() -> CFArray<CFString> {
+ unsafe { CFArray::wrap_under_create_rule(CTFontManagerCopyAvailableFontFamilyNames()) }
+}
+
+pub fn get_postscript_names() -> CFArray<CFString> {
+ unsafe { CFArray::wrap_under_create_rule(CTFontManagerCopyAvailablePostScriptNames()) }
+}
+
+extern "C" {
+ /*
+ * CTFontCollection.h
+ */
+
+ static kCTFontCollectionRemoveDuplicatesOption: CFStringRef;
+
+ //fn CTFontCollectionCreateCopyWithFontDescriptors(original: CTFontCollectionRef,
+ // descriptors: CFArrayRef,
+ // options: CFDictionaryRef) -> CTFontCollectionRef;
+ fn CTFontCollectionCreateFromAvailableFonts(options: CFDictionaryRef) -> CTFontCollectionRef;
+ // this stupid function doesn't actually do any wildcard expansion;
+ // it just chooses the best match. Use
+ // CTFontDescriptorCreateMatchingDescriptors instead.
+ fn CTFontCollectionCreateMatchingFontDescriptors(collection: CTFontCollectionRef)
+ -> CFArrayRef;
+ fn CTFontCollectionCreateWithFontDescriptors(
+ descriptors: CFArrayRef,
+ options: CFDictionaryRef,
+ ) -> CTFontCollectionRef;
+ //fn CTFontCollectionCreateMatchingFontDescriptorsSortedWithCallback;
+ fn CTFontCollectionGetTypeID() -> CFTypeID;
+}
diff --git a/third_party/rust/core-text/src/font_descriptor.rs b/third_party/rust/core-text/src/font_descriptor.rs
new file mode 100644
index 0000000000..e5506d2162
--- /dev/null
+++ b/third_party/rust/core-text/src/font_descriptor.rs
@@ -0,0 +1,441 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_upper_case_globals)]
+
+use core_foundation::array::CFArrayRef;
+use core_foundation::base::{CFType, CFTypeID, CFTypeRef, TCFType};
+use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
+use core_foundation::number::{CFNumber, CFNumberRef};
+use core_foundation::set::CFSetRef;
+use core_foundation::string::{CFString, CFStringRef};
+use core_foundation::url::{CFURLRef, CFURL};
+use core_graphics::base::CGFloat;
+
+use std::os::raw::c_void;
+use std::path::PathBuf;
+
+/*
+* CTFontTraits.h
+*/
+// actually, these are extern enums
+pub type CTFontFormat = u32;
+pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
+pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
+pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
+pub const kCTFontFormatTrueType: CTFontFormat = 3;
+pub const kCTFontFormatPostScript: CTFontFormat = 4;
+pub const kCTFontFormatBitmap: CTFontFormat = 5;
+
+pub const kCTFontClassMaskShift: u32 = 28;
+
+pub type CTFontSymbolicTraits = u32;
+pub const kCTFontItalicTrait: CTFontSymbolicTraits = 1 << 0;
+pub const kCTFontBoldTrait: CTFontSymbolicTraits = 1 << 1;
+pub const kCTFontExpandedTrait: CTFontSymbolicTraits = 1 << 5;
+pub const kCTFontCondensedTrait: CTFontSymbolicTraits = 1 << 6;
+pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = 1 << 10;
+pub const kCTFontVerticalTrait: CTFontSymbolicTraits = 1 << 11;
+pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = 1 << 12;
+pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = 1 << 13;
+pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = 15 << kCTFontClassMaskShift;
+
+pub trait SymbolicTraitAccessors {
+ fn is_italic(&self) -> bool;
+ fn is_bold(&self) -> bool;
+ fn is_expanded(&self) -> bool;
+ fn is_condensed(&self) -> bool;
+ fn is_monospace(&self) -> bool;
+ fn is_vertical(&self) -> bool;
+}
+
+impl SymbolicTraitAccessors for CTFontSymbolicTraits {
+ fn is_italic(&self) -> bool {
+ (*self & kCTFontItalicTrait) != 0
+ }
+ fn is_bold(&self) -> bool {
+ (*self & kCTFontBoldTrait) != 0
+ }
+ fn is_expanded(&self) -> bool {
+ (*self & kCTFontExpandedTrait) != 0
+ }
+ fn is_condensed(&self) -> bool {
+ (*self & kCTFontCondensedTrait) != 0
+ }
+ fn is_monospace(&self) -> bool {
+ (*self & kCTFontMonoSpaceTrait) != 0
+ }
+ fn is_vertical(&self) -> bool {
+ (*self & kCTFontVerticalTrait) != 0
+ }
+}
+
+pub type CTFontStylisticClass = u32;
+pub const kCTFontUnknownClass: CTFontStylisticClass = 0 << kCTFontClassMaskShift;
+pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = 1 << kCTFontClassMaskShift;
+pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = 2 << kCTFontClassMaskShift;
+pub const kCTFontModernSerifsClass: CTFontStylisticClass = 3 << kCTFontClassMaskShift;
+pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = 4 << kCTFontClassMaskShift;
+pub const kCTFontSlabSerifsClass: CTFontStylisticClass = 5 << kCTFontClassMaskShift;
+pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = 7 << kCTFontClassMaskShift;
+pub const kCTFontSansSerifClass: CTFontStylisticClass = 8 << kCTFontClassMaskShift;
+pub const kCTFontOrnamentalsClass: CTFontStylisticClass = 9 << kCTFontClassMaskShift;
+pub const kCTFontScriptsClass: CTFontStylisticClass = 10 << kCTFontClassMaskShift;
+pub const kCTFontSymbolicClass: CTFontStylisticClass = 12 << kCTFontClassMaskShift;
+
+pub trait StylisticClassAccessors {
+ fn is_serif(&self) -> bool;
+ fn is_sans_serif(&self) -> bool;
+ fn is_script(&self) -> bool;
+ fn is_fantasy(&self) -> bool;
+ fn is_symbols(&self) -> bool;
+}
+
+impl StylisticClassAccessors for CTFontStylisticClass {
+ fn is_serif(&self) -> bool {
+ let any_serif_class = kCTFontOldStyleSerifsClass
+ | kCTFontTransitionalSerifsClass
+ | kCTFontModernSerifsClass
+ | kCTFontClarendonSerifsClass
+ | kCTFontSlabSerifsClass
+ | kCTFontFreeformSerifsClass;
+
+ (*self & any_serif_class) != 0
+ }
+
+ fn is_sans_serif(&self) -> bool {
+ (*self & kCTFontSansSerifClass) != 0
+ }
+
+ fn is_script(&self) -> bool {
+ (*self & kCTFontScriptsClass) != 0
+ }
+
+ fn is_fantasy(&self) -> bool {
+ (*self & kCTFontOrnamentalsClass) != 0
+ }
+
+ fn is_symbols(&self) -> bool {
+ (*self & kCTFontSymbolicClass) != 0
+ }
+}
+
+pub type CTFontAttributes = CFDictionary;
+
+pub type CTFontTraits = CFDictionary<CFString, CFType>;
+
+pub trait TraitAccessors {
+ fn symbolic_traits(&self) -> CTFontSymbolicTraits;
+ fn normalized_weight(&self) -> f64;
+ fn normalized_width(&self) -> f64;
+ fn normalized_slant(&self) -> f64;
+}
+
+trait TraitAccessorPrivate {
+ fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
+}
+
+impl TraitAccessorPrivate for CTFontTraits {
+ fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
+ let cftype = self.get(key);
+ cftype.downcast::<CFNumber>().unwrap()
+ }
+}
+
+impl TraitAccessors for CTFontTraits {
+ fn symbolic_traits(&self) -> CTFontSymbolicTraits {
+ unsafe {
+ let number = self.extract_number_for_key(kCTFontSymbolicTrait);
+ number.to_i64().unwrap() as u32
+ }
+ }
+
+ fn normalized_weight(&self) -> f64 {
+ unsafe {
+ let number = self.extract_number_for_key(kCTFontWeightTrait);
+ number.to_f64().unwrap()
+ }
+ }
+
+ fn normalized_width(&self) -> f64 {
+ unsafe {
+ let number = self.extract_number_for_key(kCTFontWidthTrait);
+ number.to_f64().unwrap()
+ }
+ }
+
+ fn normalized_slant(&self) -> f64 {
+ unsafe {
+ let number = self.extract_number_for_key(kCTFontSlantTrait);
+ number.to_f64().unwrap()
+ }
+ }
+}
+
+/*
+* CTFontDescriptor.h
+*/
+pub type CTFontOrientation = u32;
+pub const kCTFontDefaultOrientation: CTFontOrientation = 0; // deprecated since macOS 10.11, iOS 9
+pub const kCTFontOrientationDefault: CTFontOrientation = 0; // introduced in macOS 10.8, iOS 6
+pub const kCTFontHorizontalOrientation: CTFontOrientation = 1; // deprecated since macOS 10.11, iOS 9
+pub const kCTFontOrientationHorizontal: CTFontOrientation = 1; // introduced in macOS 10.8, iOS 6
+pub const kCTFontVerticalOrientation: CTFontOrientation = 2; // deprecated since macOS 10.11, iOS 9
+pub const kCTFontOrientationVertical: CTFontOrientation = 2; // introduced in macOS 10.8, iOS 6
+
+pub type CTFontPriority = u32;
+pub const kCTFontPrioritySystem: CTFontPriority = 10000;
+pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
+pub const kCTFontPriorityComputer: CTFontPriority = 30000;
+pub const kCTFontPriorityUser: CTFontPriority = 40000;
+pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
+pub const kCTFontPriorityProcess: CTFontPriority = 60000;
+
+#[repr(C)]
+pub struct __CTFontDescriptor(c_void);
+
+pub type CTFontDescriptorRef = *const __CTFontDescriptor;
+
+declare_TCFType! {
+ CTFontDescriptor, CTFontDescriptorRef
+}
+impl_TCFType!(
+ CTFontDescriptor,
+ CTFontDescriptorRef,
+ CTFontDescriptorGetTypeID
+);
+impl_CFTypeDescription!(CTFontDescriptor);
+
+// "Font objects (CTFont, CTFontDescriptor, and associated objects) can be used
+// simultaneously by multiple operations, work queues, or threads."
+unsafe impl Send for CTFontDescriptor {}
+unsafe impl Sync for CTFontDescriptor {}
+
+impl CTFontDescriptor {
+ fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
+ unsafe {
+ let value = CTFontDescriptorCopyAttribute(self.0, attribute);
+ if value.is_null() {
+ return None;
+ }
+
+ let value = CFType::wrap_under_create_rule(value);
+ assert!(value.instance_of::<CFString>());
+ let s = CFString::wrap_under_get_rule(value.as_CFTypeRef() as CFStringRef);
+ Some(s.to_string())
+ }
+ }
+}
+
+impl CTFontDescriptor {
+ pub fn family_name(&self) -> String {
+ unsafe {
+ let value = self.get_string_attribute(kCTFontFamilyNameAttribute);
+ value.expect("A font must have a non-null family name.")
+ }
+ }
+
+ pub fn font_name(&self) -> String {
+ unsafe {
+ let value = self.get_string_attribute(kCTFontNameAttribute);
+ value.expect("A font must have a non-null name.")
+ }
+ }
+
+ pub fn style_name(&self) -> String {
+ unsafe {
+ let value = self.get_string_attribute(kCTFontStyleNameAttribute);
+ value.expect("A font must have a non-null style name.")
+ }
+ }
+
+ pub fn display_name(&self) -> String {
+ unsafe {
+ let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
+ value.expect("A font must have a non-null display name.")
+ }
+ }
+
+ pub fn font_format(&self) -> Option<CTFontFormat> {
+ unsafe {
+ let value = CTFontDescriptorCopyAttribute(self.0, kCTFontFormatAttribute);
+ if value.is_null() {
+ return None;
+ }
+
+ let value = CFType::wrap_under_create_rule(value);
+ assert!(value.instance_of::<CFNumber>());
+ let format = CFNumber::wrap_under_get_rule(value.as_CFTypeRef() as CFNumberRef);
+ format.to_i32().map(|x| x as CTFontFormat)
+ }
+ }
+
+ pub fn font_path(&self) -> Option<PathBuf> {
+ unsafe {
+ let value = CTFontDescriptorCopyAttribute(self.0, kCTFontURLAttribute);
+ if value.is_null() {
+ return None;
+ }
+
+ let value = CFType::wrap_under_create_rule(value);
+ assert!(value.instance_of::<CFURL>());
+ let url = CFURL::wrap_under_get_rule(value.as_CFTypeRef() as CFURLRef);
+ url.to_path()
+ }
+ }
+
+ pub fn traits(&self) -> CTFontTraits {
+ unsafe {
+ let value = CTFontDescriptorCopyAttribute(self.0, kCTFontTraitsAttribute);
+ assert!(!value.is_null());
+ let value = CFType::wrap_under_create_rule(value);
+ assert!(value.instance_of::<CFDictionary>());
+ CFDictionary::wrap_under_get_rule(value.as_CFTypeRef() as CFDictionaryRef)
+ }
+ }
+
+ pub fn create_copy_with_attributes(&self, attr: CFDictionary) -> Result<CTFontDescriptor, ()> {
+ unsafe {
+ let desc = CTFontDescriptorCreateCopyWithAttributes(
+ self.as_concrete_TypeRef(),
+ attr.as_concrete_TypeRef(),
+ );
+ if desc.is_null() {
+ return Err(());
+ }
+ Ok(CTFontDescriptor::wrap_under_create_rule(desc))
+ }
+ }
+
+ pub fn attributes(&self) -> CFDictionary<CFString, CFType> {
+ unsafe {
+ let attrs = CTFontDescriptorCopyAttributes(self.as_concrete_TypeRef());
+ CFDictionary::wrap_under_create_rule(attrs)
+ }
+ }
+}
+
+pub fn new_from_attributes(attributes: &CFDictionary<CFString, CFType>) -> CTFontDescriptor {
+ unsafe {
+ let result: CTFontDescriptorRef =
+ CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
+ CTFontDescriptor::wrap_under_create_rule(result)
+ }
+}
+
+pub fn new_from_variations(variations: &CFDictionary<CFString, CFNumber>) -> CTFontDescriptor {
+ unsafe {
+ let var_key = CFString::wrap_under_get_rule(kCTFontVariationAttribute);
+ let var_val = CFType::wrap_under_get_rule(variations.as_CFTypeRef());
+ let attributes = CFDictionary::from_CFType_pairs(&[(var_key, var_val)]);
+ new_from_attributes(&attributes)
+ }
+}
+
+pub fn new_from_postscript_name(name: &CFString) -> CTFontDescriptor {
+ unsafe {
+ let result: CTFontDescriptorRef =
+ CTFontDescriptorCreateWithNameAndSize(name.as_concrete_TypeRef(), 0.0);
+ CTFontDescriptor::wrap_under_create_rule(result)
+ }
+}
+
+pub fn debug_descriptor(desc: &CTFontDescriptor) {
+ println!("family: {}", desc.family_name());
+ println!("name: {}", desc.font_name());
+ println!("style: {}", desc.style_name());
+ println!("display: {}", desc.display_name());
+ println!("path: {:?}", desc.font_path());
+ desc.show();
+}
+
+extern "C" {
+ /*
+ * CTFontTraits.h
+ */
+
+ // font trait constants
+ pub static kCTFontSymbolicTrait: CFStringRef;
+ pub static kCTFontWeightTrait: CFStringRef;
+ pub static kCTFontWidthTrait: CFStringRef;
+ pub static kCTFontSlantTrait: CFStringRef;
+
+ /*
+ * CTFontDescriptor.h
+ */
+
+ // font attribute constants. Note that the name-related attributes
+ // here are somewhat flaky. Servo creates CTFont instances and
+ // then uses CTFontCopyName to get more fine-grained names.
+ pub static kCTFontURLAttribute: CFStringRef; // value: CFURLRef
+ pub static kCTFontNameAttribute: CFStringRef; // value: CFStringRef
+ pub static kCTFontDisplayNameAttribute: CFStringRef; // value: CFStringRef
+ pub static kCTFontFamilyNameAttribute: CFStringRef; // value: CFStringRef
+ pub static kCTFontStyleNameAttribute: CFStringRef; // value: CFStringRef
+ pub static kCTFontTraitsAttribute: CFStringRef;
+ pub static kCTFontVariationAttribute: CFStringRef;
+ pub static kCTFontSizeAttribute: CFStringRef;
+ pub static kCTFontMatrixAttribute: CFStringRef;
+ pub static kCTFontCascadeListAttribute: CFStringRef;
+ pub static kCTFontCharacterSetAttribute: CFStringRef;
+ pub static kCTFontLanguagesAttribute: CFStringRef;
+ pub static kCTFontBaselineAdjustAttribute: CFStringRef;
+ pub static kCTFontMacintoshEncodingsAttribute: CFStringRef;
+ pub static kCTFontFeaturesAttribute: CFStringRef;
+ pub static kCTFontFeatureSettingsAttribute: CFStringRef;
+ pub static kCTFontFixedAdvanceAttribute: CFStringRef;
+ pub static kCTFontOrientationAttribute: CFStringRef;
+ pub static kCTFontFormatAttribute: CFStringRef;
+ pub static kCTFontRegistrationScopeAttribute: CFStringRef;
+ pub static kCTFontPriorityAttribute: CFStringRef;
+ pub static kCTFontEnabledAttribute: CFStringRef;
+
+ pub fn CTFontDescriptorCopyAttribute(
+ descriptor: CTFontDescriptorRef,
+ attribute: CFStringRef,
+ ) -> CFTypeRef;
+ pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
+ pub fn CTFontDescriptorCopyLocalizedAttribute(
+ descriptor: CTFontDescriptorRef,
+ attribute: CFStringRef,
+ language: *mut CFStringRef,
+ ) -> CFTypeRef;
+ pub fn CTFontDescriptorCreateCopyWithAttributes(
+ original: CTFontDescriptorRef,
+ attributes: CFDictionaryRef,
+ ) -> CTFontDescriptorRef;
+ pub fn CTFontDescriptorCreateCopyWithFeature(
+ original: CTFontDescriptorRef,
+ featureTypeIdentifier: CFNumberRef,
+ featureSelectorIdentifier: CFNumberRef,
+ ) -> CTFontDescriptorRef;
+ pub fn CTFontDescriptorCreateCopyWithVariation(
+ original: CTFontDescriptorRef,
+ variationIdentifier: CFNumberRef,
+ variationValue: CGFloat,
+ ) -> CTFontDescriptorRef;
+ pub fn CTFontDescriptorCreateMatchingFontDescriptor(
+ descriptor: CTFontDescriptorRef,
+ mandatoryAttributes: CFSetRef,
+ ) -> CTFontDescriptorRef;
+ pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef)
+ -> CTFontDescriptorRef;
+ pub fn CTFontDescriptorCreateWithNameAndSize(
+ name: CFStringRef,
+ size: CGFloat,
+ ) -> CTFontDescriptorRef;
+ pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
+}
+
+extern "C" {
+ pub fn CTFontDescriptorCreateMatchingFontDescriptors(
+ descriptor: CTFontDescriptorRef,
+ mandatoryAttributes: CFSetRef,
+ ) -> CFArrayRef;
+}
diff --git a/third_party/rust/core-text/src/font_manager.rs b/third_party/rust/core-text/src/font_manager.rs
new file mode 100644
index 0000000000..dff0f8d0fb
--- /dev/null
+++ b/third_party/rust/core-text/src/font_manager.rs
@@ -0,0 +1,76 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};
+use core_foundation::array::{CFArray, CFArrayRef};
+use core_foundation::base::TCFType;
+use core_foundation::data::{CFData, CFDataRef};
+use core_foundation::string::CFString;
+use core_foundation::url::CFURLRef;
+
+pub fn copy_available_font_family_names() -> CFArray<CFString> {
+ unsafe { TCFType::wrap_under_create_rule(CTFontManagerCopyAvailableFontFamilyNames()) }
+}
+
+pub fn create_font_descriptor(buffer: &[u8]) -> Result<CTFontDescriptor, ()> {
+ let cf_data = CFData::from_buffer(buffer);
+ 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,
+ ))
+ }
+}
+
+pub fn create_font_descriptor_with_data(data: CFData) -> Result<CTFontDescriptor, ()> {
+ unsafe {
+ let ct_font_descriptor_ref =
+ CTFontManagerCreateFontDescriptorFromData(data.as_concrete_TypeRef());
+ if ct_font_descriptor_ref.is_null() {
+ return Err(());
+ }
+ Ok(CTFontDescriptor::wrap_under_create_rule(
+ ct_font_descriptor_ref,
+ ))
+ }
+}
+
+extern "C" {
+ /*
+ * CTFontManager.h
+ */
+
+ // Incomplete function bindings are mostly related to CoreText font matching, which
+ // we implement in a platform-independent manner using FontMatcher.
+
+ //pub fn CTFontManagerCompareFontFamilyNames
+ pub fn CTFontManagerCopyAvailableFontURLs() -> CFArrayRef;
+ pub fn CTFontManagerCopyAvailableFontFamilyNames() -> CFArrayRef;
+ pub fn CTFontManagerCopyAvailablePostScriptNames() -> CFArrayRef;
+ pub fn CTFontManagerCreateFontDescriptorsFromURL(fileURL: CFURLRef) -> CFArrayRef;
+ pub fn CTFontManagerCreateFontDescriptorFromData(data: CFDataRef) -> CTFontDescriptorRef;
+ //pub fn CTFontManagerCreateFontRequestRunLoopSource
+ //pub fn CTFontManagerEnableFontDescriptors
+ //pub fn CTFontManagerGetAutoActivationSetting
+ //pub fn CTFontManagerGetScopeForURL
+ //pub fn CTFontManagerGetAutoActivationSetting
+ //pub fn CTFontManagerGetScopeForURL
+ pub fn CTFontManagerIsSupportedFont(fontURL: CFURLRef) -> bool;
+ //pub fn CTFontManagerRegisterFontsForURL
+ //pub fn CTFontManagerRegisterFontsForURLs
+ //pub fn CTFontManagerRegisterGraphicsFont
+ //pub fn CTFontManagerSetAutoActivationSetting
+ //pub fn CTFontManagerUnregisterFontsForURL
+ //pub fn CTFontManagerUnregisterFontsForURLs
+ //pub fn CTFontManagerUnregisterGraphicsFont
+}
diff --git a/third_party/rust/core-text/src/frame.rs b/third_party/rust/core-text/src/frame.rs
new file mode 100644
index 0000000000..03fcee902a
--- /dev/null
+++ b/third_party/rust/core-text/src/frame.rs
@@ -0,0 +1,94 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::line::CTLine;
+use core_foundation::array::{CFArray, CFArrayRef};
+use core_foundation::base::{CFRange, CFTypeID, TCFType};
+use core_graphics::context::{CGContext, CGContextRef};
+use core_graphics::geometry::CGPoint;
+use core_graphics::path::{CGPath, SysCGPathRef};
+use foreign_types::{ForeignType, ForeignTypeRef};
+use std::os::raw::c_void;
+
+#[repr(C)]
+pub struct __CTFrame(c_void);
+
+pub type CTFrameRef = *const __CTFrame;
+
+declare_TCFType! {
+ CTFrame, CTFrameRef
+}
+impl_TCFType!(CTFrame, CTFrameRef, CTFrameGetTypeID);
+impl_CFTypeDescription!(CTFrame);
+
+impl CTFrame {
+ /// The `CGPath` used to create this `CTFrame`.
+ pub fn get_path(&self) -> CGPath {
+ unsafe { CGPath::from_ptr(CTFrameGetPath(self.as_concrete_TypeRef())).clone() }
+ }
+
+ /// Returns an owned copy of the underlying lines.
+ ///
+ /// Each line is retained, and will remain valid past the life of this `CTFrame`.
+ pub fn get_lines(&self) -> Vec<CTLine> {
+ unsafe {
+ let array_ref = CTFrameGetLines(self.as_concrete_TypeRef());
+ let array: CFArray<CTLine> = CFArray::wrap_under_get_rule(array_ref);
+ array
+ .iter()
+ .map(|l| CTLine::wrap_under_get_rule(l.as_concrete_TypeRef()))
+ .collect()
+ }
+ }
+
+ /// Return the origin of each line in a given range.
+ ///
+ /// If no range is provided, returns the origin of each line in the frame.
+ ///
+ /// If the length of the range is 0, returns the origin of all lines from
+ /// the range's start to the end.
+ ///
+ /// The origin is the position relative to the path used to create this `CTFFrame`;
+ /// to get the path use [`get_path`].
+ ///
+ /// [`get_path`]: #method.get_path
+ pub fn get_line_origins(&self, range: impl Into<Option<CFRange>>) -> Vec<CGPoint> {
+ let range = range.into().unwrap_or_else(|| CFRange::init(0, 0));
+ let len = match range.length {
+ // range length of 0 means 'all remaining lines'
+ 0 => unsafe {
+ let array_ref = CTFrameGetLines(self.as_concrete_TypeRef());
+ let array: CFArray<CTLine> = CFArray::wrap_under_get_rule(array_ref);
+ array.len() - range.location
+ },
+ n => n,
+ };
+ let len = len.max(0) as usize;
+ let mut out = vec![CGPoint::new(0., 0.); len];
+ unsafe {
+ CTFrameGetLineOrigins(self.as_concrete_TypeRef(), range, out.as_mut_ptr());
+ }
+ out
+ }
+
+ pub fn draw(&self, context: &CGContextRef) {
+ unsafe {
+ CTFrameDraw(self.as_concrete_TypeRef(), context.as_ptr());
+ }
+ }
+}
+
+#[link(name = "CoreText", kind = "framework")]
+extern "C" {
+ fn CTFrameGetTypeID() -> CFTypeID;
+ fn CTFrameGetLines(frame: CTFrameRef) -> CFArrayRef;
+ fn CTFrameDraw(frame: CTFrameRef, context: *mut <CGContext as ForeignType>::CType);
+ fn CTFrameGetLineOrigins(frame: CTFrameRef, range: CFRange, origins: *mut CGPoint);
+ fn CTFrameGetPath(frame: CTFrameRef) -> SysCGPathRef;
+}
diff --git a/third_party/rust/core-text/src/framesetter.rs b/third_party/rust/core-text/src/framesetter.rs
new file mode 100644
index 0000000000..dacb540b85
--- /dev/null
+++ b/third_party/rust/core-text/src/framesetter.rs
@@ -0,0 +1,94 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::frame::{CTFrame, CTFrameRef};
+use core_foundation::attributed_string::CFAttributedStringRef;
+use core_foundation::base::{CFRange, CFTypeID, TCFType};
+use core_foundation::dictionary::CFDictionaryRef;
+use core_graphics::geometry::CGSize;
+use core_graphics::path::{CGPath, CGPathRef};
+use foreign_types::{ForeignType, ForeignTypeRef};
+use std::os::raw::c_void;
+use std::ptr::null;
+
+#[repr(C)]
+pub struct __CTFramesetter(c_void);
+
+pub type CTFramesetterRef = *const __CTFramesetter;
+
+declare_TCFType! {
+ CTFramesetter, CTFramesetterRef
+}
+impl_TCFType!(CTFramesetter, CTFramesetterRef, CTFramesetterGetTypeID);
+impl_CFTypeDescription!(CTFramesetter);
+
+impl CTFramesetter {
+ pub fn new_with_attributed_string(string: CFAttributedStringRef) -> Self {
+ unsafe {
+ let ptr = CTFramesetterCreateWithAttributedString(string);
+ CTFramesetter::wrap_under_create_rule(ptr)
+ }
+ }
+
+ pub fn create_frame(&self, string_range: CFRange, path: &CGPathRef) -> CTFrame {
+ unsafe {
+ let ptr = CTFramesetterCreateFrame(
+ self.as_concrete_TypeRef(),
+ string_range,
+ path.as_ptr(),
+ null(),
+ );
+
+ CTFrame::wrap_under_create_rule(ptr)
+ }
+ }
+
+ /// Suggest an appropriate frame size for displaying a text range.
+ ///
+ /// Returns a tuple containing an appropriate size (that should be smaller
+ /// than the provided constraints) as well as the range of text that fits in
+ /// this frame.
+ pub fn suggest_frame_size_with_constraints(
+ &self,
+ string_range: CFRange,
+ frame_attributes: CFDictionaryRef,
+ constraints: CGSize,
+ ) -> (CGSize, CFRange) {
+ unsafe {
+ let mut fit_range = CFRange::init(0, 0);
+ let size = CTFramesetterSuggestFrameSizeWithConstraints(
+ self.as_concrete_TypeRef(),
+ string_range,
+ frame_attributes,
+ constraints,
+ &mut fit_range,
+ );
+ (size, fit_range)
+ }
+ }
+}
+
+#[link(name = "CoreText", kind = "framework")]
+extern "C" {
+ fn CTFramesetterGetTypeID() -> CFTypeID;
+ fn CTFramesetterCreateWithAttributedString(string: CFAttributedStringRef) -> CTFramesetterRef;
+ fn CTFramesetterCreateFrame(
+ framesetter: CTFramesetterRef,
+ string_range: CFRange,
+ path: *mut <CGPath as ForeignType>::CType,
+ attributes: *const c_void,
+ ) -> CTFrameRef;
+ fn CTFramesetterSuggestFrameSizeWithConstraints(
+ framesetter: CTFramesetterRef,
+ string_range: CFRange,
+ frame_attributes: CFDictionaryRef,
+ constraints: CGSize,
+ fitRange: *mut CFRange,
+ ) -> CGSize;
+}
diff --git a/third_party/rust/core-text/src/lib.rs b/third_party/rust/core-text/src/lib.rs
new file mode 100644
index 0000000000..be394b020d
--- /dev/null
+++ b/third_party/rust/core-text/src/lib.rs
@@ -0,0 +1,34 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "core_text"]
+#![crate_type = "rlib"]
+#![allow(non_snake_case)]
+
+/*!
+Many of these functions will add objects to the autorelease pool.
+If you don't have one this will cause leaks.
+*/
+
+extern crate foreign_types;
+extern crate libc;
+
+#[macro_use]
+extern crate core_foundation;
+extern crate core_graphics;
+
+pub mod font;
+pub mod font_collection;
+pub mod font_descriptor;
+pub mod font_manager;
+pub mod frame;
+pub mod framesetter;
+pub mod line;
+pub mod run;
+pub mod string_attributes;
diff --git a/third_party/rust/core-text/src/line.rs b/third_party/rust/core-text/src/line.rs
new file mode 100644
index 0000000000..b2645aaf5c
--- /dev/null
+++ b/third_party/rust/core-text/src/line.rs
@@ -0,0 +1,125 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core_foundation::array::{CFArray, CFArrayRef};
+use core_foundation::attributed_string::CFAttributedStringRef;
+use core_foundation::base::{CFIndex, CFRange, CFTypeID, TCFType};
+use core_graphics::base::CGFloat;
+use core_graphics::context::CGContext;
+use core_graphics::geometry::{CGPoint, CGRect};
+use foreign_types::ForeignType;
+use run::CTRun;
+use std::os::raw::c_void;
+
+#[repr(C)]
+pub struct __CTLine(c_void);
+
+pub type CTLineRef = *const __CTLine;
+
+declare_TCFType! {
+ CTLine, CTLineRef
+}
+impl_TCFType!(CTLine, CTLineRef, CTLineGetTypeID);
+impl_CFTypeDescription!(CTLine);
+
+/// Metrics for a given line.
+pub struct TypographicBounds {
+ pub width: CGFloat,
+ pub ascent: CGFloat,
+ pub descent: CGFloat,
+ pub leading: CGFloat,
+}
+
+impl CTLine {
+ pub fn new_with_attributed_string(string: CFAttributedStringRef) -> Self {
+ unsafe {
+ let ptr = CTLineCreateWithAttributedString(string);
+ CTLine::wrap_under_create_rule(ptr)
+ }
+ }
+
+ pub fn glyph_runs(&self) -> CFArray<CTRun> {
+ unsafe { TCFType::wrap_under_get_rule(CTLineGetGlyphRuns(self.0)) }
+ }
+
+ pub fn get_string_range(&self) -> CFRange {
+ unsafe { CTLineGetStringRange(self.as_concrete_TypeRef()) }
+ }
+
+ pub fn draw(&self, context: &CGContext) {
+ unsafe { CTLineDraw(self.as_concrete_TypeRef(), context.as_ptr()) }
+ }
+
+ pub fn get_image_bounds(&self, context: &CGContext) -> CGRect {
+ unsafe { CTLineGetImageBounds(self.as_concrete_TypeRef(), context.as_ptr()) }
+ }
+
+ pub fn get_typographic_bounds(&self) -> TypographicBounds {
+ let mut ascent = 0.0;
+ let mut descent = 0.0;
+ let mut leading = 0.0;
+ unsafe {
+ let width = CTLineGetTypographicBounds(
+ self.as_concrete_TypeRef(),
+ &mut ascent,
+ &mut descent,
+ &mut leading,
+ );
+ TypographicBounds {
+ width,
+ ascent,
+ descent,
+ leading,
+ }
+ }
+ }
+
+ pub fn get_string_index_for_position(&self, position: CGPoint) -> CFIndex {
+ unsafe { CTLineGetStringIndexForPosition(self.as_concrete_TypeRef(), position) }
+ }
+
+ pub fn get_string_offset_for_string_index(&self, charIndex: CFIndex) -> CGFloat {
+ unsafe {
+ CTLineGetOffsetForStringIndex(self.as_concrete_TypeRef(), charIndex, std::ptr::null())
+ }
+ }
+}
+
+#[link(name = "CoreText", kind = "framework")]
+extern "C" {
+ fn CTLineGetTypeID() -> CFTypeID;
+ fn CTLineGetGlyphRuns(line: CTLineRef) -> CFArrayRef;
+ fn CTLineGetStringRange(line: CTLineRef) -> CFRange;
+
+ // Creating Lines
+ fn CTLineCreateWithAttributedString(string: CFAttributedStringRef) -> CTLineRef;
+
+ // Drawing the Line
+ fn CTLineDraw(line: CTLineRef, context: *const core_graphics::sys::CGContext);
+
+ // Measuring Lines
+ fn CTLineGetImageBounds(
+ line: CTLineRef,
+ context: *const core_graphics::sys::CGContext,
+ ) -> CGRect;
+ fn CTLineGetTypographicBounds(
+ line: CTLineRef,
+ ascent: *mut CGFloat,
+ descent: *mut CGFloat,
+ leading: *mut CGFloat,
+ ) -> CGFloat;
+
+ // Getting Line Positioning
+ fn CTLineGetStringIndexForPosition(line: CTLineRef, position: CGPoint) -> CFIndex;
+ fn CTLineGetOffsetForStringIndex(
+ line: CTLineRef,
+ charIndex: CFIndex,
+ secondaryOffset: *const CGFloat,
+ ) -> CGFloat;
+}
diff --git a/third_party/rust/core-text/src/run.rs b/third_party/rust/core-text/src/run.rs
new file mode 100644
index 0000000000..f84fb46cb7
--- /dev/null
+++ b/third_party/rust/core-text/src/run.rs
@@ -0,0 +1,159 @@
+// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core_foundation::base::{CFIndex, CFRange, CFType, CFTypeID, TCFType};
+use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
+use core_foundation::string::CFString;
+use core_graphics::font::CGGlyph;
+use core_graphics::geometry::CGPoint;
+use std::borrow::Cow;
+use std::os::raw::c_void;
+use std::slice;
+
+#[repr(C)]
+pub struct __CTRun(c_void);
+
+pub type CTRunRef = *const __CTRun;
+
+declare_TCFType! {
+ CTRun, CTRunRef
+}
+impl_TCFType!(CTRun, CTRunRef, CTRunGetTypeID);
+impl_CFTypeDescription!(CTRun);
+
+impl CTRun {
+ pub fn attributes(&self) -> Option<CFDictionary<CFString, CFType>> {
+ unsafe {
+ let attrs = CTRunGetAttributes(self.0);
+ if attrs.is_null() {
+ return None;
+ }
+ Some(TCFType::wrap_under_get_rule(attrs))
+ }
+ }
+ pub fn glyph_count(&self) -> CFIndex {
+ unsafe { CTRunGetGlyphCount(self.0) }
+ }
+
+ pub fn glyphs(&self) -> Cow<[CGGlyph]> {
+ unsafe {
+ // CTRunGetGlyphsPtr can return null under some not understood circumstances.
+ // If it does the Apple documentation tells us to allocate our own buffer and call
+ // CTRunGetGlyphs
+ let count = CTRunGetGlyphCount(self.0);
+ let glyphs_ptr = CTRunGetGlyphsPtr(self.0);
+ if !glyphs_ptr.is_null() {
+ Cow::from(slice::from_raw_parts(glyphs_ptr, count as usize))
+ } else {
+ let mut vec = Vec::with_capacity(count as usize);
+ // "If the length of the range is set to 0, then the copy operation will continue
+ // from the start index of the range to the end of the run"
+ CTRunGetGlyphs(self.0, CFRange::init(0, 0), vec.as_mut_ptr());
+ vec.set_len(count as usize);
+ Cow::from(vec)
+ }
+ }
+ }
+
+ pub fn positions(&self) -> Cow<[CGPoint]> {
+ unsafe {
+ // CTRunGetPositionsPtr can return null under some not understood circumstances.
+ // If it does the Apple documentation tells us to allocate our own buffer and call
+ // CTRunGetPositions
+ let count = CTRunGetGlyphCount(self.0);
+ let positions_ptr = CTRunGetPositionsPtr(self.0);
+ if !positions_ptr.is_null() {
+ Cow::from(slice::from_raw_parts(positions_ptr, count as usize))
+ } else {
+ let mut vec = Vec::with_capacity(count as usize);
+ // "If the length of the range is set to 0, then the copy operation will continue
+ // from the start index of the range to the end of the run"
+ CTRunGetPositions(self.0, CFRange::init(0, 0), vec.as_mut_ptr());
+ vec.set_len(count as usize);
+ Cow::from(vec)
+ }
+ }
+ }
+
+ pub fn string_indices(&self) -> Cow<[CFIndex]> {
+ unsafe {
+ // CTRunGetStringIndicesPtr can return null under some not understood circumstances.
+ // If it does the Apple documentation tells us to allocate our own buffer and call
+ // CTRunGetStringIndices
+ let count = CTRunGetGlyphCount(self.0);
+ let indices_ptr = CTRunGetStringIndicesPtr(self.0);
+ if !indices_ptr.is_null() {
+ Cow::from(slice::from_raw_parts(indices_ptr, count as usize))
+ } else {
+ let mut vec = Vec::with_capacity(count as usize);
+ // "If the length of the range is set to 0, then the copy operation will continue
+ // from the start index of the range to the end of the run"
+ CTRunGetStringIndices(self.0, CFRange::init(0, 0), vec.as_mut_ptr());
+ vec.set_len(count as usize);
+ Cow::from(vec)
+ }
+ }
+ }
+}
+
+#[test]
+fn create_runs() {
+ use core_foundation::attributed_string::CFMutableAttributedString;
+ use font;
+ use line::*;
+ use string_attributes::*;
+ let mut string = CFMutableAttributedString::new();
+ string.replace_str(&CFString::new("Food"), CFRange::init(0, 0));
+ let len = string.char_len();
+ unsafe {
+ string.set_attribute(
+ CFRange::init(0, len),
+ kCTFontAttributeName,
+ &font::new_from_name("Helvetica", 16.).unwrap(),
+ );
+ }
+ let line = CTLine::new_with_attributed_string(string.as_concrete_TypeRef());
+ let runs = line.glyph_runs();
+ assert_eq!(runs.len(), 1);
+ for run in runs.iter() {
+ assert_eq!(run.glyph_count(), 4);
+ let font = run
+ .attributes()
+ .unwrap()
+ .get(CFString::new("NSFont"))
+ .downcast::<font::CTFont>()
+ .unwrap();
+ assert_eq!(font.pt_size(), 16.);
+
+ let positions = run.positions();
+ assert_eq!(positions.len(), 4);
+ assert!(positions[0].x < positions[1].x);
+
+ let glyphs = run.glyphs();
+ assert_eq!(glyphs.len(), 4);
+ assert_ne!(glyphs[0], glyphs[1]);
+ assert_eq!(glyphs[1], glyphs[2]);
+
+ let indices = run.string_indices();
+ assert_eq!(indices.as_ref(), &[0, 1, 2, 3]);
+ }
+}
+
+#[link(name = "CoreText", kind = "framework")]
+extern "C" {
+ fn CTRunGetTypeID() -> CFTypeID;
+ fn CTRunGetAttributes(run: CTRunRef) -> CFDictionaryRef;
+ fn CTRunGetGlyphCount(run: CTRunRef) -> CFIndex;
+ fn CTRunGetPositionsPtr(run: CTRunRef) -> *const CGPoint;
+ fn CTRunGetPositions(run: CTRunRef, range: CFRange, buffer: *const CGPoint);
+ fn CTRunGetStringIndicesPtr(run: CTRunRef) -> *const CFIndex;
+ fn CTRunGetStringIndices(run: CTRunRef, range: CFRange, buffer: *const CFIndex);
+ fn CTRunGetGlyphsPtr(run: CTRunRef) -> *const CGGlyph;
+ fn CTRunGetGlyphs(run: CTRunRef, range: CFRange, buffer: *const CGGlyph);
+}
diff --git a/third_party/rust/core-text/src/string_attributes.rs b/third_party/rust/core-text/src/string_attributes.rs
new file mode 100644
index 0000000000..4f38ced4b9
--- /dev/null
+++ b/third_party/rust/core-text/src/string_attributes.rs
@@ -0,0 +1,19 @@
+use core_foundation::string::CFStringRef;
+
+extern "C" {
+ pub static kCTCharacterShapeAttributeName: CFStringRef;
+ pub static kCTFontAttributeName: CFStringRef;
+ pub static kCTKernAttributeName: CFStringRef;
+ pub static kCTLigatureAttributeName: CFStringRef;
+ pub static kCTForegroundColorAttributeName: CFStringRef;
+ pub static kCTForegroundColorFromContextAttributeName: CFStringRef;
+ pub static kCTParagraphStyleAttributeName: CFStringRef;
+ pub static kCTStrokeWidthAttributeName: CFStringRef;
+ pub static kCTStrokeColorAttributeName: CFStringRef;
+ pub static kCTSuperscriptAttributeName: CFStringRef;
+ pub static kCTUnderlineColorAttributeName: CFStringRef;
+ pub static kCTUnderlineStyleAttributeName: CFStringRef;
+ pub static kCTVerticalFormsAttributeName: CFStringRef;
+ pub static kCTGlyphInfoAttributeName: CFStringRef;
+ pub static kCTRunDelegateAttributeName: CFStringRef;
+}