use CALayer for macOS backend

This commit is contained in:
Ryan Hileman 2022-04-24 07:31:19 -07:00
parent 75216061b7
commit ba3b823e1c
2 changed files with 25 additions and 29 deletions

View file

@ -26,7 +26,9 @@ x11-dl = "2.19.1"
winapi = "0.3.9" winapi = "0.3.9"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24.0"
core-graphics = "0.22.3" core-graphics = "0.22.3"
foreign-types = "0.3.0"
objc = "0.2.7" objc = "0.2.7"
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
@ -49,4 +51,4 @@ features = ["jpeg"]
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
# Turn rayon back on everywhere else; creating the separate entry resets the features to default. # Turn rayon back on everywhere else; creating the separate entry resets the features to default.
image = "0.23.14" image = "0.23.14"
rayon = "1.5.1" rayon = "1.5.1"

View file

@ -1,42 +1,30 @@
use crate::{GraphicsContextImpl, SoftBufferError}; use crate::{GraphicsContextImpl, SoftBufferError};
use raw_window_handle::{HasRawWindowHandle, AppKitHandle}; use raw_window_handle::{HasRawWindowHandle, AppKitHandle};
use objc::runtime::Object;
use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault}; use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault};
use core_graphics::color_space::CGColorSpace; use core_graphics::color_space::CGColorSpace;
use core_graphics::context::CGContext;
use core_graphics::data_provider::CGDataProvider; use core_graphics::data_provider::CGDataProvider;
use core_graphics::geometry::{CGPoint, CGSize, CGRect}; use core_graphics::geometry::CGSize;
use core_graphics::image::CGImage; use core_graphics::image::CGImage;
use core_graphics::sys;
use cocoa::base::id;
use cocoa::quartzcore::CALayer;
use foreign_types::ForeignType;
pub struct CGImpl { pub struct CGImpl {
view: *mut Object, layer: CALayer,
} }
impl CGImpl { impl CGImpl {
pub unsafe fn new<W: HasRawWindowHandle>(handle: AppKitHandle) -> Result<Self, SoftBufferError<W>> { pub unsafe fn new<W: HasRawWindowHandle>(handle: AppKitHandle) -> Result<Self, SoftBufferError<W>> {
let window = handle.ns_window as *mut Object; let view = handle.ns_view as id;
let view = handle.ns_view as *mut Object; let layer = CALayer::new();
let cls = class!(NSGraphicsContext); let _: () = msg_send![view, setLayer:layer.clone()];
let graphics_context: *mut Object = msg_send![cls, graphicsContextWithWindow:window]; Ok(Self{layer})
if graphics_context.is_null() {
return Err(SoftBufferError::PlatformError(Some("Graphics context is null".into()), None));
}
let _: () = msg_send![cls, setCurrentContext:graphics_context];
Ok(
Self {
view,
}
)
} }
} }
impl GraphicsContextImpl for CGImpl { impl GraphicsContextImpl for CGImpl {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
let cls = class!(NSGraphicsContext);
let graphics_context: *mut Object = msg_send![cls, currentContext];
let context_ptr: *mut sys::CGContext = msg_send![graphics_context, CGContext];
let context = CGContext::from_existing_context_ptr(context_ptr);
let color_space = CGColorSpace::create_device_rgb(); let color_space = CGColorSpace::create_device_rgb();
let slice = std::slice::from_raw_parts( let slice = std::slice::from_raw_parts(
buffer.as_ptr() as *const u8, buffer.as_ptr() as *const u8,
@ -54,11 +42,17 @@ impl GraphicsContextImpl for CGImpl {
false, false,
kCGRenderingIntentDefault, kCGRenderingIntentDefault,
); );
let frame: CGRect = msg_send![self.view, frame];
// In Core Graphics, (0, 0) is bottom left, not top left let size = CGSize::new(width as f64, height as f64);
let origin = CGPoint { x: 0f64, y: frame.size.height }; let rep: id = msg_send![class!(NSCGImageRep), alloc];
let size = CGSize { width: width as f64, height: -(height as f64) }; let rep: id = msg_send![rep, initWithCGImage:image.as_ptr() size:size];
let rect = CGRect { origin, size };
context.draw_image(rect, &image); let nsimage: id = msg_send![class!(NSImage), alloc];
let nsimage: id = msg_send![nsimage, initWithSize:size];
let _: () = msg_send![nsimage, addRepresentation:rep];
let _: () = msg_send![rep, release];
self.layer.set_contents(nsimage);
let _: () = msg_send![nsimage, release];
} }
} }