summaryrefslogtreecommitdiffstats
path: root/third_party/rust/core-text
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/rust/core-text
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/core-text')
-rw-r--r--third_party/rust/core-text/.cargo-checksum.json1
-rw-r--r--third_party/rust/core-text/COPYRIGHT5
-rw-r--r--third_party/rust/core-text/Cargo.toml36
-rw-r--r--third_party/rust/core-text/LICENSE-APACHE201
-rw-r--r--third_party/rust/core-text/LICENSE-MIT25
-rw-r--r--third_party/rust/core-text/README.md3
-rw-r--r--third_party/rust/core-text/src/font.rs744
-rw-r--r--third_party/rust/core-text/src/font_collection.rs131
-rw-r--r--third_party/rust/core-text/src/font_descriptor.rs404
-rw-r--r--third_party/rust/core-text/src/font_manager.rs72
-rw-r--r--third_party/rust/core-text/src/frame.rs93
-rw-r--r--third_party/rust/core-text/src/framesetter.rs94
-rw-r--r--third_party/rust/core-text/src/lib.rs35
-rw-r--r--third_party/rust/core-text/src/line.rs113
-rw-r--r--third_party/rust/core-text/src/run.rs152
-rw-r--r--third_party/rust/core-text/src/string_attributes.rs19
16 files changed, 2128 insertions, 0 deletions
diff --git a/third_party/rust/core-text/.cargo-checksum.json b/third_party/rust/core-text/.cargo-checksum.json
new file mode 100644
index 0000000000..057b261191
--- /dev/null
+++ b/third_party/rust/core-text/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"26a527860e530d18a5ce446ffb595f63a178504506fb4a283993402295053afe","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"98d25015857a430aac32f34bdc979a1a66e672a0ea42c5f92dd9cfe23c1fccfd","src/font.rs":"17d957510eee8d96ef2bc1b5bc97491917ac0336ad3dbf48416dda3685cef579","src/font_collection.rs":"02de0ce2a61683314897a521d31ab9cc572a8b10ceda2ac47181fbe18bf4f235","src/font_descriptor.rs":"43a2fec6bca9689d8172f363ab20ce8c633696974e1653cad2e072e3af776528","src/font_manager.rs":"6e5056a42868187e1f4e696c181ca247423308652d3c68867c708616031876e4","src/frame.rs":"ed1e2aad7be9dafc3e9729f2caecefd4214a9552f834932a414239146142069a","src/framesetter.rs":"13e34b4111cee5f023aa05e2220d2a6f102e96fd18c51a356992bffd6c9fc7c1","src/lib.rs":"1c662e51874eb43ff52a8a1af131d1b2fd84095c3d949a271dc895bf56fd0fc6","src/line.rs":"02fab7f07c3f6a003a7c35ffeb3d37546ae58e4da7fe05f26e520f283397a602","src/run.rs":"b86e9b9b39effe4a79c6002880d95f214742d448029a3111e288734abe75b827","src/string_attributes.rs":"ea0f854d64097d3626a03002323e2276e28affae7a698aaadd89dd6b744dd80f"},"package":"99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"} \ No newline at end of file
diff --git a/third_party/rust/core-text/COPYRIGHT b/third_party/rust/core-text/COPYRIGHT
new file mode 100644
index 0000000000..8b7291ad28
--- /dev/null
+++ b/third_party/rust/core-text/COPYRIGHT
@@ -0,0 +1,5 @@
+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. All files in the project carrying such notice may not be
+copied, modified, or distributed except according to those terms.
diff --git a/third_party/rust/core-text/Cargo.toml b/third_party/rust/core-text/Cargo.toml
new file mode 100644
index 0000000000..a674dc3327
--- /dev/null
+++ b/third_party/rust/core-text/Cargo.toml
@@ -0,0 +1,36 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "core-text"
+version = "19.2.0"
+authors = ["The Servo Project Developers"]
+description = "Bindings to the Core Text framework."
+license = "MIT/Apache-2.0"
+repository = "https://github.com/servo/core-foundation-rs"
+[package.metadata.docs.rs]
+default-target = "x86_64-apple-darwin"
+[dependencies.core-foundation]
+version = "0.9"
+
+[dependencies.core-graphics]
+version = "0.22.0"
+
+[dependencies.foreign-types]
+version = "0.3"
+
+[dependencies.libc]
+version = "0.2"
+
+[features]
+default = ["mountainlion"]
+mountainlion = []
diff --git a/third_party/rust/core-text/LICENSE-APACHE b/third_party/rust/core-text/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/core-text/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/core-text/LICENSE-MIT b/third_party/rust/core-text/LICENSE-MIT
new file mode 100644
index 0000000000..807526f57f
--- /dev/null
+++ b/third_party/rust/core-text/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2012-2013 Mozilla Foundation
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/core-text/README.md b/third_party/rust/core-text/README.md
new file mode 100644
index 0000000000..312fe3325d
--- /dev/null
+++ b/third_party/rust/core-text/README.md
@@ -0,0 +1,3 @@
+# core-text-rs
+
+[![Build Status](https://travis-ci.com/servo/core-text-rs.svg?branch=master)](https://travis-ci.com/servo/core-text-rs)
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..ebe6d580f5
--- /dev/null
+++ b/third_party/rust/core-text/src/font.rs
@@ -0,0 +1,744 @@
+// 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::{CFURL, CFURLRef};
+use core_graphics::base::CGFloat;
+use core_graphics::context::CGContext;
+use core_graphics::font::{CGGlyph, CGFont};
+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;
+
+#[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_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))
+ }
+ }
+}
+
+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 family_name(&self) -> String {
+ unsafe {
+ let value = get_string_by_name_key(self, kCTFontFamilyNameKey);
+ value.expect("Fonts should always have a family name.")
+ }
+ }
+
+ pub fn face_name(&self) -> String {
+ unsafe {
+ let value = get_string_by_name_key(self, kCTFontSubFamilyNameKey);
+ value.expect("Fonts should always have a face name.")
+ }
+ }
+
+ pub fn unique_name(&self) -> String {
+ unsafe {
+ let value = get_string_by_name_key(self, kCTFontUniqueNameKey);
+ value.expect("Fonts should always have a unique name.")
+ }
+ }
+
+ pub fn postscript_name(&self) -> String {
+ unsafe {
+ let value = get_string_by_name_key(self, kCTFontPostScriptNameKey);
+ value.expect("Fonts should always have a PostScript name.")
+ }
+ }
+
+ pub fn display_name(&self) -> String {
+ unsafe {
+ let value = get_string_by_name_key(self, kCTFontFullNameKey);
+ value.expect("Fonts should always have a PostScript name.")
+ }
+ }
+
+ pub fn style_name(&self) -> String {
+ unsafe {
+ let value = get_string_by_name_key(self, kCTFontStyleNameKey);
+ 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) as f64
+ }
+
+ 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
+fn get_string_by_name_key(font: &CTFont, name_key: CFStringRef) -> Option<String> {
+ unsafe {
+ let result = CTFontCopyName(font.as_concrete_TypeRef(), name_key);
+ if result.is_null() {
+ None
+ } else {
+ Some(CFString::wrap_under_create_rule(result).to_string())
+ }
+ }
+}
+
+pub fn debug_font_names(font: &CTFont) {
+ fn get_key(font: &CTFont, key: CFStringRef) -> String {
+ get_string_by_name_key(font, key).unwrap()
+ }
+
+ unsafe {
+ println!("kCTFontFamilyNameKey: {}", get_key(font, kCTFontFamilyNameKey));
+ println!("kCTFontSubFamilyNameKey: {}", get_key(font, kCTFontSubFamilyNameKey));
+ println!("kCTFontStyleNameKey: {}", get_key(font, kCTFontStyleNameKey));
+ println!("kCTFontUniqueNameKey: {}", get_key(font, kCTFontUniqueNameKey));
+ println!("kCTFontFullNameKey: {}", get_key(font, kCTFontFullNameKey));
+ println!("kCTFontPostScriptNameKey: {}", get_key(font, kCTFontPostScriptNameKey));
+ }
+}
+
+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 {
+ /*
+ * 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;
+
+ //static kCTFontVariationAxisIdentifierKey: CFStringRef;
+ //static kCTFontVariationAxisMinimumValueKey: CFStringRef;
+ //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
+ fn CTFontCreateWithFontDescriptor(descriptor: CTFontDescriptorRef, size: CGFloat,
+ matrix: *const CGAffineTransform) -> CTFontRef;
+ //fn CTFontCreateWithFontDescriptorAndOptions
+ #[cfg(test)]
+ 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() {
+ let small = unsafe {
+ CTFont::wrap_under_create_rule(
+ CTFontCreateUIFontForLanguage(kCTFontSystemDetailFontType, 19., std::ptr::null())
+ )
+ };
+ 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());
+
+ // 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());
+} \ No newline at end of file
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..8f3f2c5619
--- /dev/null
+++ b/third_party/rust/core-text/src/font_collection.rs
@@ -0,0 +1,131 @@
+// 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 {
+ /*
+ * 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..c70495c829
--- /dev/null
+++ b/third_party/rust/core-text/src/font_descriptor.rs
@@ -0,0 +1,404 @@
+// 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::{CFURL, CFURLRef};
+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;
+pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
+pub const kCTFontVerticalOrientation: CTFontOrientation = 2;
+
+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 {
+ /*
+ * 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 {
+ 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..cdf65ee3bf
--- /dev/null
+++ b/third_party/rust/core-text/src/font_manager.rs
@@ -0,0 +1,72 @@
+// 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::base::TCFType;
+use core_foundation::string::CFString;
+use core_foundation::url::CFURLRef;
+use core_foundation::data::{CFDataRef, CFData};
+use crate::font_descriptor::{CTFontDescriptorRef, CTFontDescriptor};
+
+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 {
+ /*
+ * 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..95b97c802b
--- /dev/null
+++ b/third_party/rust/core-text/src/frame.rs
@@ -0,0 +1,93 @@
+// 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 std::os::raw::c_void;
+use core_foundation::base::{CFRange, CFTypeID, TCFType};
+use core_foundation::array::{CFArrayRef, CFArray};
+use core_graphics::context::{CGContext, CGContextRef};
+use core_graphics::geometry::CGPoint;
+use core_graphics::path::{CGPath, SysCGPathRef};
+use foreign_types::{ForeignType, ForeignTypeRef};
+use crate::line::CTLine;
+
+#[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 {
+ 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..1e6288bcd1
--- /dev/null
+++ b/third_party/rust/core-text/src/lib.rs
@@ -0,0 +1,35 @@
+// 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..50c1b4785d
--- /dev/null
+++ b/third_party/rust/core-text/src/line.rs
@@ -0,0 +1,113 @@
+// 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 std::os::raw::c_void;
+use core_foundation::attributed_string::CFAttributedStringRef;
+use core_foundation::array::{CFArray, CFArrayRef};
+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;
+
+#[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 {
+ 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..b7cb37616e
--- /dev/null
+++ b/third_party/rust/core-text/src/run.rs
@@ -0,0 +1,152 @@
+// 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 std::borrow::Cow;
+use std::os::raw::c_void;
+use std::slice;
+use core_foundation::base::{CFIndex, CFTypeID, TCFType, CFType, CFRange};
+use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
+use core_foundation::string::CFString;
+use core_graphics::font::CGGlyph;
+use core_graphics::geometry::CGPoint;
+
+#[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 string_attributes::*;
+ use line::*;
+ use font;
+ 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 {
+ 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..dde1936c48
--- /dev/null
+++ b/third_party/rust/core-text/src/string_attributes.rs
@@ -0,0 +1,19 @@
+use core_foundation::string::CFStringRef;
+
+extern {
+ 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;
+}