diff --git a/CHANGELOG.md b/CHANGELOG.md index efc793c..a9bdea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The sections should follow the order `Added`, `Changed`, `Fixed`, and `Removed`. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- On macOS, use `objc2` when determining whether font smoothing is enabled. + ## 0.8.0 ### Changed diff --git a/Cargo.toml b/Cargo.toml index 1dcf65d..906c583 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,13 +25,17 @@ freetype-rs = "0.36.0" pkg-config = "0.3" [target.'cfg(target_os = "macos")'.dependencies] -cocoa = "0.25.0" core-foundation = "0.9.3" core-text = "20.1.0" core-graphics = "0.23.1" core-foundation-sys = "0.8.4" -objc = "0.2.7" once_cell = "1.12" +objc2 = "0.5.1" +objc2-foundation = { version = "0.2.2", features = [ + "NSString", + "NSUserDefaults", + "NSValue", +] } [target.'cfg(windows)'.dependencies] dwrote = { version = "0.11" } diff --git a/src/darwin/mod.rs b/src/darwin/mod.rs index 669b3ab..641c2cf 100644 --- a/src/darwin/mod.rs +++ b/src/darwin/mod.rs @@ -1,15 +1,11 @@ //! Font rendering based on CoreText. use std::collections::HashMap; -use std::ffi::c_char; use std::ffi::CStr; use std::iter; use std::path::PathBuf; use std::ptr; -use cocoa::base::{id, nil}; -use cocoa::foundation::{NSInteger, NSString, NSUserDefaults}; - use core_foundation::array::{CFArray, CFIndex}; use core_foundation::base::{CFType, ItemRef, TCFType}; use core_foundation::number::{CFNumber, CFNumberRef}; @@ -28,10 +24,10 @@ use core_text::font_descriptor::{ self, kCTFontColorGlyphsTrait, kCTFontDefaultOrientation, kCTFontEnabledAttribute, CTFontDescriptor, SymbolicTraitAccessors, }; +use objc2::rc::{autoreleasepool, Retained}; +use objc2_foundation::{ns_string, NSNumber, NSObject, NSObjectProtocol, NSString, NSUserDefaults}; use log::{trace, warn}; -use objc::rc::autoreleasepool; -use objc::{class, msg_send, sel, sel_impl}; use once_cell::sync::Lazy; pub mod byte_order; @@ -274,15 +270,21 @@ fn descriptors_for_family(family: &str) -> Vec { // other integer, or a missing value (the default), or a value of any other type, as leaving it // enabled. static FONT_SMOOTHING_ENABLED: Lazy = Lazy::new(|| { - autoreleasepool(|| unsafe { - let key = NSString::alloc(nil).init_str("AppleFontSmoothing"); - let value: id = msg_send![id::standardUserDefaults(), objectForKey: key]; + autoreleasepool(|_| { + let value = unsafe { + NSUserDefaults::standardUserDefaults().objectForKey(ns_string!("AppleFontSmoothing")) + }; + let Some(value) = value else { + return true; + }; - if msg_send![value, isKindOfClass: class!(NSNumber)] { - let num_type: *const c_char = msg_send![value, objCType]; - if num_type.is_null() { - return true; - } + // SAFETY: The values in `NSUserDefaults` are always subclasses of + // `NSObject`. + let value: Retained = unsafe { Retained::cast(value) }; + + if value.is_kind_of::() { + // SAFETY: Just checked that the value is a NSNumber + let value: Retained = unsafe { Retained::cast(value) }; // NSNumber's objCType method returns one of these strings depending on the size: // q = quad (long long), l = long, i = int, s = short. @@ -290,14 +292,18 @@ static FONT_SMOOTHING_ENABLED: Lazy = Lazy::new(|| { // macOS does not treat them the same as an integer 0 or 1 for this setting, // it just ignores it. let int_specifiers: [&[u8]; 4] = [b"q", b"l", b"i", b"s"]; - if !int_specifiers.contains(&CStr::from_ptr(num_type).to_bytes()) { + + let encoding = unsafe { CStr::from_ptr(value.objCType().as_ptr()).to_bytes() }; + if !int_specifiers.contains(&encoding) { return true; } - let smoothing: NSInteger = msg_send![value, integerValue]; + let smoothing = value.integerValue(); smoothing != 0 - } else if msg_send![value, isKindOfClass: class!(NSString)] { - let smoothing: NSInteger = msg_send![value, integerValue]; + } else if value.is_kind_of::() { + // SAFETY: Just checked that the value is a NSString + let value: Retained = unsafe { Retained::cast(value) }; + let smoothing = unsafe { value.integerValue() }; smoothing != 0 } else { true