@@ -52,6 +52,11 @@ pub fn apply_features_and_fallbacks(
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks,
);
+
+ for value in &values {
+ CFRelease(*value as _);
+ }
+
let new_descriptor = CTFontDescriptorCreateWithAttributes(attrs);
CFRelease(attrs as _);
let new_descriptor = CTFontDescriptor::wrap_under_create_rule(new_descriptor);
@@ -110,13 +110,21 @@ impl ScreenCaptureSource for MacScreenCaptureSource {
let _: id = msg_send![configuration, setHeight: meta.resolution.height.0 as i64];
let stream: id = msg_send![stream, initWithFilter:filter configuration:configuration delegate:delegate];
+ // Stream contains filter, configuration, and delegate internally so we release them here
+ // to prevent a memory leak when steam is dropped
+ let _: () = msg_send![filter, release];
+ let _: () = msg_send![configuration, release];
+ let _: () = msg_send![delegate, release];
+
let (mut tx, rx) = oneshot::channel();
let mut error: id = nil;
let _: () = msg_send![stream, addStreamOutput:output type:SCStreamOutputTypeScreen sampleHandlerQueue:0 error:&mut error as *mut id];
if error != nil {
let message: id = msg_send![error, localizedDescription];
- tx.send(Err(anyhow!("failed to add stream output {message:?}")))
+ let _: () = msg_send![stream, release];
+ let _: () = msg_send![output, release];
+ tx.send(Err(anyhow!("failed to add stream output {message:?}")))
.ok();
return rx;
}
@@ -132,8 +140,10 @@ impl ScreenCaptureSource for MacScreenCaptureSource {
};
Ok(Box::new(stream) as Box<dyn ScreenCaptureStream>)
} else {
+ let _: () = msg_send![stream, release];
+ let _: () = msg_send![output, release];
let message: id = msg_send![error, localizedDescription];
- Err(anyhow!("failed to stop screen capture stream {message:?}"))
+ Err(anyhow!("failed to start screen capture stream {message:?}"))
};
if let Some(tx) = tx.borrow_mut().take() {
tx.send(result).ok();
@@ -8,6 +8,7 @@ use anyhow::anyhow;
use cocoa::appkit::CGFloat;
use collections::HashMap;
use core_foundation::{
+ array::{CFArray, CFArrayRef},
attributed_string::CFMutableAttributedString,
base::{CFRange, TCFType},
number::CFNumber,
@@ -21,8 +22,10 @@ use core_graphics::{
};
use core_text::{
font::CTFont,
+ font_collection::CTFontCollectionRef,
font_descriptor::{
- kCTFontSlantTrait, kCTFontSymbolicTrait, kCTFontWeightTrait, kCTFontWidthTrait,
+ CTFontDescriptor, kCTFontSlantTrait, kCTFontSymbolicTrait, kCTFontWeightTrait,
+ kCTFontWidthTrait,
},
line::CTLine,
string_attributes::kCTFontAttributeName,
@@ -97,7 +100,26 @@ impl PlatformTextSystem for MacTextSystem {
fn all_font_names(&self) -> Vec<String> {
let mut names = Vec::new();
let collection = core_text::font_collection::create_for_all_families();
- let Some(descriptors) = collection.get_descriptors() else {
+ // NOTE: We intentionally avoid using `collection.get_descriptors()` here because
+ // it has a memory leak bug in core-text v21.0.0. The upstream code uses
+ // `wrap_under_get_rule` but `CTFontCollectionCreateMatchingFontDescriptors`
+ // follows the Create Rule (caller owns the result), so it should use
+ // `wrap_under_create_rule`. We call the function directly with correct memory management.
+ unsafe extern "C" {
+ fn CTFontCollectionCreateMatchingFontDescriptors(
+ collection: CTFontCollectionRef,
+ ) -> CFArrayRef;
+ }
+ let descriptors: Option<CFArray<CTFontDescriptor>> = unsafe {
+ let array_ref =
+ CTFontCollectionCreateMatchingFontDescriptors(collection.as_concrete_TypeRef());
+ if array_ref.is_null() {
+ None
+ } else {
+ Some(CFArray::wrap_under_create_rule(array_ref))
+ }
+ };
+ let Some(descriptors) = descriptors else {
return names;
};
for descriptor in descriptors.into_iter() {
@@ -1190,6 +1190,7 @@ impl PlatformWindow for MacWindow {
let (done_tx, done_rx) = oneshot::channel();
let done_tx = Cell::new(Some(done_tx));
let block = ConcreteBlock::new(move |answer: NSInteger| {
+ let _: () = msg_send![alert, release];
if let Some(done_tx) = done_tx.take() {
let _ = done_tx.send(answer.try_into().unwrap());
}