X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e3d7f7703ee16c35dca819794bec8bd730848cd0..ab7049776d45e622f621dd06216a4c1a1ad34b15:/src/cocoa/dcmemory.mm diff --git a/src/cocoa/dcmemory.mm b/src/cocoa/dcmemory.mm index 10b01be3b3..c8f1ff94b4 100644 --- a/src/cocoa/dcmemory.mm +++ b/src/cocoa/dcmemory.mm @@ -1,60 +1,70 @@ ///////////////////////////////////////////////////////////////////////////// // Name: src/cocoa/dcmemory.mm -// Purpose: wxMemoryDC class +// Purpose: wxMemoryDCImpl class // Author: David Elliott // Modified by: // Created: 2003/03/16 // RCS-ID: $Id$ // Copyright: (c) 2002 David Elliott -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#include "wx/dcmemory.h" -#include "wx/log.h" +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif //WX_PRECOMP + +#include "wx/cocoa/dcmemory.h" +#include "wx/cocoa/autorelease.h" #import #import #import +#import +#import //----------------------------------------------------------------------------- -// wxMemoryDC +// wxMemoryDCImpl //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC,wxDC) +IMPLEMENT_ABSTRACT_CLASS(wxMemoryDCImpl,wxCocoaDCImpl) -wxMemoryDC::wxMemoryDC(void) +void wxMemoryDCImpl::Init() { m_cocoaNSImage = NULL; m_ok = false; } -wxMemoryDC::wxMemoryDC( wxDC *WXUNUSED(dc) ) +wxMemoryDCImpl::wxMemoryDCImpl(wxMemoryDC *owner, wxDC *WXUNUSED(dc)) +: wxCocoaDCImpl(owner) { - m_cocoaNSImage = NULL; - m_ok = false; + Init(); } -wxMemoryDC::~wxMemoryDC(void) +wxMemoryDCImpl::~wxMemoryDCImpl(void) { CocoaUnwindStackAndLoseFocus(); [m_cocoaNSImage release]; } -bool wxMemoryDC::CocoaLockFocus() +bool wxMemoryDCImpl::CocoaLockFocus() { if(m_cocoaNSImage) { [m_cocoaNSImage lockFocus]; sm_cocoaDCStack.Insert(this); - m_cocoaFlipped = [m_cocoaNSImage isFlipped]; - m_cocoaHeight = [m_cocoaNSImage size].height; + NSAffineTransform *newTransform = CocoaGetWxToBoundsTransform([m_cocoaNSImage isFlipped], [m_cocoaNSImage size].height); + [newTransform retain]; + [m_cocoaWxToBoundsTransform release]; + m_cocoaWxToBoundsTransform = newTransform; CocoaApplyTransformations(); return true; } return false; } -bool wxMemoryDC::CocoaUnlockFocus() +bool wxMemoryDCImpl::CocoaUnlockFocus() { [m_cocoaNSImage unlockFocus]; return true; @@ -62,12 +72,19 @@ bool wxMemoryDC::CocoaUnlockFocus() // NOTE: The AppKit is unable to draw onto an NSBitmapImageRep so we must // instead copy the data to an offscreen window, then copy it back -void wxMemoryDC::SelectObject( const wxBitmap& bitmap ) +void wxMemoryDCImpl::DoSelect( const wxBitmap& bitmap ) { - if(m_selectedBitmap.Ok()) + wxAutoNSAutoreleasePool pool; + if(m_selectedBitmap.IsOk()) { 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, @@ -78,7 +95,7 @@ void wxMemoryDC::SelectObject( const wxBitmap& bitmap ) [m_cocoaNSImage release]; m_cocoaNSImage = nil; m_selectedBitmap = bitmap; - if(m_selectedBitmap.Ok()) + if(m_selectedBitmap.IsOk()) { // Create an offscreen window of the same size m_cocoaNSImage = [[NSImage alloc] @@ -86,20 +103,29 @@ void wxMemoryDC::SelectObject( const wxBitmap& bitmap ) m_selectedBitmap.GetHeight())]; // Now copy the data - NSImage *nsimage = [[NSImage alloc] - initWithSize:NSMakeSize(m_selectedBitmap.GetWidth(), - m_selectedBitmap.GetHeight())]; - [nsimage addRepresentation: const_cast(m_selectedBitmap).GetNSBitmapImageRep()]; + // 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) fromRect: NSMakeRect(0.0,0.0,m_selectedBitmap.GetWidth(),m_selectedBitmap.GetHeight()) operation: NSCompositeCopy fraction: 1.0]; - + [m_cocoaNSImage unlockFocus]; + [nsimage release]; } } -void wxMemoryDC::DoGetSize( int *width, int *height ) const +void wxMemoryDCImpl::DoGetSize( int *width, int *height ) const { if(width) *width = m_selectedBitmap.GetWidth(); @@ -107,11 +133,11 @@ void wxMemoryDC::DoGetSize( int *width, int *height ) const *height = m_selectedBitmap.GetHeight(); } -bool wxMemoryDC::CocoaDoBlitOnFocusedDC(wxCoord xdest, wxCoord ydest, +bool wxMemoryDCImpl::CocoaDoBlitOnFocusedDC(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxCoord xsrc, wxCoord ysrc, int logicalFunc, bool useMask, wxCoord xsrcMask, wxCoord ysrcMask) { - if(!m_selectedBitmap.Ok()) + if(!m_selectedBitmap.IsOk()) return false; NSAffineTransform *transform = [NSAffineTransform transform]; @@ -133,15 +159,62 @@ bool wxMemoryDC::CocoaDoBlitOnFocusedDC(wxCoord xdest, wxCoord ydest, [transform concat]; [flipTransform concat]; - wxLogDebug("[m_cocoaNSImage isFlipped]=%d", [m_cocoaNSImage isFlipped]); - [m_cocoaNSImage drawAtPoint: NSMakePoint(0,0) + 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]); + [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; } +bool wxMemoryDCImpl::CocoaGetBounds(void *rectData) +{ + if(!rectData) + return false; + if(!m_cocoaNSImage) + return false; + NSRect *pRect = (NSRect*)rectData; + pRect->origin.x = 0.0; + pRect->origin.y = 0.0; + pRect->size = [m_cocoaNSImage size]; + return true; +} +