Bug 1743852 - Use core-text upstream variation support. r=jfkthame

This let us get rid of most of the unsafe. It also includes an update of
core-graphics for the copy_variation_axes() api

Differential Revision: https://phabricator.services.mozilla.com/D132600
This commit is contained in:
Jeff Muizelaar 2021-12-01 17:59:15 +00:00
parent 3d64c3bcca
commit 63ef72803c
11 changed files with 294 additions and 173 deletions

5
Cargo.lock generated
View File

@ -724,9 +724,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "core-graphics"
version = "0.22.2"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"core-foundation",
@ -5570,7 +5570,6 @@ dependencies = [
"dwrote",
"etagere",
"euclid",
"foreign-types",
"freetype",
"fxhash",
"gleam",

17
gfx/wr/Cargo.lock generated
View File

@ -343,9 +343,9 @@ dependencies = [
[[package]]
name = "core-graphics"
version = "0.22.0"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6082396a349fa49674ba1bda4077332a18bf150e8fa75745ece07085e29a113"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"core-foundation 0.9.2",
@ -368,12 +368,12 @@ dependencies = [
[[package]]
name = "core-text"
version = "19.0.0"
version = "19.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04dfae50af11e72657fe7174cddb1ecddc5398037f7f6f39533ad69207c9a4e2"
checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
dependencies = [
"core-foundation 0.9.2",
"core-graphics 0.22.0",
"core-graphics 0.22.3",
"foreign-types",
"libc",
]
@ -1664,13 +1664,12 @@ dependencies = [
"build-parallel",
"byteorder",
"core-foundation 0.9.2",
"core-graphics 0.22.0",
"core-graphics 0.22.3",
"core-text",
"derive_more",
"dwrote",
"etagere",
"euclid",
"foreign-types",
"freetype",
"fxhash",
"gleam 0.13.1",
@ -1721,7 +1720,7 @@ dependencies = [
"bitflags",
"byteorder",
"core-foundation 0.9.2",
"core-graphics 0.22.0",
"core-graphics 0.22.3",
"crossbeam-channel",
"derive_more",
"euclid",
@ -1823,7 +1822,7 @@ dependencies = [
"chrono",
"clap",
"core-foundation 0.9.2",
"core-graphics 0.22.0",
"core-graphics 0.22.3",
"crossbeam",
"dwrote",
"env_logger",

View File

@ -66,7 +66,6 @@ dwrote = "0.11"
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.9.2"
core-graphics = "0.22"
core-text = { version = "19", default-features = false }
core-graphics = "0.22.3"
core-text = { version = "19.2", default-features = false }
objc = "0.2"
foreign-types = "0.3.0"

View File

@ -71,8 +71,6 @@ extern crate tracy_rs;
extern crate derive_more;
extern crate malloc_size_of;
extern crate svg_fmt;
#[cfg(target_os = "macos")]
extern crate foreign_types;
#[macro_use]
mod profiler;

View File

@ -4,10 +4,10 @@
use api::{ColorF, ColorU, FontKey, FontRenderMode, FontSize, GlyphDimensions};
use api::{FontInstanceFlags, FontVariation, NativeFontHandle};
use core_foundation::{array::{CFArray, CFArrayRef}, data::CFData};
use core_foundation::base::TCFType;
use core_foundation::data::CFData;
use core_foundation::base::{CFType, TCFType};
use core_foundation::dictionary::CFDictionary;
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::number::{CFNumber};
use core_foundation::string::{CFString, CFStringRef};
use core_graphics::base::{kCGImageAlphaNoneSkipFirst, kCGImageAlphaPremultipliedFirst};
use core_graphics::base::{kCGBitmapByteOrder32Little};
@ -17,9 +17,10 @@ use core_graphics::context::{CGBlendMode, CGTextDrawingMode};
use core_graphics::font::{CGFont, CGGlyph};
use core_graphics::geometry::{CGAffineTransform, CGPoint, CGSize};
use core_graphics::geometry::{CG_AFFINE_TRANSFORM_IDENTITY, CGRect};
use core_text::{self, font_descriptor::CTFontDescriptorCreateCopyWithAttributes};
use core_text::font::{CTFont, CTFontRef};
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef, kCTFontDefaultOrientation};
use core_text;
use core_text::font::CTFont;
use core_text::font_descriptor::{CTFontDescriptor, kCTFontDefaultOrientation};
use core_text::font_manager;
use euclid::default::Size2D;
use crate::gamma_lut::{ColorLut, GammaLut};
use crate::glyph_rasterizer::{FontInstance, FontTransform, GlyphKey};
@ -27,13 +28,9 @@ use crate::glyph_rasterizer::{GlyphFormat, GlyphRasterError, GlyphRasterResult,
use crate::internal_types::{FastHashMap, ResourceCacheError};
use std::collections::hash_map::Entry;
use std::sync::Arc;
use foreign_types::ForeignType;
const INITIAL_CG_CONTEXT_SIDE_LENGTH: u32 = 32;
// Needed for calling CGFontCopyVariationAxes manually.
type CGFontRef = *mut <CGFont as ForeignType>::CType;
// We prefer to create CTFonts from a CTFontDescriptor, but that doesn't work in the case
// of hidden system fonts on recent macOS versions, so for those we will instead use a
// native CGFont as the basis.
@ -225,37 +222,29 @@ extern {
static kCTFontVariationAttribute: CFStringRef;
static kCGFontVariationAxisName: CFStringRef;
fn CTFontCopyVariationAxes(font: CTFontRef) -> CFArrayRef;
fn CGFontCopyVariationAxes(font: CGFontRef) -> CFArrayRef;
}
fn get_tag_from_axis(axis: &CFDictionary, key: CFStringRef) -> Option<i64> {
if let Some(number_ptr) = axis.find(key as *const _) {
let number: CFNumber = unsafe { TCFType::wrap_under_get_rule(*number_ptr as CFNumberRef) };
if number.instance_of::<CFNumber>() {
fn get_tag_from_axis(axis: &CFDictionary<CFString, CFType>, key: CFStringRef) -> Option<i64> {
if let Some(number) = axis.find(key as *const _) {
if let Some(number) = number.downcast::<CFNumber>() {
return number.to_i64();
}
}
None
}
fn get_value_from_axis(axis: &CFDictionary, key: CFStringRef) -> Option<f64> {
if let Some(number_ptr) = axis.find(key as *const _) {
let number: CFNumber = unsafe { TCFType::wrap_under_get_rule(*number_ptr as CFNumberRef) };
if number.instance_of::<CFNumber>() {
fn get_value_from_axis(axis: &CFDictionary<CFString, CFType>, key: CFStringRef) -> Option<f64> {
if let Some(number) = axis.find(key as *const _) {
if let Some(number) = number.downcast::<CFNumber>() {
return number.to_f64();
}
}
None
}
fn get_name_from_axis(axis: &CFDictionary, key: CFStringRef) -> Option<CFString> {
if let Some(name_ptr) = axis.find(key as *const _) {
let name: CFString = unsafe { TCFType::wrap_under_get_rule(*name_ptr as CFStringRef) };
if name.instance_of::<CFString>() {
return Some(name);
}
fn get_name_from_axis(axis: &CFDictionary<CFString, CFType>, key: CFStringRef) -> Option<CFString> {
if let Some(name) = axis.find(key as *const _) {
return name.downcast::<CFString>();
}
None
}
@ -266,59 +255,53 @@ fn new_ct_font_with_variations_from_ct_font_desc(ct_font_desc: &CTFontDescriptor
return ct_font;
}
let mut vals: Vec<(CFNumber, CFNumber)> = Vec::with_capacity(variations.len() as usize);
let axes = match ct_font.get_variation_axes() {
Some(axes) => axes,
None => return ct_font,
};
unsafe {
let axes_ref = CTFontCopyVariationAxes(ct_font.as_concrete_TypeRef());
if axes_ref.is_null() {
for axis in axes.iter() {
let tag = if let Some(tag) = get_tag_from_axis(&axis, unsafe { kCTFontVariationAxisIdentifierKey }) {
tag
} else {
return ct_font;
}
let axes: CFArray<CFDictionary> = TCFType::wrap_under_create_rule(axes_ref);
};
for axis in axes.iter() {
if !axis.instance_of::<CFDictionary>() {
return ct_font;
}
let mut val = match variations.iter().find(|variation| (variation.tag as i64) == tag) {
Some(variation) => variation.value as f64,
None => continue,
};
let tag = if let Some(tag) = get_tag_from_axis(&axis, kCTFontVariationAxisIdentifierKey) {
tag
} else {
return ct_font;
};
let mut val = match variations.iter().find(|variation| (variation.tag as i64) == tag) {
Some(variation) => variation.value as f64,
None => continue,
};
let min_val = if let Some(num) = get_value_from_axis(&axis, kCTFontVariationAxisMinimumValueKey) {
num
} else {
return ct_font;
};
let max_val = if let Some(num) = get_value_from_axis(&axis, kCTFontVariationAxisMaximumValueKey) {
num
} else {
return ct_font;
};
let def_val = if let Some(num) = get_value_from_axis(&axis, kCTFontVariationAxisDefaultValueKey) {
num
} else {
return ct_font;
};
val = val.max(min_val).min(max_val);
if val != def_val {
vals.push((CFNumber::from(tag), CFNumber::from(val)));
}
}
if vals.is_empty() {
let min_val = if let Some(num) = get_value_from_axis(&axis, unsafe { kCTFontVariationAxisMinimumValueKey }) {
num
} else {
return ct_font;
};
let max_val = if let Some(num) = get_value_from_axis(&axis, unsafe { kCTFontVariationAxisMaximumValueKey }) {
num
} else {
return ct_font;
};
let def_val = if let Some(num) = get_value_from_axis(&axis, unsafe { kCTFontVariationAxisDefaultValueKey }) {
num
} else {
return ct_font;
};
val = val.max(min_val).min(max_val);
if val != def_val {
vals.push((CFNumber::from(tag), CFNumber::from(val)));
}
let vals_dict = CFDictionary::from_CFType_pairs(&vals);
let attrs_dict = CFDictionary::from_CFType_pairs(&[(CFString::wrap_under_get_rule(kCTFontVariationAttribute), vals_dict)]);
let ct_var_font_desc = create_copy_with_attributes(ct_font_desc, attrs_dict.to_untyped()).unwrap();
core_text::font::new_from_descriptor(&ct_var_font_desc, size)
}
if vals.is_empty() {
return ct_font;
}
let vals_dict = CFDictionary::from_CFType_pairs(&vals);
let variation_attribute = unsafe { CFString::wrap_under_get_rule(kCTFontVariationAttribute) };
let attrs_dict = CFDictionary::from_CFType_pairs(&[(variation_attribute, vals_dict)]);
let ct_var_font_desc = ct_font_desc.create_copy_with_attributes(attrs_dict.to_untyped()).unwrap();
core_text::font::new_from_descriptor(&ct_var_font_desc, size)
}
fn new_ct_font_with_variations_from_cg_font(cg_font: &CGFont, size: f64, variations: &[FontVariation]) -> CTFont {
@ -328,64 +311,58 @@ fn new_ct_font_with_variations_from_cg_font(cg_font: &CGFont, size: f64, variati
}
let mut vals: Vec<(CFString, CFNumber)> = Vec::with_capacity(variations.len() as usize);
unsafe {
let ct_axes_ref = CTFontCopyVariationAxes(ct_font.as_concrete_TypeRef());
if ct_axes_ref.is_null() {
let ct_axes = match ct_font.get_variation_axes() {
Some(ct_axes) => ct_axes,
None => return ct_font,
};
let cg_axes = match cg_font.copy_variation_axes() {
Some(cg_axes) => cg_axes,
None => return ct_font,
};
if ct_axes.len() != cg_axes.len() {
return ct_font;
}
for (ct_axis, cg_axis) in ct_axes.iter().zip(cg_axes.iter()) {
if !ct_axis.instance_of::<CFDictionary>() {
return ct_font;
}
let ct_axes: CFArray<CFDictionary> = TCFType::wrap_under_create_rule(ct_axes_ref);
let cg_axes_ref = CGFontCopyVariationAxes(cg_font.as_ptr());
if cg_axes_ref.is_null() {
let tag = if let Some(tag) = get_tag_from_axis(&ct_axis, unsafe { kCTFontVariationAxisIdentifierKey }) {
tag
} else {
return ct_font;
}
let cg_axes: CFArray<CFDictionary> = TCFType::wrap_under_create_rule(cg_axes_ref);
};
if ct_axes.len() != cg_axes.len() {
let mut val = match variations.iter().find(|variation| (variation.tag as i64) == tag) {
Some(variation) => variation.value as f64,
None => continue,
};
let name = if let Some(name) = get_name_from_axis(&cg_axis, unsafe { kCGFontVariationAxisName }) {
name
} else {
return ct_font;
}
for (ct_axis, cg_axis) in ct_axes.iter().zip(cg_axes.iter()) {
if !ct_axis.instance_of::<CFDictionary>() {
return ct_font;
}
};
let tag = if let Some(tag) = get_tag_from_axis(&ct_axis, kCTFontVariationAxisIdentifierKey) {
tag
} else {
return ct_font;
};
let min_val = if let Some(num) = get_value_from_axis(&ct_axis, unsafe { kCTFontVariationAxisMinimumValueKey }) {
num
} else {
return ct_font;
};
let max_val = if let Some(num) = get_value_from_axis(&ct_axis, unsafe { kCTFontVariationAxisMaximumValueKey }) {
num
} else {
return ct_font;
};
let def_val = if let Some(num) = get_value_from_axis(&ct_axis, unsafe { kCTFontVariationAxisDefaultValueKey }) {
num
} else {
return ct_font;
};
let mut val = match variations.iter().find(|variation| (variation.tag as i64) == tag) {
Some(variation) => variation.value as f64,
None => continue,
};
let name = if let Some(name) = get_name_from_axis(&cg_axis, kCGFontVariationAxisName) {
name
} else {
return ct_font;
};
let min_val = if let Some(num) = get_value_from_axis(&ct_axis, kCTFontVariationAxisMinimumValueKey) {
num
} else {
return ct_font;
};
let max_val = if let Some(num) = get_value_from_axis(&ct_axis, kCTFontVariationAxisMaximumValueKey) {
num
} else {
return ct_font;
};
let def_val = if let Some(num) = get_value_from_axis(&ct_axis, kCTFontVariationAxisDefaultValueKey) {
num
} else {
return ct_font;
};
val = val.max(min_val).min(max_val);
if val != def_val {
vals.push((name, CFNumber::from(val)));
}
val = val.max(min_val).min(max_val);
if val != def_val {
vals.push((name, CFNumber::from(val)));
}
}
if vals.is_empty() {
@ -436,7 +413,7 @@ impl FontContext {
assert_eq!(index, 0);
let data = CFData::from_arc(bytes);
let ct_font_desc = match create_font_descriptor(data) {
let ct_font_desc = match font_manager::create_font_descriptor_with_data(data) {
Err(_) => return,
Ok(desc) => desc,
};
@ -1048,26 +1025,3 @@ enum GlyphType {
Bitmap,
}
fn create_font_descriptor(cf_data: CFData) -> Result<CTFontDescriptor, ()> {
use core_foundation::data::CFDataRef;
extern {
pub fn CTFontManagerCreateFontDescriptorFromData(data: CFDataRef) -> CTFontDescriptorRef;
}
unsafe {
let ct_font_descriptor_ref = CTFontManagerCreateFontDescriptorFromData(cf_data.as_concrete_TypeRef());
if ct_font_descriptor_ref.is_null() {
return Err(());
}
Ok(CTFontDescriptor::wrap_under_create_rule(ct_font_descriptor_ref))
}
}
fn create_copy_with_attributes(desc: &CTFontDescriptor, attr: CFDictionary) -> Result<CTFontDescriptor, ()> {
unsafe {
let ct_font_descriptor_ref = CTFontDescriptorCreateCopyWithAttributes(desc.as_concrete_TypeRef(), attr.as_concrete_TypeRef());
if ct_font_descriptor_ref.is_null() {
return Err(());
}
Ok(CTFontDescriptor::wrap_under_create_rule(ct_font_descriptor_ref))
}
}

View File

@ -1 +1 @@
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"4f4c058a2b1b415d2b94911d133a72e9046b0dc397ccb6bcdc07d8633557fe2d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"6745c3c38183d2eda9b1fa265fb0a95018db5c110cbabc00b32327d951bbe2ea","src/base.rs":"838683ff67253f4aff1d4b4177531210ca73d4e61f05c5d96a8f196b2a88c787","src/color.rs":"4c8ec4ab828cbc1b2a1538a34a51f5b380927f2f1daf187dff6f732f57a43656","src/color_space.rs":"b3d7ee8a21703c789160867cb8eb2188bd1daa193e3d030f21adb6f1a6f872de","src/context.rs":"8bda7f9ecb5be768b09a29cc3b0a4f329f55d2a2ab74030d121610283862d833","src/data_provider.rs":"b25201fdea43ea1a019c68aa5e997725d04d0824a238354ddc9f2dd8a6835cc4","src/display.rs":"cc691712c3d27342ae97f04df6032d6f682570239ba51936fcc796c61bf08c8b","src/event.rs":"84d6035ab155e702be056f4f37d0cbb76ccfa8fb9277fcbfb42c7953d0cd3937","src/event_source.rs":"d55a4f5b5e62789325028febc51bbf54c74b15ab1a4e70c6ad749a2f9753e081","src/font.rs":"cfff63d8f07d8fe497fdef258163c1bf7b3755b845fffb8e3c99a5cb45986fc8","src/geometry.rs":"8e12dc89835406bfa514de8fb58f5fd435724d1ddb97dc3a70392efbcf1c42ed","src/gradient.rs":"8ee8661706f36914d08e903840c4f07414b38ba40ea4a482d34b900ac6ac7cf9","src/image.rs":"a5a5df8c0f310455f038eeb16688015f481688cb417f8e8f424a4c1d2a1cdd57","src/lib.rs":"78264571227db6fc9194cb90d64beaff1738a501f88b5da55eb17ae42592d26f","src/path.rs":"c429afeaed999b02ac00f89a867b5fc64f1e223039079a4e0529306b734ff117","src/private.rs":"da3fd61338bab2d8e26aa5433b2e18ecd2a0a408c62e1ac2b33a0f87f2dad88a","src/sys.rs":"72cd460e499734a9394a8ec57dcb30ea0a15717452ff9fb343f22effa5d6d308","src/window.rs":"2f6c3dc958ae2c0c9e2fc5033300b96e60ed0abee9823ea1f03797d64df0911a"},"package":"269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86"}
{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"453b079ac8a6df8842e7e8a37222318c500f68e1605db7adbdf87337830df593","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"6745c3c38183d2eda9b1fa265fb0a95018db5c110cbabc00b32327d951bbe2ea","src/base.rs":"838683ff67253f4aff1d4b4177531210ca73d4e61f05c5d96a8f196b2a88c787","src/color.rs":"4c8ec4ab828cbc1b2a1538a34a51f5b380927f2f1daf187dff6f732f57a43656","src/color_space.rs":"b3d7ee8a21703c789160867cb8eb2188bd1daa193e3d030f21adb6f1a6f872de","src/context.rs":"8bda7f9ecb5be768b09a29cc3b0a4f329f55d2a2ab74030d121610283862d833","src/data_provider.rs":"b25201fdea43ea1a019c68aa5e997725d04d0824a238354ddc9f2dd8a6835cc4","src/display.rs":"9db5e5440fd302849b13b48393cab4db95447df8d5057c4534a9d8be948ca480","src/event.rs":"17c601ca0b8a0d806fc576cc6cee63a784deaf4246793cf6ce3abcb562de15c5","src/event_source.rs":"d55a4f5b5e62789325028febc51bbf54c74b15ab1a4e70c6ad749a2f9753e081","src/font.rs":"2a7ac5024f17550dd2b6eb97f6971559f930c163eac3a6625d6d55703fd5e96e","src/geometry.rs":"8e12dc89835406bfa514de8fb58f5fd435724d1ddb97dc3a70392efbcf1c42ed","src/gradient.rs":"8ee8661706f36914d08e903840c4f07414b38ba40ea4a482d34b900ac6ac7cf9","src/image.rs":"a5a5df8c0f310455f038eeb16688015f481688cb417f8e8f424a4c1d2a1cdd57","src/lib.rs":"78264571227db6fc9194cb90d64beaff1738a501f88b5da55eb17ae42592d26f","src/path.rs":"c429afeaed999b02ac00f89a867b5fc64f1e223039079a4e0529306b734ff117","src/private.rs":"da3fd61338bab2d8e26aa5433b2e18ecd2a0a408c62e1ac2b33a0f87f2dad88a","src/sys.rs":"3077395beb77193530b713aa681cb61f7b86fa79e4e4060133b6d61cf9f47e09","src/window.rs":"2f6c3dc958ae2c0c9e2fc5033300b96e60ed0abee9823ea1f03797d64df0911a"},"package":"2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"}

View File

@ -12,7 +12,7 @@
[package]
name = "core-graphics"
version = "0.22.2"
version = "0.22.3"
authors = ["The Servo Project Developers"]
description = "Bindings to Core Graphics for macOS"
homepage = "https://github.com/servo/core-graphics-rs"

View File

@ -608,6 +608,10 @@ impl CGDisplayMode {
0
}
}
pub fn mode_id(&self) -> i32 {
unsafe { CGDisplayModeGetIODisplayModeID(self.as_ptr()) }
}
}
#[link(name = "CoreGraphics", kind = "framework")]
@ -686,6 +690,7 @@ extern "C" {
pub fn CGDisplayModeGetRefreshRate(mode: ::sys::CGDisplayModeRef) -> libc::c_double;
pub fn CGDisplayModeGetIOFlags(mode: ::sys::CGDisplayModeRef) -> u32;
pub fn CGDisplayModeCopyPixelEncoding(mode: ::sys::CGDisplayModeRef) -> CFStringRef;
pub fn CGDisplayModeGetIODisplayModeID(mode: ::sys::CGDisplayModeRef) -> i32;
pub fn CGDisplayCopyAllDisplayModes(
display: CGDirectDisplayID,

View File

@ -1,12 +1,13 @@
#![allow(non_upper_case_globals)]
use core_foundation::base::{CFRelease, CFRetain, CFTypeID};
use geometry::CGPoint;
use core_foundation::{
base::{CFRelease, CFRetain, CFTypeID, TCFType},
mach_port::{CFMachPort, CFMachPortRef},
};
use event_source::CGEventSource;
use libc;
use foreign_types::ForeignType;
use geometry::CGPoint;
use libc::c_void;
use std::mem::ManuallyDrop;
pub type CGEventField = u32;
pub type CGKeyCode = u16;
@ -384,6 +385,137 @@ pub enum CGEventTapLocation {
AnnotatedSession,
}
// The next three enums are taken from:
// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/ef9fe35d5691b6dd383c8c46d867a499817a01b6/MacOSX10.15.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGEventTypes.h)
/* Constants that specify where a new event tap is inserted into the list of
active event taps. */
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapPlacement {
HeadInsertEventTap = 0,
TailAppendEventTap,
}
/* Constants that specify whether a new event tap is an active filter or a
passive listener. */
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapOptions {
Default = 0x00000000,
ListenOnly = 0x00000001,
}
pub type CGEventMask = u64;
/* Generate an event mask for a single type of event. */
macro_rules! CGEventMaskBit {
($eventType:expr) => {
1 << $eventType as CGEventMask
};
}
pub type CGEventTapProxy = *const c_void;
pub type CGEventTapCallBackFn<'tap_life> =
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>;
type CGEventTapCallBackInternal = unsafe extern "C" fn(
proxy: CGEventTapProxy,
etype: CGEventType,
event: ::sys::CGEventRef,
user_info: *const c_void,
) -> ::sys::CGEventRef;
#[no_mangle]
unsafe extern "C" fn cg_event_tap_callback_internal(
_proxy: CGEventTapProxy,
_etype: CGEventType,
_event: ::sys::CGEventRef,
_user_info: *const c_void,
) -> ::sys::CGEventRef {
let callback = _user_info as *mut CGEventTapCallBackFn;
let event = CGEvent::from_ptr(_event);
let new_event = (*callback)(_proxy, _etype, &event);
let event = match new_event {
Some(new_event) => new_event,
None => event,
};
ManuallyDrop::new(event).as_ptr()
}
/// ```no_run
///extern crate core_foundation;
///use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
///use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
///let current = CFRunLoop::get_current();
///match CGEventTap::new(
/// CGEventTapLocation::HID,
/// CGEventTapPlacement::HeadInsertEventTap,
/// CGEventTapOptions::Default,
/// vec![CGEventType::MouseMoved],
/// |_a, _b, d| {
/// println!("{:?}", d.location());
/// None
/// },
/// ) {
/// Ok(tap) => unsafe {
/// let loop_source = tap
/// .mach_port
/// .create_runloop_source(0)
/// .expect("Somethings is bad ");
/// current.add_source(&loop_source, kCFRunLoopCommonModes);
/// tap.enable();
/// CFRunLoop::run_current();
/// },
/// Err(_) => (assert!(false)),
/// }
/// ```
pub struct CGEventTap<'tap_life> {
pub mach_port: CFMachPort,
pub callback_ref:
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>,
}
impl<'tap_life> CGEventTap<'tap_life> {
pub fn new<F: Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>(
tap: CGEventTapLocation,
place: CGEventTapPlacement,
options: CGEventTapOptions,
events_of_interest: std::vec::Vec<CGEventType>,
callback: F,
) -> Result<CGEventTap<'tap_life>, ()> {
let event_mask: CGEventMask = events_of_interest
.iter()
.fold(CGEventType::Null as CGEventMask, |mask, &etype| {
mask | CGEventMaskBit!(etype)
});
let cb = Box::new(Box::new(callback) as CGEventTapCallBackFn);
let cbr = Box::into_raw(cb);
unsafe {
let event_tap_ref = CGEventTapCreate(
tap,
place,
options,
event_mask,
cg_event_tap_callback_internal,
cbr as *const c_void,
);
if !event_tap_ref.is_null() {
Ok(Self {
mach_port: (CFMachPort::wrap_under_create_rule(event_tap_ref)),
callback_ref: Box::from_raw(cbr),
})
} else {
Box::from_raw(cbr);
Err(())
}
}
}
pub fn enable(&self) {
unsafe { CGEventTapEnable(self.mach_port.as_concrete_TypeRef(), true) }
}
}
foreign_type! {
#[doc(hidden)]
type CType = ::sys::CGEvent;
@ -666,4 +798,17 @@ extern {
/// fixed point number or integer, the value parameter is scaled as needed
/// and converted to the appropriate type.
fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64);
// ::sys::CGEventTapRef is actually an CFMachPortRef
fn CGEventTapCreate(
tap: CGEventTapLocation,
place: CGEventTapPlacement,
options: CGEventTapOptions,
eventsOfInterest: CGEventMask,
callback: CGEventTapCallBackInternal,
userInfo: *const c_void,
) -> CFMachPortRef;
fn CGEventTapEnable(tap: CFMachPortRef, enable: bool);
}

View File

@ -7,7 +7,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType};
use core_foundation::base::{CFRelease, CFRetain, CFType, CFTypeID, TCFType};
use core_foundation::array::{CFArray, CFArrayRef};
use core_foundation::data::{CFData, CFDataRef};
use core_foundation::number::CFNumber;
@ -122,6 +122,24 @@ impl CGFont {
None
}
}
pub fn copy_variations(&self) -> Option<CFDictionary<CFString, CFNumber>> {
let variations = unsafe { CGFontCopyVariations(self.as_ptr()) };
if !variations.is_null() {
Some(unsafe { TCFType::wrap_under_create_rule(variations) })
} else {
None
}
}
pub fn copy_variation_axes(&self) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
let axes = unsafe { CGFontCopyVariationAxes(self.as_ptr()) };
if !axes.is_null() {
Some(unsafe { TCFType::wrap_under_create_rule(axes) })
} else {
None
}
}
}
#[link(name = "CoreGraphics", kind = "framework")]
@ -153,4 +171,6 @@ extern {
fn CGFontCopyTableTags(font: ::sys::CGFontRef) -> CFArrayRef;
fn CGFontCopyTableForTag(font: ::sys::CGFontRef, tag: u32) -> CFDataRef;
fn CGFontCopyVariations(font: ::sys::CGFontRef) -> CFDictionaryRef;
fn CGFontCopyVariationAxes(font: ::sys::CGFontRef) -> CFArrayRef;
}

View File

@ -28,6 +28,8 @@ pub type CGGradientRef = *mut CGGradient;
#[cfg(target_os = "macos")]
mod macos {
pub enum CGEventTap {}
pub type CGEventTapRef = core_foundation::mach_port::CFMachPortRef;
pub enum CGEvent {}
pub type CGEventRef = *mut CGEvent;