Skip to content

Commit c9c1430

Browse files
committed
Use objc2 for determining whether font smoothing is enabled
`objc2` / `objc2-foundation` is much more type-safe than `cocoa`, and automatically ensures that memory management-rules are upheld. See also alacritty/copypasta#74.
1 parent 169fb22 commit c9c1430

File tree

3 files changed

+36
-20
lines changed

3 files changed

+36
-20
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ The sections should follow the order `Added`, `Changed`, `Fixed`, and `Removed`.
66
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## Unreleased
10+
11+
### Changed
12+
13+
- On macOS, use `objc2` when determining whether font smoothing is enabled.
14+
915
## 0.8.0
1016

1117
### Changed

Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ freetype-rs = "0.36.0"
2525
pkg-config = "0.3"
2626

2727
[target.'cfg(target_os = "macos")'.dependencies]
28-
cocoa = "0.25.0"
2928
core-foundation = "0.9.3"
3029
core-text = "20.1.0"
3130
core-graphics = "0.23.1"
3231
core-foundation-sys = "0.8.4"
33-
objc = "0.2.7"
3432
once_cell = "1.12"
33+
objc2 = "0.5.1"
34+
objc2-foundation = { version = "0.2.2", features = [
35+
"NSString",
36+
"NSUserDefaults",
37+
"NSValue",
38+
] }
3539

3640
[target.'cfg(windows)'.dependencies]
3741
dwrote = { version = "0.11" }

src/darwin/mod.rs

+24-18
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
//! Font rendering based on CoreText.
22
33
use std::collections::HashMap;
4-
use std::ffi::c_char;
54
use std::ffi::CStr;
65
use std::iter;
76
use std::path::PathBuf;
87
use std::ptr;
98

10-
use cocoa::base::{id, nil};
11-
use cocoa::foundation::{NSInteger, NSString, NSUserDefaults};
12-
139
use core_foundation::array::{CFArray, CFIndex};
1410
use core_foundation::base::{CFType, ItemRef, TCFType};
1511
use core_foundation::number::{CFNumber, CFNumberRef};
@@ -28,10 +24,10 @@ use core_text::font_descriptor::{
2824
self, kCTFontColorGlyphsTrait, kCTFontDefaultOrientation, kCTFontEnabledAttribute,
2925
CTFontDescriptor, SymbolicTraitAccessors,
3026
};
27+
use objc2::rc::{autoreleasepool, Retained};
28+
use objc2_foundation::{ns_string, NSNumber, NSObject, NSObjectProtocol, NSString, NSUserDefaults};
3129

3230
use log::{trace, warn};
33-
use objc::rc::autoreleasepool;
34-
use objc::{class, msg_send, sel, sel_impl};
3531
use once_cell::sync::Lazy;
3632

3733
pub mod byte_order;
@@ -274,30 +270,40 @@ fn descriptors_for_family(family: &str) -> Vec<Descriptor> {
274270
// other integer, or a missing value (the default), or a value of any other type, as leaving it
275271
// enabled.
276272
static FONT_SMOOTHING_ENABLED: Lazy<bool> = Lazy::new(|| {
277-
autoreleasepool(|| unsafe {
278-
let key = NSString::alloc(nil).init_str("AppleFontSmoothing");
279-
let value: id = msg_send![id::standardUserDefaults(), objectForKey: key];
273+
autoreleasepool(|_| {
274+
let value = unsafe {
275+
NSUserDefaults::standardUserDefaults().objectForKey(ns_string!("AppleFontSmoothing"))
276+
};
277+
let Some(value) = value else {
278+
return true;
279+
};
280280

281-
if msg_send![value, isKindOfClass: class!(NSNumber)] {
282-
let num_type: *const c_char = msg_send![value, objCType];
283-
if num_type.is_null() {
284-
return true;
285-
}
281+
// SAFETY: The values in `NSUserDefaults` are always subclasses of
282+
// `NSObject`.
283+
let value: Retained<NSObject> = unsafe { Retained::cast(value) };
284+
285+
if value.is_kind_of::<NSNumber>() {
286+
// SAFETY: Just checked that the value is a NSNumber
287+
let value: Retained<NSNumber> = unsafe { Retained::cast(value) };
286288

287289
// NSNumber's objCType method returns one of these strings depending on the size:
288290
// q = quad (long long), l = long, i = int, s = short.
289291
// This is done to reject booleans, which are NSNumbers with an objCType of "c", but
290292
// macOS does not treat them the same as an integer 0 or 1 for this setting,
291293
// it just ignores it.
292294
let int_specifiers: [&[u8]; 4] = [b"q", b"l", b"i", b"s"];
293-
if !int_specifiers.contains(&CStr::from_ptr(num_type).to_bytes()) {
295+
296+
let encoding = unsafe { CStr::from_ptr(value.objCType().as_ptr()).to_bytes() };
297+
if !int_specifiers.contains(&encoding) {
294298
return true;
295299
}
296300

297-
let smoothing: NSInteger = msg_send![value, integerValue];
301+
let smoothing = value.integerValue();
298302
smoothing != 0
299-
} else if msg_send![value, isKindOfClass: class!(NSString)] {
300-
let smoothing: NSInteger = msg_send![value, integerValue];
303+
} else if value.is_kind_of::<NSString>() {
304+
// SAFETY: Just checked that the value is a NSString
305+
let value: Retained<NSString> = unsafe { Retained::cast(value) };
306+
let smoothing = unsafe { value.integerValue() };
301307
smoothing != 0
302308
} else {
303309
true

0 commit comments

Comments
 (0)