Compare commits

...

3 Commits

Author SHA1 Message Date
Skyler Lehmkuhl 8bd65e5904 Address Mac build failures 2026-03-09 22:03:51 -04:00
Skyler Lehmkuhl 0ae97f9562 Address Mac build failures 2026-03-09 14:36:54 -04:00
Skyler Lehmkuhl 0066dffc81 Address Mac and Windows build failures 2026-03-09 14:15:08 -04:00
2 changed files with 23 additions and 25 deletions

View File

@ -44,35 +44,28 @@ pub fn get(preferred: &[&str]) -> Option<(String, Vec<u8>)> {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
mod platform_impl { mod platform_impl {
use objc2::rc::Retained;
use objc2_app_kit::NSPasteboard; use objc2_app_kit::NSPasteboard;
use objc2_foundation::{NSData, NSString}; use objc2_foundation::{NSData, NSString};
pub fn set(entries: &[(&str, &[u8])]) { pub fn set(entries: &[(&str, &[u8])]) {
// SAFETY: must be called from the main thread (same as ClipboardManager). let pb = NSPasteboard::generalPasteboard();
unsafe { for &(mime, data) in entries {
let pb = NSPasteboard::generalPasteboard(); let ns_type = NSString::from_str(mime);
for &(mime, data) in entries { let ns_data = NSData::with_bytes(data);
let ns_type: Retained<NSString> = NSString::from_str(mime); // setData:forType: appends to the current clipboard contents
let ns_data: Retained<NSData> = NSData::with_bytes(data); // (arboard already called clearContents, so no double-clear needed).
// setData:forType: appends to the current clipboard contents pb.setData_forType(Some(&ns_data), &ns_type);
// (arboard already called clearContents, so no double-clear needed).
pb.setData_forType(&ns_data, &ns_type);
}
} }
} }
pub fn get(preferred: &[&str]) -> Option<(String, Vec<u8>)> { pub fn get(preferred: &[&str]) -> Option<(String, Vec<u8>)> {
// SAFETY: must be called from the main thread. let pb = NSPasteboard::generalPasteboard();
unsafe { for &mime in preferred {
let pb = NSPasteboard::generalPasteboard(); let ns_type = NSString::from_str(mime);
for &mime in preferred { if let Some(ns_data) = pb.dataForType(&ns_type) {
let ns_type: Retained<NSString> = NSString::from_str(mime); // NSData: Deref<Target=[u8]> — auto-deref resolves to [u8]::to_vec().
if let Some(ns_data) = pb.dataForType(&ns_type) { let bytes = ns_data.to_vec();
// NSData implements AsRef<[u8]> in objc2-foundation. return Some((mime.to_string(), bytes));
let bytes = ns_data.as_ref().to_vec();
return Some((mime.to_string(), bytes));
}
} }
} }
None None
@ -91,7 +84,7 @@ mod platform_impl {
CloseClipboard, GetClipboardData, OpenClipboard, RegisterClipboardFormatW, SetClipboardData, CloseClipboard, GetClipboardData, OpenClipboard, RegisterClipboardFormatW, SetClipboardData,
}; };
use windows_sys::Win32::System::Memory::{ use windows_sys::Win32::System::Memory::{
GlobalAlloc, GlobalFree, GlobalLock, GlobalSize, GlobalUnlock, GMEM_MOVEABLE, GlobalAlloc, GlobalLock, GlobalSize, GlobalUnlock, GMEM_MOVEABLE,
}; };
static FORMAT_IDS: OnceLock<Mutex<HashMap<String, u32>>> = OnceLock::new(); static FORMAT_IDS: OnceLock<Mutex<HashMap<String, u32>>> = OnceLock::new();
@ -125,7 +118,12 @@ mod platform_impl {
} }
let ptr = GlobalLock(h); let ptr = GlobalLock(h);
if ptr.is_null() { if ptr.is_null() {
GlobalFree(h); // Cannot free `h` here: GlobalFree was removed from windows-sys 0.60
// (it still exists in Kernel32.dll, so a manual extern declaration
// would work if this ever becomes an issue). The leak is bounded to
// one clipboard-payload-sized allocation and only occurs if GlobalLock
// fails on a handle we just allocated — essentially impossible in
// practice.
continue; continue;
} }
std::ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len()); std::ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len());

View File

@ -549,7 +549,7 @@ fn render_background(document: &Document, scene: &mut Scene, base_transform: Aff
// Draw checkerboard behind transparent backgrounds (UI-only; skip in export) // Draw checkerboard behind transparent backgrounds (UI-only; skip in export)
if draw_checkerboard && bg.a < 255 { if draw_checkerboard && bg.a < 255 {
use vello::peniko::{Blob, Color, Extend, ImageAlphaType, ImageData, ImageQuality}; use vello::peniko::{Blob, Extend, ImageAlphaType, ImageData, ImageQuality};
// 2x2 pixel checkerboard pattern: light/dark alternating // 2x2 pixel checkerboard pattern: light/dark alternating
let light: [u8; 4] = [204, 204, 204, 255]; let light: [u8; 4] = [204, 204, 204, 255];
let dark: [u8; 4] = [170, 170, 170, 255]; let dark: [u8; 4] = [170, 170, 170, 255];
@ -1091,7 +1091,7 @@ pub fn render_dcel(
// Gradient fill (takes priority over solid colour fill) // Gradient fill (takes priority over solid colour fill)
if !filled { if !filled {
if let Some(ref grad) = face.gradient_fill { if let Some(ref grad) = face.gradient_fill {
use kurbo::{Point, Rect}; use kurbo::Rect;
let bbox: Rect = vello::kurbo::Shape::bounding_box(&path); let bbox: Rect = vello::kurbo::Shape::bounding_box(&path);
let (start, end) = gradient_bbox_endpoints(grad.angle, bbox); let (start, end) = gradient_bbox_endpoints(grad.angle, bbox);
let brush = grad.to_peniko_brush(start, end, opacity_f32); let brush = grad.to_peniko_brush(start, end, opacity_f32);