X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/15fc716c570947057fcceaee6c0e0c4c757b0865..43c5b6e808f083617eb42cb48e77366844f8fb5c:/src/osx/carbon/graphics.cpp?ds=sidebyside diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 416880038a..4bf733644a 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -5,7 +5,7 @@ // Modified by: // Created: 01/02/97 // RCS-ID: $Id$ -// Copyright: (c) Stefan Csomor +// copyright: (c) Stefan Csomor // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -39,12 +39,7 @@ #include "wx/osx/dcprint.h" #include "wx/osx/dcclient.h" #include "wx/osx/dcmemory.h" -#if wxOSX_USE_CARBON -#include "wx/osx/uma.h" -#else -#include "wx/osx/private.h" -#endif - + #include "wx/osx/private.h" #else #include "CoreServices/CoreServices.h" #include "ApplicationServices/ApplicationServices.h" @@ -78,10 +73,39 @@ int UMAGetSystemVersion() #if wxOSX_USE_COCOA_OR_IPHONE extern CGContextRef wxOSXGetContextFromCurrentNSContext() ; -extern void wxOSXLockFocus( WXWidget view) ; +extern bool wxOSXLockFocus( WXWidget view) ; extern void wxOSXUnlockFocus( WXWidget view) ; #endif +#if 1 // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + +// TODO test whether this private API also works under 10.3 + +// copying values from NSCompositingModes (see also webkit and cairo sources) + +typedef enum CGCompositeOperation { + kCGCompositeOperationClear = 0, + kCGCompositeOperationCopy = 1, + kCGCompositeOperationSourceOver = 2, + kCGCompositeOperationSourceIn = 3, + kCGCompositeOperationSourceOut = 4, + kCGCompositeOperationSourceAtop = 5, + kCGCompositeOperationDestinationOver = 6, + kCGCompositeOperationDestinationIn = 7, + kCGCompositeOperationDestinationOut = 8, + kCGCompositeOperationDestinationAtop = 9, + kCGCompositeOperationXOR = 10, + kCGCompositeOperationPlusDarker = 11, +// NS only, unsupported by CG : Highlight + kCGCompositeOperationPlusLighter = 12 +} CGCompositeOperation ; + +extern "C" +{ + CG_EXTERN void CGContextSetCompositeOperation (CGContextRef context, int operation); +} ; + +#endif //----------------------------------------------------------------------------- // constants @@ -147,7 +171,7 @@ CGColorRef wxMacCreateCGColor( const wxColour& col ) CTFontRef wxMacCreateCTFont( const wxFont& font ) { #ifdef __WXMAC__ - return wxCFRetain((CTFontRef) font.MacGetCTFont()); + return wxCFRetain((CTFontRef) font.OSXGetCTFont()); #else return CTFontCreateWithName( wxCFStringRef( font.GetFaceName(), wxLocale::GetSystemEncoding() ) , font.GetPointSize() , NULL ); #endif @@ -539,12 +563,7 @@ void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context ) } else { - if ( context->GetLogicalFunction() == wxINVERT || context->GetLogicalFunction() == wxXOR ) - { - CGContextSetRGBStrokeColor( cg , (CGFloat) 1.0,(CGFloat) 1.0 , (CGFloat) 1.0, (CGFloat) 1.0 ); - } - else - CGContextSetStrokeColorWithColor( cg , m_color ); + CGContextSetStrokeColorWithColor( cg , m_color ); } } @@ -796,7 +815,7 @@ public: virtual ATSUStyle GetATSUStyle() { return m_macATSUIStyle; } #endif #if wxOSX_USE_CORE_TEXT - CTFontRef GetCTFont() const { return m_ctFont ; } + CTFontRef OSXGetCTFont() const { return m_ctFont ; } #endif wxColour GetColour() const { return m_colour ; } @@ -840,7 +859,7 @@ wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* rendere // we need the scale here ... - Fixed atsuSize = IntToFixed( int( 1 * font.MacGetFontSize()) ); + Fixed atsuSize = IntToFixed( int( 1 * font.GetPointSize()) ); RGBColor atsuColor ; col.GetRGBColor( &atsuColor ); ATSUAttributeTag atsuTags[] = @@ -1321,7 +1340,14 @@ public: virtual void * GetNativeContext(); - bool SetLogicalFunction( wxRasterOperationMode function ); + virtual bool SetAntialiasMode(wxAntialiasMode antialias); + + virtual bool SetCompositionMode(wxCompositionMode op); + + virtual void BeginLayer(wxDouble opacity); + + virtual void EndLayer(); + // // transformation // @@ -1391,7 +1417,7 @@ public: DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsContext) private: - void EnsureIsValid(); + bool EnsureIsValid(); virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y ); virtual void DoDrawRotatedText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ); @@ -1406,6 +1432,7 @@ private: CGAffineTransform m_windowTransform; wxDouble m_width; wxDouble m_height; + bool m_invisible; #if wxOSX_USE_COCOA_OR_CARBON wxCFRef m_clipRgn; @@ -1462,6 +1489,7 @@ void wxMacCoreGraphicsContext::Init() #if wxOSX_USE_COCOA_OR_IPHONE m_view = NULL; #endif + m_invisible = false; } wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer) @@ -1527,12 +1555,6 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL) wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext() { SetNativeContext(NULL); -#if wxOSX_USE_COCOA_OR_IPHONE - if ( m_view ) - { - CGContextFlush(m_cgContext); - } -#endif } void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height) @@ -1565,13 +1587,23 @@ void wxMacCoreGraphicsContext::Flush() CGContextFlush(m_cgContext); } -void wxMacCoreGraphicsContext::EnsureIsValid() +bool wxMacCoreGraphicsContext::EnsureIsValid() { if ( !m_cgContext ) { + if (m_invisible) + return false; + #if wxOSX_USE_COCOA_OR_IPHONE - wxOSXLockFocus(m_view); - m_cgContext = wxOSXGetContextFromCurrentNSContext(); + if ( wxOSXLockFocus(m_view) ) + { + m_cgContext = wxOSXGetContextFromCurrentNSContext(); + wxASSERT_MSG( m_cgContext != NULL, _T("Unable to retrieve drawing context from View")); + } + else + { + m_invisible = true; + } #endif #if wxOSX_USE_CARBON OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext ); @@ -1580,110 +1612,208 @@ void wxMacCoreGraphicsContext::EnsureIsValid() wxFAIL_MSG("Cannot nest wxDCs on the same window"); } #endif - CGContextConcatCTM( m_cgContext, m_windowTransform ); - CGContextSaveGState( m_cgContext ); - m_contextSynthesized = true; - if ( m_clipRgn.get() ) + if ( m_cgContext ) { - // the clip region is in device coordinates, so we convert this again to user coordinates - wxCFRef hishape( HIShapeCreateMutableCopy( m_clipRgn ) ); - CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform); - HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y ); - // if the shape is empty, HIShapeReplacePathInCGContext doesn't work - if ( HIShapeIsEmpty(hishape)) + CGContextConcatCTM( m_cgContext, m_windowTransform ); + CGContextSaveGState( m_cgContext ); + m_contextSynthesized = true; + if ( m_clipRgn.get() ) { - CGRect empty = CGRectMake( 0,0,0,0 ); - CGContextClipToRect( m_cgContext, empty ); + // the clip region is in device coordinates, so we convert this again to user coordinates + wxCFRef hishape( HIShapeCreateMutableCopy( m_clipRgn ) ); + CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform); + HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y ); + // if the shape is empty, HIShapeReplacePathInCGContext doesn't work + if ( HIShapeIsEmpty(hishape)) + { + CGRect empty = CGRectMake( 0,0,0,0 ); + CGContextClipToRect( m_cgContext, empty ); + } + else + { + HIShapeReplacePathInCGContext( hishape, m_cgContext ); + CGContextClip( m_cgContext ); + } } - else + CGContextSaveGState( m_cgContext ); + +#if 0 // turn on for debugging of clientdc + static float color = 0.5 ; + static int channel = 0 ; + CGRect bounds = CGRectMake(-1000,-1000,2000,2000); + CGContextSetRGBFillColor( m_cgContext, channel == 0 ? color : 0.5 , + channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 ); + CGContextFillRect( m_cgContext, bounds ); + color += 0.1 ; + if ( color > 0.9 ) { - HIShapeReplacePathInCGContext( hishape, m_cgContext ); - CGContextClip( m_cgContext ); + color = 0.5 ; + channel++ ; + if ( channel == 3 ) + channel = 0 ; } - } - CGContextSaveGState( m_cgContext ); - -#if 0 // turn on for debugging of clientdc - static float color = 0.5 ; - static int channel = 0 ; - CGRect bounds = CGRectMake(-1000,-1000,2000,2000); - CGContextSetRGBFillColor( m_cgContext, channel == 0 ? color : 0.5 , - channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 ); - CGContextFillRect( m_cgContext, bounds ); - color += 0.1 ; - if ( color > 0.9 ) - { - color = 0.5 ; - channel++ ; - if ( channel == 3 ) - channel = 0 ; - } #endif + } } + return m_cgContext != NULL; } -// TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes) - -bool wxMacCoreGraphicsContext::SetLogicalFunction( wxRasterOperationMode function ) +bool wxMacCoreGraphicsContext::SetAntialiasMode(wxAntialiasMode antialias) { - if (m_logicalFunction == function) + if (EnsureIsValid()==false) return true; - EnsureIsValid(); + if (m_antialias == antialias) + return true; + + m_antialias = antialias; + + bool antialiasMode; + switch (antialias) + { + case wxANTIALIAS_DEFAULT: + antialiasMode = true; + break; + case wxANTIALIAS_NONE: + antialiasMode = false; + break; + default: + return false; + } + CGContextSetShouldAntialias(m_cgContext, antialiasMode); + return true; +} - bool retval = false; - bool shouldAntiAlias = true; - CGBlendMode mode = kCGBlendModeNormal; +bool wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op) +{ + if (EnsureIsValid()==false) + return true; -#if defined(__WXMAC__) && ( wxOSX_USE_IPHONE || ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 ) ) -#if wxOSX_USE_IPHONE - if ( 1 ) -#else - if ( UMAGetSystemVersion() >= 0x1050 ) -#endif + if ( m_composition == op ) + return true; + + m_composition = op; + + if (m_composition == wxCOMPOSITION_DEST) + return true; + +#if wxOSX_USE_COCOA_OR_CARBON + if ( UMAGetSystemVersion() < 0x1060 ) { - retval = true; - switch ( function ) + CGCompositeOperation cop = kCGCompositeOperationSourceOver; + CGBlendMode mode = kCGBlendModeNormal; + switch( op ) { - // TODO find best corresponding porter duff modes - case wxCOPY : - mode = kCGBlendModeCopy; - break; - case wxCLEAR : - mode = kCGBlendModeClear; - break; - case wxXOR : - mode = kCGBlendModeXOR; - shouldAntiAlias = false; - break; - default : - retval = false; - break; + case wxCOMPOSITION_CLEAR: + cop = kCGCompositeOperationClear; + break; + case wxCOMPOSITION_SOURCE: + cop = kCGCompositeOperationCopy; + break; + case wxCOMPOSITION_OVER: + mode = kCGBlendModeNormal; + break; + case wxCOMPOSITION_IN: + cop = kCGCompositeOperationSourceIn; + break; + case wxCOMPOSITION_OUT: + cop = kCGCompositeOperationSourceOut; + break; + case wxCOMPOSITION_ATOP: + cop = kCGCompositeOperationSourceAtop; + break; + case wxCOMPOSITION_DEST_OVER: + cop = kCGCompositeOperationDestinationOver; + break; + case wxCOMPOSITION_DEST_IN: + cop = kCGCompositeOperationDestinationIn; + break; + case wxCOMPOSITION_DEST_OUT: + cop = kCGCompositeOperationDestinationOut; + break; + case wxCOMPOSITION_DEST_ATOP: + cop = kCGCompositeOperationDestinationAtop; + break; + case wxCOMPOSITION_XOR: + cop = kCGCompositeOperationXOR; + break; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + case wxCOMPOSITION_ADD: + mode = kCGBlendModePlusLighter ; + break; +#endif + default: + return false; } + if ( cop != kCGCompositeOperationSourceOver ) + CGContextSetCompositeOperation(m_cgContext, cop); + else + CGContextSetBlendMode(m_cgContext, mode); } - else #endif +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + else { - if ( function == wxCOPY ) - { - retval = true; - } - else if ( function == wxINVERT || function == wxXOR ) + CGBlendMode mode = kCGBlendModeNormal; + switch( op ) { - // change color to white - mode = kCGBlendModeExclusion; - shouldAntiAlias = false; - retval = true; + case wxCOMPOSITION_CLEAR: + mode = kCGBlendModeClear; + break; + case wxCOMPOSITION_SOURCE: + mode = kCGBlendModeCopy; + break; + case wxCOMPOSITION_OVER: + mode = kCGBlendModeNormal; + break; + case wxCOMPOSITION_IN: + mode = kCGBlendModeSourceIn; + break; + case wxCOMPOSITION_OUT: + mode = kCGBlendModeSourceOut; + break; + case wxCOMPOSITION_ATOP: + mode = kCGBlendModeSourceAtop; + break; + case wxCOMPOSITION_DEST_OVER: + mode = kCGBlendModeDestinationOver; + break; + case wxCOMPOSITION_DEST_IN: + mode = kCGBlendModeDestinationIn; + break; + case wxCOMPOSITION_DEST_OUT: + mode = kCGBlendModeDestinationOut; + break; + case wxCOMPOSITION_DEST_ATOP: + mode = kCGBlendModeDestinationAtop; + break; + case wxCOMPOSITION_XOR: + mode = kCGBlendModeXOR; + break; + + case wxCOMPOSITION_ADD: + mode = kCGBlendModePlusLighter ; + break; + default: + return false; } + CGContextSetBlendMode(m_cgContext, mode); } +#endif + return true; +} - if (retval) - { - m_logicalFunction = function; - CGContextSetBlendMode( m_cgContext, mode ); - CGContextSetShouldAntialias(m_cgContext, shouldAntiAlias); - } - return retval ; +void wxMacCoreGraphicsContext::BeginLayer(wxDouble opacity) +{ + CGContextSaveGState(m_cgContext); + CGContextSetAlpha(m_cgContext, (CGFloat) opacity); + CGContextBeginTransparencyLayer(m_cgContext, 0); +} + +void wxMacCoreGraphicsContext::EndLayer() +{ + CGContextEndTransparencyLayer(m_cgContext); + CGContextRestoreGState(m_cgContext); } void wxMacCoreGraphicsContext::Clip( const wxRegion ®ion ) @@ -1773,7 +1903,11 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) if ( m_pen.IsNull() ) return ; - EnsureIsValid(); + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() ); @@ -1784,6 +1918,12 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle ) { + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; + if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) { // when using shading, we cannot draw pen and brush at the same time @@ -1818,8 +1958,6 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF } } - EnsureIsValid(); - if ( !m_brush.IsNull() ) ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this); if ( !m_pen.IsNull() ) @@ -1836,7 +1974,11 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF if ( m_brush.IsNull() ) return; - EnsureIsValid(); + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) { @@ -1933,7 +2075,12 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { - EnsureIsValid(); + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; + #ifdef __WXMAC__ wxMacCoreGraphicsBitmapData* refdata =static_cast(bmp.GetRefData()); CGImageRef image = refdata->GetBitmap(); @@ -1970,30 +2117,36 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { - EnsureIsValid(); + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; CGRect r = CGRectMake( (CGFloat) 0.0 , (CGFloat) 0.0 , (CGFloat) w , (CGFloat) h ); CGContextSaveGState( m_cgContext ); CGContextTranslateCTM( m_cgContext,(CGFloat) x ,(CGFloat) (y + h) ); CGContextScaleCTM( m_cgContext, 1, -1 ); -#if wxOSX_USE_CARBON +#if wxOSX_USE_COCOA_OR_CARBON PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone , - NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ); + NULL , kPlotIconRefNormalFlags , icon.GetHICON() ); #endif CGContextRestoreGState( m_cgContext ); } void wxMacCoreGraphicsContext::PushState() { - EnsureIsValid(); - + if (EnsureIsValid()==false) + return; + CGContextSaveGState( m_cgContext ); } void wxMacCoreGraphicsContext::PopState() { - EnsureIsValid(); - + if (EnsureIsValid()==false) + return; + CGContextRestoreGState( m_cgContext ); } @@ -2001,13 +2154,18 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo { wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); - EnsureIsValid(); + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; + #if wxOSX_USE_CORE_TEXT if ( UMAGetSystemVersion() >= 0x1050 ) { wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData(); wxCFStringRef text(str, wxLocale::GetSystemEncoding() ); - CTFontRef font = fref->GetCTFont(); + CTFontRef font = fref->OSXGetCTFont(); CGColorRef col = wxMacCreateCGColor( fref->GetColour() ); CTUnderlineStyle ustyle = fref->GetUnderlined() ? kCTUnderlineStyleSingle : kCTUnderlineStyleNone ; wxCFRef underlined( CFNumberCreate(NULL, kCFNumberSInt32Type, &ustyle) ); @@ -2021,7 +2179,7 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo y += CTFontGetAscent(font); CGContextSaveGState(m_cgContext); - CGContextTranslateCTM(m_cgContext, x, y); + CGContextTranslateCTM(m_cgContext, (CGFloat) x, (CGFloat) y); CGContextScaleCTM(m_cgContext, 1, -1); CGContextSetTextPosition(m_cgContext, 0, 0); CTLineDraw( line, m_cgContext ); @@ -2059,7 +2217,12 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, { wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); - EnsureIsValid(); + if (EnsureIsValid()==false) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; + #if wxOSX_USE_CORE_TEXT if ( UMAGetSystemVersion() >= 0x1050 ) { @@ -2179,7 +2342,7 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid if ( UMAGetSystemVersion() >= 0x1050 ) { wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData(); - CTFontRef font = fref->GetCTFont(); + CTFontRef font = fref->OSXGetCTFont(); wxCFStringRef text(str, wxLocale::GetSystemEncoding() ); CFStringRef keys[] = { kCTFontAttributeName }; @@ -2189,7 +2352,8 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid wxCFRef attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) ); wxCFRef line( CTLineCreateWithAttributedString(attrtext) ); - CGFloat w, a, d, l; + double w; + CGFloat a, d, l; w = CTLineGetTypographicBounds(line, &a, &d, &l) ; @@ -2273,7 +2437,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr #if wxOSX_USE_CORE_TEXT { wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData(); - CTFontRef font = fref->GetCTFont(); + CTFontRef font = fref->OSXGetCTFont(); wxCFStringRef t(text, wxLocale::GetSystemEncoding() ); CFStringRef keys[] = { kCTFontAttributeName }; @@ -2540,6 +2704,7 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( vo #if wxOSX_USE_CARBON return new wxMacCoreGraphicsContext(this,(WindowRef)window); #else + wxUnusedVar(window); return NULL; #endif }