From f4d77105f34d39f32b6ef43905b2430d82944430 Mon Sep 17 00:00:00 2001 From: longmathemagician Date: Wed, 17 Aug 2022 14:59:53 -0700 Subject: [PATCH 1/5] Draw all updates to an intermediate bitmap context --- druid-shell/src/backend/mac/window.rs | 62 +++++++++++++++++++++------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/druid-shell/src/backend/mac/window.rs b/druid-shell/src/backend/mac/window.rs index a3b18cf1a9..01c2b96d0e 100644 --- a/druid-shell/src/backend/mac/window.rs +++ b/druid-shell/src/backend/mac/window.rs @@ -24,19 +24,21 @@ use std::time::Instant; use block::ConcreteBlock; use cocoa::appkit::{ CGFloat, NSApp, NSApplication, NSAutoresizingMaskOptions, NSBackingStoreBuffered, NSColor, - NSEvent, NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow, NSWindowStyleMask, + NSEvent, NSImage, NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow, NSWindowStyleMask, }; use cocoa::base::{id, nil, BOOL, NO, YES}; use cocoa::foundation::{ NSArray, NSAutoreleasePool, NSInteger, NSPoint, NSRect, NSSize, NSString, NSUInteger, }; use core_graphics::context::CGContextRef; +use core_graphics::sys::CGContext; use foreign_types::ForeignTypeRef; use lazy_static::lazy_static; use objc::declare::ClassDecl; use objc::rc::WeakPtr; use objc::runtime::{Class, Object, Protocol, Sel}; use objc::{class, msg_send, sel, sel_impl}; +use piet_common::InterpolationMode; use tracing::{debug, error, info}; #[cfg(feature = "raw-win-handle")] @@ -850,27 +852,59 @@ extern "C" fn view_will_draw(this: &mut Object, _: Sel) { extern "C" fn draw_rect(this: &mut Object, _: Sel, dirtyRect: NSRect) { unsafe { - let context: id = msg_send![class![NSGraphicsContext], currentContext]; - //FIXME: when core_graphics is at 0.20, we should be able to use - //core_graphics::sys::CGContextRef as our pointer type. - let cgcontext_ptr: *mut ::CType = - msg_send![context, CGContext]; - let cgcontext_ref = CGContextRef::from_ptr_mut(cgcontext_ptr); + let cgcontext_id: id = msg_send![class![NSGraphicsContext], currentContext]; + let cgcontext_ptr: &mut CGContext = msg_send![cgcontext_id, CGContext]; + let cgcontext_ref: &mut CGContextRef = CGContextRef::from_ptr_mut(cgcontext_ptr); + + let view_state: *mut c_void = *this.get_ivar("viewState"); + let view_state: &mut ViewState = &mut *(view_state as *mut ViewState); // FIXME: use the actual invalid region instead of just this bounding box. // https://developer.apple.com/documentation/appkit/nsview/1483772-getrectsbeingdrawn?language=objc - let rect = Rect::from_origin_size( + let invalid_region_rect = Rect::from_origin_size( (dirtyRect.origin.x, dirtyRect.origin.y), (dirtyRect.size.width, dirtyRect.size.height), ); - let invalid = Region::from(rect); + let invalid_region = Region::from(invalid_region_rect); - let view_state: *mut c_void = *this.get_ivar("viewState"); - let view_state = &mut *(view_state as *mut ViewState); - let mut piet_ctx = Piet::new_y_down(cgcontext_ref, Some(view_state.text.clone())); + let context_size = NSView::frame(this as *mut _); + let context_width = context_size.size.width; + let context_height = context_size.size.height; + + let mut cache_ctx = core_graphics::context::CGContext::create_bitmap_context( + None, + context_width as usize, + context_height as usize, + 8, + 0, + &core_graphics::color_space::CGColorSpace::create_device_rgb(), + core_graphics::base::kCGImageAlphaPremultipliedLast, + ); + + { + let mut piet_bitmap_ctx = Piet::new_y_up( + &mut cache_ctx, + context_height as f64, + Some(view_state.text.clone()), + ); + (*view_state) + .handler + .paint(&mut piet_bitmap_ctx, &invalid_region); + } + + let cache_context_content = cache_ctx + .create_image() + .expect("Failed to retrieve content from render cache context"); + + let mut window_ctx = Piet::new_y_down(cgcontext_ref, Some(view_state.text.clone())); + window_ctx.draw_image_area( + &piet_common::CoreGraphicsImage::NonEmpty(cache_context_content), + invalid_region_rect, + invalid_region_rect, + InterpolationMode::Bilinear, + ); - (*view_state).handler.paint(&mut piet_ctx, &invalid); - if let Err(e) = piet_ctx.finish() { + if let Err(e) = window_ctx.finish() { error!("{}", e) } From a7a103758e5ff49de364fa45fd5454627eb7d6f0 Mon Sep 17 00:00:00 2001 From: longmathemagician Date: Wed, 17 Aug 2022 17:12:57 -0700 Subject: [PATCH 2/5] Remove unused import --- druid-shell/src/backend/mac/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/druid-shell/src/backend/mac/window.rs b/druid-shell/src/backend/mac/window.rs index 01c2b96d0e..b32be0d3f6 100644 --- a/druid-shell/src/backend/mac/window.rs +++ b/druid-shell/src/backend/mac/window.rs @@ -24,7 +24,7 @@ use std::time::Instant; use block::ConcreteBlock; use cocoa::appkit::{ CGFloat, NSApp, NSApplication, NSAutoresizingMaskOptions, NSBackingStoreBuffered, NSColor, - NSEvent, NSImage, NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow, NSWindowStyleMask, + NSEvent, NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow, NSWindowStyleMask, }; use cocoa::base::{id, nil, BOOL, NO, YES}; use cocoa::foundation::{ From 36771960a55922e56fb78ea604019f9dbc963ac4 Mon Sep 17 00:00:00 2001 From: longmathemagician Date: Thu, 18 Aug 2022 16:40:17 -0700 Subject: [PATCH 3/5] Harmonize y-direction management --- druid-shell/src/backend/mac/window.rs | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/druid-shell/src/backend/mac/window.rs b/druid-shell/src/backend/mac/window.rs index b32be0d3f6..34876124e3 100644 --- a/druid-shell/src/backend/mac/window.rs +++ b/druid-shell/src/backend/mac/window.rs @@ -881,25 +881,25 @@ extern "C" fn draw_rect(this: &mut Object, _: Sel, dirtyRect: NSRect) { core_graphics::base::kCGImageAlphaPremultipliedLast, ); - { - let mut piet_bitmap_ctx = Piet::new_y_up( - &mut cache_ctx, - context_height as f64, - Some(view_state.text.clone()), - ); - (*view_state) - .handler - .paint(&mut piet_bitmap_ctx, &invalid_region); - } + let mut piet_bitmap_ctx = Piet::new_y_up( + &mut cache_ctx, + context_height as f64, + Some(view_state.text.clone()), + ); - let cache_context_content = cache_ctx - .create_image() - .expect("Failed to retrieve content from render cache context"); + (*view_state) + .handler + .paint(&mut piet_bitmap_ctx, &invalid_region); + + let cache_context_content = piet_bitmap_ctx + .capture_image_area(invalid_region_rect) + .expect("Failed to retrieve content from render cache context") + .copy_image() + .expect("Cropped image was empty"); let mut window_ctx = Piet::new_y_down(cgcontext_ref, Some(view_state.text.clone())); - window_ctx.draw_image_area( - &piet_common::CoreGraphicsImage::NonEmpty(cache_context_content), - invalid_region_rect, + window_ctx.draw_image( + &piet_common::CoreGraphicsImage::YDown(cache_context_content), invalid_region_rect, InterpolationMode::Bilinear, ); From f0ff474ae91a3b6bcc6d2a3dc881ea3892161c1e Mon Sep 17 00:00:00 2001 From: longmathemagician Date: Thu, 18 Aug 2022 20:02:28 -0700 Subject: [PATCH 4/5] Switch image unwrapping method --- druid-shell/src/backend/mac/window.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/druid-shell/src/backend/mac/window.rs b/druid-shell/src/backend/mac/window.rs index 34876124e3..b7ceb28324 100644 --- a/druid-shell/src/backend/mac/window.rs +++ b/druid-shell/src/backend/mac/window.rs @@ -891,15 +891,15 @@ extern "C" fn draw_rect(this: &mut Object, _: Sel, dirtyRect: NSRect) { .handler .paint(&mut piet_bitmap_ctx, &invalid_region); - let cache_context_content = piet_bitmap_ctx + let cache_capture = piet_bitmap_ctx .capture_image_area(invalid_region_rect) - .expect("Failed to retrieve content from render cache context") - .copy_image() - .expect("Cropped image was empty"); + .expect("Failed to retrieve content from render cache context"); + let unwrapped_cache = cache_capture.as_ref().expect("Cropped image was empty"); + let rewrapped_cache = piet_common::CoreGraphicsImage::YDown(unwrapped_cache.clone()); let mut window_ctx = Piet::new_y_down(cgcontext_ref, Some(view_state.text.clone())); window_ctx.draw_image( - &piet_common::CoreGraphicsImage::YDown(cache_context_content), + &rewrapped_cache, invalid_region_rect, InterpolationMode::Bilinear, ); From 131e68843cf9aa053815b1768f5d29c8fef75638 Mon Sep 17 00:00:00 2001 From: longmathemagician Date: Thu, 18 Aug 2022 23:14:30 -0700 Subject: [PATCH 5/5] Rename CoreGraphicsImage::as_ref to CoreGraphicsImage::aas_cgimage so as to not conflict with as_ref trait --- druid-shell/src/backend/mac/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/druid-shell/src/backend/mac/window.rs b/druid-shell/src/backend/mac/window.rs index b7ceb28324..ec2dfc228b 100644 --- a/druid-shell/src/backend/mac/window.rs +++ b/druid-shell/src/backend/mac/window.rs @@ -894,7 +894,7 @@ extern "C" fn draw_rect(this: &mut Object, _: Sel, dirtyRect: NSRect) { let cache_capture = piet_bitmap_ctx .capture_image_area(invalid_region_rect) .expect("Failed to retrieve content from render cache context"); - let unwrapped_cache = cache_capture.as_ref().expect("Cropped image was empty"); + let unwrapped_cache = cache_capture.as_cgimage().expect("Cropped image was empty"); let rewrapped_cache = piet_common::CoreGraphicsImage::YDown(unwrapped_cache.clone()); let mut window_ctx = Piet::new_y_down(cgcontext_ref, Some(view_state.text.clone()));