|
| 1 | +use crate::{GraphicsContextImpl, SoftBufferError}; |
| 2 | +use raw_window_handle::{HasRawWindowHandle, AppKitHandle}; |
| 3 | +use objc::runtime::Object; |
| 4 | +use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault}; |
| 5 | +use core_graphics::color_space::CGColorSpace; |
| 6 | +use core_graphics::context::CGContext; |
| 7 | +use core_graphics::data_provider::CGDataProvider; |
| 8 | +use core_graphics::geometry::{CGPoint, CGSize, CGRect}; |
| 9 | +use core_graphics::image::CGImage; |
| 10 | +use core_graphics::sys; |
| 11 | + |
| 12 | +pub struct CGImpl { |
| 13 | + view: *mut Object, |
| 14 | +} |
| 15 | + |
| 16 | +impl CGImpl { |
| 17 | + pub unsafe fn new<W: HasRawWindowHandle>(handle: AppKitHandle) -> Result<Self, SoftBufferError<W>> { |
| 18 | + let window = handle.ns_window as *mut Object; |
| 19 | + let view = handle.ns_view as *mut Object; |
| 20 | + let cls = class!(NSGraphicsContext); |
| 21 | + let graphics_context: *mut Object = msg_send![cls, graphicsContextWithWindow:window]; |
| 22 | + if graphics_context.is_null() { |
| 23 | + return Err(SoftBufferError::PlatformError(Some("Graphics context is null".into()), None)); |
| 24 | + } |
| 25 | + let _: () = msg_send![cls, setCurrentContext:graphics_context]; |
| 26 | + Ok( |
| 27 | + Self { |
| 28 | + view, |
| 29 | + } |
| 30 | + ) |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +impl GraphicsContextImpl for CGImpl { |
| 35 | + unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { |
| 36 | + let cls = class!(NSGraphicsContext); |
| 37 | + let graphics_context: *mut Object = msg_send![cls, currentContext]; |
| 38 | + let context_ptr: *mut sys::CGContext = msg_send![graphics_context, CGContext]; |
| 39 | + let context = CGContext::from_existing_context_ptr(context_ptr); |
| 40 | + let color_space = CGColorSpace::create_device_rgb(); |
| 41 | + let slice = std::slice::from_raw_parts( |
| 42 | + buffer.as_ptr() as *const u8, |
| 43 | + buffer.len() * 4); |
| 44 | + let data_provider = CGDataProvider::from_slice(slice); |
| 45 | + let image = CGImage::new( |
| 46 | + width as usize, |
| 47 | + height as usize, |
| 48 | + 8, |
| 49 | + 32, |
| 50 | + (width * 4) as usize, |
| 51 | + &color_space, |
| 52 | + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, |
| 53 | + &data_provider, |
| 54 | + false, |
| 55 | + kCGRenderingIntentDefault, |
| 56 | + ); |
| 57 | + let frame: CGRect = msg_send![self.view, frame]; |
| 58 | + // In Core Graphics, (0, 0) is bottom left, not top left |
| 59 | + let origin = CGPoint { x: 0f64, y: frame.size.height }; |
| 60 | + let size = CGSize { width: width as f64, height: -(height as f64) }; |
| 61 | + let rect = CGRect { origin, size }; |
| 62 | + context.draw_image(rect, &image); |
| 63 | + } |
| 64 | +} |
0 commit comments