Skip to content

Commit a3c7289

Browse files
madsmtmchrisduerr
authored andcommitted
Use objc2 for macOS font smoothing determination
`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 a3c7289

File tree

6 files changed

+42
-29
lines changed

6 files changed

+42
-29
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
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+
- MSRV changed to 1.71.0
14+
915
## 0.8.0
1016

1117
### Changed

Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ readme = "README.md"
1010
categories = ["gui", "os"]
1111
keywords = ["font"]
1212
edition = "2021"
13-
rust-version = "1.65.0"
13+
rust-version = "1.71.0"
1414

1515
[dependencies]
1616
libc = "0.2"
@@ -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

Lines changed: 26 additions & 18 deletions
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,42 @@ 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+
};
280277

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-
}
278+
let value = match value {
279+
Some(value) => value,
280+
None => return true,
281+
};
282+
283+
// SAFETY: The values in `NSUserDefaults` are always subclasses of
284+
// `NSObject`.
285+
let value: Retained<NSObject> = unsafe { Retained::cast(value) };
286+
287+
if value.is_kind_of::<NSNumber>() {
288+
// SAFETY: Just checked that the value is a NSNumber
289+
let value: Retained<NSNumber> = unsafe { Retained::cast(value) };
286290

287291
// NSNumber's objCType method returns one of these strings depending on the size:
288292
// q = quad (long long), l = long, i = int, s = short.
289293
// This is done to reject booleans, which are NSNumbers with an objCType of "c", but
290294
// macOS does not treat them the same as an integer 0 or 1 for this setting,
291295
// it just ignores it.
292296
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()) {
297+
298+
let encoding = unsafe { CStr::from_ptr(value.objCType().as_ptr()).to_bytes() };
299+
if !int_specifiers.contains(&encoding) {
294300
return true;
295301
}
296302

297-
let smoothing: NSInteger = msg_send![value, integerValue];
303+
let smoothing = value.integerValue();
298304
smoothing != 0
299-
} else if msg_send![value, isKindOfClass: class!(NSString)] {
300-
let smoothing: NSInteger = msg_send![value, integerValue];
305+
} else if value.is_kind_of::<NSString>() {
306+
// SAFETY: Just checked that the value is a NSString
307+
let value: Retained<NSString> = unsafe { Retained::cast(value) };
308+
let smoothing = unsafe { value.integerValue() };
301309
smoothing != 0
302310
} else {
303311
true

src/ft/fc/char_set.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl CharSetRef {
3838
}
3939

4040
pub fn count(&self) -> u32 {
41-
unsafe { FcCharSetCount(self.as_ptr()) as u32 }
41+
unsafe { FcCharSetCount(self.as_ptr()) }
4242
}
4343

4444
pub fn union(&self, other: &CharSetRef) -> CharSet {

src/ft/fc/pattern.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::ffi::{CStr, CString};
22
use std::fmt;
3-
use std::mem;
43
use std::path::PathBuf;
54
use std::ptr::{self, NonNull};
65
use std::str;
@@ -45,11 +44,7 @@ impl<'a> StringPropertyIter<'a> {
4544
};
4645

4746
if result == FcResultMatch {
48-
// Transmute here is to extend lifetime of the str to that of the iterator.
49-
//
50-
// Potential unsafety? What happens if the pattern is modified while this ptr is
51-
// borrowed out?
52-
unsafe { mem::transmute(CStr::from_ptr(value as *const c_char).to_str().ok()?) }
47+
unsafe { CStr::from_ptr(value as *const c_char).to_str().ok() }
5348
} else {
5449
None
5550
}

src/ft/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ impl FreeTypeLoader {
693693
font_key: FontKey,
694694
) -> Result<Option<FontKey>, Error> {
695695
if let Some(ft_face_location) = pattern.ft_face_location(0) {
696-
if self.faces.get(&font_key).is_some() {
696+
if self.faces.contains_key(&font_key) {
697697
return Ok(Some(font_key));
698698
}
699699

0 commit comments

Comments
 (0)