From 50918c652cd4130ad3daa5389e6a0d9a38eb740f Mon Sep 17 00:00:00 2001 From: David Elliott Date: Wed, 1 Aug 2007 04:14:12 +0000 Subject: [PATCH] Make masks and alpha work for wxCOPY when blitting a selected bitmap from a wxMemoryDC with an eye towards possibly doing more in the future. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47838 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/cocoa/dcmemory.mm | 54 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/cocoa/dcmemory.mm b/src/cocoa/dcmemory.mm index b6de98c880..9b1a0e9f85 100644 --- a/src/cocoa/dcmemory.mm +++ b/src/cocoa/dcmemory.mm @@ -78,6 +78,12 @@ void wxMemoryDC::DoSelect( const wxBitmap& bitmap ) { CocoaTakeFocus(); wxASSERT(m_cocoaNSImage); + // Replace the bitmap's native data with a newly created one based on the + // NSImage that has been (potentially) drawn upon. Note that this may and + // probably will in many cases change the bitmap's format. + // There is nothing we can do about this using pure Cocoa code. Even using + // CGBitmapContext is not an option because it only supports a limited + // number of bitmap formats. Specifically, 24-bpp is not supported. m_selectedBitmap.SetNSBitmapImageRep( [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0.0,0.0, @@ -96,6 +102,16 @@ void wxMemoryDC::DoSelect( const wxBitmap& bitmap ) m_selectedBitmap.GetHeight())]; // Now copy the data + // Pass false to GetNSImage so the mask is not applied as an alpha channel. + // Cocoa uses premultiplied alpha so applying the mask would cause all + // color information masked out to be turned black which is undesirable. + // FIXME: Currently, the mask will not be updated if any drawing occurs. + // My only suggestion is for wxCocoa users to eschew the mask in favor + // of an alpha channel or to recreate the mask after drawing. + // The only way to fix this is to draw twice, once as normal and again + // onto the mask to update it. That would require overriding every + // single drawing primitive (e.g. DoDrawLine, DoDrawRectangle, etc.) + // and would be a major undertaking. NSImage *nsimage = [m_selectedBitmap.GetNSImage(false) retain]; [m_cocoaNSImage lockFocus]; [nsimage drawAtPoint: NSMakePoint(0,0) @@ -142,14 +158,48 @@ bool wxMemoryDC::CocoaDoBlitOnFocusedDC(wxCoord xdest, wxCoord ydest, [transform concat]; [flipTransform concat]; + NSImage *sourceImage; + if(useMask) + { + sourceImage = [m_cocoaNSImage copy]; + // Apply the mask to the copied image + NSBitmapImageRep *maskRep = m_selectedBitmap.GetMask()->GetNSBitmapImageRep(); + NSImage *maskImage = [[NSImage alloc] initWithSize:[maskRep size]]; + [maskImage addRepresentation:maskRep]; + [sourceImage lockFocus]; + [maskImage compositeToPoint:NSZeroPoint operation:NSCompositeDestinationIn]; + [sourceImage unlockFocus]; + [maskImage release]; + } + else + { // retain the m_cocoaNSImage so it has the same ownership as the copy done in the other case. + sourceImage = [m_cocoaNSImage retain]; + } + NSCompositingOperation drawingOp; + switch(logicalFunc) + { + case wxCOPY: + // Even if not using the mask, the image might have an alpha channel + // so always use NSCompositeSourceOver. If the image is fully opaque + // it works out the same as NSCompositeCopy. + drawingOp = NSCompositeSourceOver; + break; + // FIXME: implement more raster ops + default: + wxLogDebug(wxT("wxCocoa does not support blitting with raster operation %d."), logicalFunc); + // Just use the default operation. + drawingOp = NSCompositeCopy; + } + wxLogTrace(wxTRACE_COCOA,wxT("[m_cocoaNSImage isFlipped]=%d"), [m_cocoaNSImage isFlipped]); - [m_cocoaNSImage drawAtPoint: NSMakePoint(0,0) + [sourceImage drawAtPoint: NSMakePoint(0,0) fromRect: NSMakeRect(xsrc, m_selectedBitmap.GetHeight()-height-ysrc, width, height) - operation: NSCompositeCopy // FIXME: raster ops + operation: drawingOp fraction: 1.0]; + [sourceImage release]; // It was either retained, copied, or allocated. [context restoreGraphicsState]; return false; } -- 2.45.2