X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b2680ced12cbbed16990007c5fa3ea7730700122..c9ed413ab4f5673ffff00198dc6ce1397398bda4:/src/osx/carbon/graphics.cpp diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 1b0eca575a..1a07e2278d 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -1,11 +1,11 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/mac/carbon/dccg.cpp +// Name: src/osx/carbon/dccg.cpp // Purpose: wxDC class // Author: Stefan Csomor // 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" @@ -72,7 +67,45 @@ int UMAGetSystemVersion() } -#define wxMAC_USE_CORE_TEXT 1 +#define wxOSX_USE_CORE_TEXT 1 + +#endif + +#if wxOSX_USE_COCOA_OR_IPHONE +extern CGContextRef wxOSXGetContextFromCurrentContext() ; +#if wxOSX_USE_COCOA +extern bool wxOSXLockFocus( WXWidget view) ; +extern void wxOSXUnlockFocus( WXWidget view) ; +#endif +#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 @@ -103,8 +136,13 @@ OSStatus wxMacDrawCGImage( #if wxOSX_USE_CARBON return HIViewDrawCGImage( inContext, inBounds, inImage ); #else - // todo flip - CGContextDrawImage(inContext, *inBounds, inImage ); + CGContextSaveGState(inContext); + CGContextTranslateCTM(inContext, inBounds->origin.x, inBounds->origin.y + inBounds->size.height); + CGRect r = *inBounds; + r.origin.x = r.origin.y = 0; + CGContextScaleCTM(inContext, 1, -1); + CGContextDrawImage(inContext, r, inImage ); + CGContextRestoreGState(inContext); return noErr; #endif } @@ -130,12 +168,12 @@ CGColorRef wxMacCreateCGColor( const wxColour& col ) return retval; } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 && wxMAC_USE_CORE_TEXT +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 && wxOSX_USE_CORE_TEXT 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 @@ -415,32 +453,32 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer switch ( pen.GetStyle() ) { - case wxSOLID : + case wxPENSTYLE_SOLID: break; - case wxDOT : + case wxPENSTYLE_DOT: m_count = WXSIZEOF(dotted); m_userLengths = new CGFloat[ m_count ] ; memcpy( m_userLengths, dotted, sizeof(dotted) ); m_lengths = m_userLengths; break; - case wxLONG_DASH : + case wxPENSTYLE_LONG_DASH: m_count = WXSIZEOF(dashed); m_lengths = dashed; break; - case wxSHORT_DASH : + case wxPENSTYLE_SHORT_DASH: m_count = WXSIZEOF(short_dashed); m_lengths = short_dashed; break; - case wxDOT_DASH : + case wxPENSTYLE_DOT_DASH: m_count = WXSIZEOF(dotted_dashed); m_lengths = dotted_dashed; break; - case wxUSER_DASH : + case wxPENSTYLE_USER_DASH: wxDash *dashes; m_count = pen.GetDashes( &dashes ); if ((dashes != NULL) && (m_count > 0)) @@ -459,7 +497,7 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer m_lengths = m_userLengths; break; - case wxSTIPPLE : + case wxPENSTYLE_STIPPLE: { wxBitmap* bmp = pen.GetStipple(); if ( bmp && bmp->Ok() ) @@ -527,12 +565,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 ); } } @@ -540,20 +573,6 @@ void wxMacCoreGraphicsPenData::Apply( wxGraphicsContext* context ) // Brush // -static const char *gs_stripedback_xpm[] = { -/* columns rows colors chars-per-pixel */ -"4 4 2 1", -". c #F0F0F0", -"X c #ECECEC", -/* pixels */ -"....", -"....", -"XXXX", -"XXXX" -}; - -wxBitmap gs_stripedback_bmp( wxImage( (const char* const* ) gs_stripedback_xpm ), -1 ) ; - // make sure we all use one class for all conversions from wx to native colour class wxMacCoreGraphicsColour @@ -647,15 +666,18 @@ public: ~wxMacCoreGraphicsBrushData (); virtual void Apply( wxGraphicsContext* context ); - void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ); - void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ); + void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops); + void CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, wxDouble radius, + const wxGraphicsGradientStops& stops); virtual bool IsShading() { return m_isShading; } CGShadingRef GetShading() { return m_shading; } protected: - CGFunctionRef CreateGradientFunction( const wxColour& c1, const wxColour& c2 ); + CGFunctionRef CreateGradientFunction(const wxGraphicsGradientStops& stops); + static void CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out); virtual void Init(); @@ -664,7 +686,42 @@ protected: bool m_isShading; CGFunctionRef m_gradientFunction; CGShadingRef m_shading; - CGFloat *m_gradientComponents; + + // information about a single gradient component + struct GradientComponent + { + CGFloat pos; + CGFloat red; + CGFloat green; + CGFloat blue; + CGFloat alpha; + }; + + // and information about all of them + struct GradientComponents + { + GradientComponents() + { + count = 0; + comps = NULL; + } + + void Init(unsigned count_) + { + count = count_; + comps = new GradientComponent[count]; + } + + ~GradientComponents() + { + delete [] comps; + } + + unsigned count; + GradientComponent *comps; + }; + + GradientComponents m_gradientComponents; }; wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* renderer) : wxGraphicsObjectRefData( renderer ) @@ -672,20 +729,25 @@ wxMacCoreGraphicsBrushData::wxMacCoreGraphicsBrushData( wxGraphicsRenderer* rend Init(); } -void wxMacCoreGraphicsBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ) +void +wxMacCoreGraphicsBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { - m_gradientFunction = CreateGradientFunction( c1, c2 ); + m_gradientFunction = CreateGradientFunction(stops); m_shading = CGShadingCreateAxial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) x1, (CGFloat) y1), CGPointMake((CGFloat) x2,(CGFloat) y2), m_gradientFunction, true, true ) ; m_isShading = true ; } -void wxMacCoreGraphicsBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ) +void +wxMacCoreGraphicsBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { - m_gradientFunction = CreateGradientFunction( oColor, cColor ); - m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) xo,(CGFloat) yo), 0, + m_gradientFunction = CreateGradientFunction(stops); + m_shading = CGShadingCreateRadial( wxMacGetGenericRGBColorSpace(), CGPointMake((CGFloat) xo,(CGFloat) yo), 0, CGPointMake((CGFloat) xc,(CGFloat) yc), (CGFloat) radius, m_gradientFunction, true, true ) ; m_isShading = true ; } @@ -704,15 +766,12 @@ wxMacCoreGraphicsBrushData::~wxMacCoreGraphicsBrushData() if( m_gradientFunction ) CGFunctionRelease(m_gradientFunction); - - delete[] m_gradientComponents; } void wxMacCoreGraphicsBrushData::Init() { m_gradientFunction = NULL; m_shading = NULL; - m_gradientComponents = NULL; m_isShading = false; } @@ -732,30 +791,70 @@ void wxMacCoreGraphicsBrushData::Apply( wxGraphicsContext* context ) void wxMacCoreGraphicsBrushData::CalculateShadingValues (void *info, const CGFloat *in, CGFloat *out) { - CGFloat* colors = (CGFloat*) info ; + const GradientComponents& stops = *(GradientComponents*) info ; + CGFloat f = *in; - for( int i = 0 ; i < 4 ; ++i ) + if (f <= 0.0) + { + // Start + out[0] = stops.comps[0].red; + out[1] = stops.comps[0].green; + out[2] = stops.comps[0].blue; + out[3] = stops.comps[0].alpha; + } + else if (f >= 1.0) + { + // end + out[0] = stops.comps[stops.count - 1].red; + out[1] = stops.comps[stops.count - 1].green; + out[2] = stops.comps[stops.count - 1].blue; + out[3] = stops.comps[stops.count - 1].alpha; + } + else { - out[i] = colors[i] + ( colors[4+i] - colors[i] ) * f; + // Find first component with position greater than f + unsigned i; + for ( i = 0; i < stops.count; i++ ) + { + if (stops.comps[i].pos > f) + break; + } + + // Interpolated between stops + CGFloat diff = (f - stops.comps[i-1].pos); + CGFloat range = (stops.comps[i].pos - stops.comps[i-1].pos); + CGFloat fact = diff / range; + + out[0] = stops.comps[i - 1].red + (stops.comps[i].red - stops.comps[i - 1].red) * fact; + out[1] = stops.comps[i - 1].green + (stops.comps[i].green - stops.comps[i - 1].green) * fact; + out[2] = stops.comps[i - 1].blue + (stops.comps[i].blue - stops.comps[i - 1].blue) * fact; + out[3] = stops.comps[i - 1].alpha + (stops.comps[i].alpha - stops.comps[i - 1].alpha) * fact; } } -CGFunctionRef wxMacCoreGraphicsBrushData::CreateGradientFunction( const wxColour& c1, const wxColour& c2 ) +CGFunctionRef +wxMacCoreGraphicsBrushData::CreateGradientFunction(const wxGraphicsGradientStops& stops) { + static const CGFunctionCallbacks callbacks = { 0, &CalculateShadingValues, NULL }; static const CGFloat input_value_range [2] = { 0, 1 }; static const CGFloat output_value_ranges [8] = { 0, 1, 0, 1, 0, 1, 0, 1 }; - m_gradientComponents = new CGFloat[8] ; - m_gradientComponents[0] = (CGFloat) (c1.Red() / 255.0); - m_gradientComponents[1] = (CGFloat) (c1.Green() / 255.0); - m_gradientComponents[2] = (CGFloat) (c1.Blue() / 255.0); - m_gradientComponents[3] = (CGFloat) (c1.Alpha() / 255.0); - m_gradientComponents[4] = (CGFloat) (c2.Red() / 255.0); - m_gradientComponents[5] = (CGFloat) (c2.Green() / 255.0); - m_gradientComponents[6] = (CGFloat) (c2.Blue() / 255.0); - m_gradientComponents[7] = (CGFloat) (c2.Alpha() / 255.0); - - return CGFunctionCreate ( m_gradientComponents, 1, + + m_gradientComponents.Init(stops.GetCount()); + for ( unsigned i = 0; i < m_gradientComponents.count; i++ ) + { + const wxGraphicsGradientStop stop = stops.Item(i); + + m_gradientComponents.comps[i].pos = stop.GetPosition(); + + const wxColour col = stop.GetColour(); + m_gradientComponents.comps[i].red = (CGFloat) (col.Red() / 255.0); + m_gradientComponents.comps[i].green = (CGFloat) (col.Green() / 255.0); + m_gradientComponents.comps[i].blue = (CGFloat) (col.Blue() / 255.0); + m_gradientComponents.comps[i].alpha = (CGFloat) (col.Alpha() / 255.0); + } + + return CGFunctionCreate ( &m_gradientComponents, 1, input_value_range, 4, output_value_ranges, @@ -780,11 +879,11 @@ public: wxMacCoreGraphicsFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col ); ~wxMacCoreGraphicsFontData(); -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT virtual ATSUStyle GetATSUStyle() { return m_macATSUIStyle; } #endif -#if wxMAC_USE_CORE_TEXT - CTFontRef GetCTFont() const { return m_ctFont ; } +#if wxOSX_USE_CORE_TEXT + CTFontRef OSXGetCTFont() const { return m_ctFont ; } #endif wxColour GetColour() const { return m_colour ; } @@ -795,10 +894,10 @@ public: private : wxColour m_colour; bool m_underlined; -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT ATSUStyle m_macATSUIStyle; #endif -#if wxMAC_USE_CORE_TEXT +#if wxOSX_USE_CORE_TEXT wxCFRef< CTFontRef > m_ctFont; #endif #if wxOSX_USE_IPHONE @@ -811,14 +910,14 @@ wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* rendere m_colour = col; m_underlined = font.GetUnderlined(); -#if wxMAC_USE_CORE_TEXT +#if wxOSX_USE_CORE_TEXT m_ctFont.reset( wxMacCreateCTFont( font ) ); #endif #if wxOSX_USE_IPHONE m_uiFont = CreateUIFont(font); wxMacCocoaRetain( m_uiFont ); #endif -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT OSStatus status = noErr; m_macATSUIStyle = NULL; @@ -828,7 +927,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[] = @@ -836,19 +935,19 @@ wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* rendere kATSUSizeTag , kATSUColorTag , }; - ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = + ByteCount atsuSizes[WXSIZEOF(atsuTags)] = { sizeof( Fixed ) , sizeof( RGBColor ) , }; - ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = + ATSUAttributeValuePtr atsuValues[WXSIZEOF(atsuTags)] = { &atsuSize , &atsuColor , }; status = ::ATSUSetAttributes( - m_macATSUIStyle, sizeof(atsuTags) / sizeof(ATSUAttributeTag) , + m_macATSUIStyle, WXSIZEOF(atsuTags), atsuTags, atsuSizes, atsuValues); wxASSERT_MSG( status == noErr , wxT("couldn't modify ATSU style") ); @@ -857,9 +956,9 @@ wxMacCoreGraphicsFontData::wxMacCoreGraphicsFontData(wxGraphicsRenderer* rendere wxMacCoreGraphicsFontData::~wxMacCoreGraphicsFontData() { -#if wxMAC_USE_CORE_TEXT +#if wxOSX_USE_CORE_TEXT #endif -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT if ( m_macATSUIStyle ) { ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle); @@ -983,7 +1082,7 @@ wxGraphicsObjectRefData *wxMacCoreGraphicsMatrixData::Clone() const // concatenates the matrix void wxMacCoreGraphicsMatrixData::Concat( const wxGraphicsMatrixData *t ) { - m_matrix = CGAffineTransformConcat(m_matrix, *((CGAffineTransform*) t->GetNativeMatrix()) ); + m_matrix = CGAffineTransformConcat(*((CGAffineTransform*) t->GetNativeMatrix()), m_matrix ); } // sets the matrix to the respective values @@ -1119,9 +1218,12 @@ public : // appends a rectangle as a new closed subpath virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ); - // appends an ellipsis as a new closed subpath fitting the passed rectangle + // appends a circle as a new closed subpath virtual void AddCircle( wxDouble x, wxDouble y, wxDouble r ); + // appends an ellipsis as a new closed subpath fitting the passed rectangle + virtual void AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h); + // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ); @@ -1140,7 +1242,7 @@ public : // gets the bounding box enclosing all points (possibly including control points) virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *y) const; - virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxODDEVEN_RULE) const; + virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxODDEVEN_RULE) const; private : CGMutablePathRef m_path; }; @@ -1198,7 +1300,12 @@ void wxMacCoreGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w void wxMacCoreGraphicsPathData::AddCircle( wxDouble x, wxDouble y , wxDouble r ) { - CGPathAddArc( m_path , NULL , (CGFloat) x , (CGFloat) y , (CGFloat) r , (CGFloat) 0.0 , (CGFloat) (2 * M_PI) , true ); + CGPathAddEllipseInRect( m_path, NULL, CGRectMake(x-r,y-r,2*r,2*r)); +} + +void wxMacCoreGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + CGPathAddEllipseInRect( m_path, NULL, CGRectMake(x,y,w,h)); } // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle @@ -1251,7 +1358,7 @@ void wxMacCoreGraphicsPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wx *h = bounds.size.height; } -bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, int fillStyle) const +bool wxMacCoreGraphicsPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle) const { return CGPathContainsPoint( m_path, NULL, CGPointMake((CGFloat) x,(CGFloat) y), fillStyle == wxODDEVEN_RULE ); } @@ -1309,7 +1416,14 @@ public: virtual void * GetNativeContext(); - bool SetLogicalFunction( int function ); + virtual bool SetAntialiasMode(wxAntialiasMode antialias); + + virtual bool SetCompositionMode(wxCompositionMode op); + + virtual void BeginLayer(wxDouble opacity); + + virtual void EndLayer(); + // // transformation // @@ -1339,10 +1453,10 @@ public: virtual void StrokePath( const wxGraphicsPath &path ); // fills a path with the current brush - virtual void FillPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE ); + virtual void FillPath( const wxGraphicsPath &path, wxPolygonFillMode fillStyle = wxODDEVEN_RULE ); // draws a path by first filling and then stroking - virtual void DrawPath( const wxGraphicsPath &path, int fillStyle = wxODDEVEN_RULE ); + virtual void DrawPath( const wxGraphicsPath &path, wxPolygonFillMode fillStyle = wxODDEVEN_RULE ); virtual bool ShouldOffset() const { @@ -1359,10 +1473,6 @@ public: // text // - virtual void DrawText( const wxString &str, wxDouble x, wxDouble y ); - - virtual void DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ); - virtual void GetTextExtent( const wxString &text, wxDouble *width, wxDouble *height, wxDouble *descent, wxDouble *externalLeading ) const; @@ -1383,18 +1493,24 @@ 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 ); CGContextRef m_cgContext; #if wxOSX_USE_CARBON WindowRef m_windowRef; +#else + WXWidget m_view; #endif - bool m_releaseContext; + bool m_contextSynthesized; CGAffineTransform m_windowTransform; wxDouble m_width; wxDouble m_height; + bool m_invisible; -#if wxOSX_USE_CARBON +#if wxOSX_USE_COCOA_OR_CARBON wxCFRef m_clipRgn; #endif }; @@ -1425,14 +1541,23 @@ public : m_cg = cg; m_offset = offset; if ( m_offset ) - CGContextTranslateCTM( m_cg, (CGFloat) 0.5, (CGFloat) 0.5 ); + { + m_userOffset = CGContextConvertSizeToUserSpace( m_cg, CGSizeMake( 0.5 , 0.5 ) ); + CGContextTranslateCTM( m_cg, m_userOffset.width , m_userOffset.height ); + } + else + { + m_userOffset = CGSizeMake(0.0, 0.0); + } + } ~wxQuartzOffsetHelper( ) { if ( m_offset ) - CGContextTranslateCTM( m_cg, (CGFloat) -0.5, (CGFloat) -0.5 ); + CGContextTranslateCTM( m_cg, -m_userOffset.width , -m_userOffset.height ); } public : + CGSize m_userOffset; CGContextRef m_cg; bool m_offset; } ; @@ -1440,12 +1565,16 @@ public : void wxMacCoreGraphicsContext::Init() { m_cgContext = NULL; - m_releaseContext = false; + m_contextSynthesized = false; + m_width = 0; + m_height = 0; #if wxOSX_USE_CARBON m_windowRef = NULL; #endif - m_width = 0; - m_height = 0; +#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) @@ -1468,19 +1597,35 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer { Init(); + wxSize sz = window->GetSize(); + m_width = sz.x; + m_height = sz.y; + +#if wxOSX_USE_COCOA_OR_IPHONE + m_view = window->GetHandle(); + +#if wxOSX_USE_COCOA + if ( ! window->GetPeer()->IsFlipped() ) + { + m_windowTransform = CGAffineTransformMakeTranslation( 0 , m_height ); + m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 ); + } + else +#endif + { + m_windowTransform = CGAffineTransformIdentity; + } +#else int originX , originY; originX = originY = 0; - Rect bounds = { 0,0,0,0 }; -#if defined(__WXCOCOA__) || !wxOSX_USE_CARBON -#else m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef(); window->MacWindowToRootWindow( &originX , &originY ); GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds ); -#endif m_windowTransform = CGAffineTransformMakeTranslation( 0 , bounds.bottom - bounds.top ); m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 ); m_windowTransform = CGAffineTransformTranslate( m_windowTransform, originX, originY ) ; +#endif } wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer) @@ -1529,112 +1674,248 @@ void wxMacCoreGraphicsContext::Flush() CGContextFlush(m_cgContext); } -void wxMacCoreGraphicsContext::EnsureIsValid() +bool wxMacCoreGraphicsContext::EnsureIsValid() { if ( !m_cgContext ) { -#if defined(__WXCOCOA__) || ! wxOSX_USE_CARBON - wxFAIL_MSG("Cannot create wxDCs lazily"); -#else + if (m_invisible) + return false; + +#if wxOSX_USE_COCOA + if ( wxOSXLockFocus(m_view) ) + { + m_cgContext = wxOSXGetContextFromCurrentContext(); + wxASSERT_MSG( m_cgContext != NULL, wxT("Unable to retrieve drawing context from View")); + } + else + { + m_invisible = true; + } +#endif +#if wxOSX_USE_IPHONE + m_cgContext = wxOSXGetContextFromCurrentContext(); + if ( m_cgContext == NULL ) + { + m_invisible = true; + } +#endif +#if wxOSX_USE_CARBON OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext ); if ( status != noErr ) { wxFAIL_MSG("Cannot nest wxDCs on the same window"); } - - CGContextConcatCTM( m_cgContext, m_windowTransform ); - CGContextSaveGState( m_cgContext ); - m_releaseContext = true; - if ( m_clipRgn.get() ) +#endif + 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)) + CGContextSaveGState( m_cgContext ); + CGContextConcatCTM( m_cgContext, m_windowTransform ); + CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity ); + m_contextSynthesized = true; +#if wxOSX_USE_COCOA_OR_CARBON + 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 +#endif + 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 ); #endif + } } + return m_cgContext != NULL; } -// TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes) +bool wxMacCoreGraphicsContext::SetAntialiasMode(wxAntialiasMode antialias) +{ + if (!EnsureIsValid()) + return true; -bool wxMacCoreGraphicsContext::SetLogicalFunction( int function ) + 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 wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op) { - if (m_logicalFunction == function) + if (!EnsureIsValid()) return true; - EnsureIsValid(); + if ( m_composition == op ) + return true; - bool retval = false; - bool shouldAntiAlias = true; - CGBlendMode mode = kCGBlendModeNormal; + m_composition = op; -#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 == 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 ) { -#if wxOSX_USE_CARBON +#if wxOSX_USE_COCOA_OR_CARBON if( m_cgContext ) { wxCFRef shape = wxCFRefFromGet(region.GetWXHRGN()); @@ -1676,7 +1957,7 @@ void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDoubl } else { -#if wxOSX_USE_CARBON +#if wxOSX_USE_COCOA_OR_CARBON // the clipping itself must be stored as device coordinates, otherwise // we cannot apply it back correctly r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform ); @@ -1705,7 +1986,7 @@ void wxMacCoreGraphicsContext::ResetClip() } else { -#if wxOSX_USE_CARBON +#if wxOSX_USE_COCOA_OR_CARBON m_clipRgn.reset(); #else // allow usage as measuring context @@ -1719,7 +2000,11 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) if ( m_pen.IsNull() ) return ; - EnsureIsValid(); + if (!EnsureIsValid()) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() ); @@ -1728,8 +2013,14 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) CGContextStrokePath( m_cgContext ); } -void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillStyle ) +void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle ) { + if (!EnsureIsValid()) + 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 @@ -1764,8 +2055,6 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillSt } } - EnsureIsValid(); - if ( !m_brush.IsNull() ) ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this); if ( !m_pen.IsNull() ) @@ -1777,12 +2066,16 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillSt CGContextDrawPath( m_cgContext , mode ); } -void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , int fillStyle ) +void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle ) { if ( m_brush.IsNull() ) return; - EnsureIsValid(); + if (!EnsureIsValid()) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) { @@ -1810,20 +2103,21 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ) if ( m_cgContext ) { - // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext ); CGContextRestoreGState( m_cgContext ); CGContextRestoreGState( m_cgContext ); - if ( m_releaseContext ) + if ( m_contextSynthesized ) { #if wxOSX_USE_CARBON QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext); +#endif +#if wxOSX_USE_COCOA + wxOSXUnlockFocus(m_view); #endif } else CGContextRelease(m_cgContext); } - m_cgContext = cg; // FIXME: This check is needed because currently we need to use a DC/GraphicsContext @@ -1839,7 +2133,7 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ) CGContextSaveGState( m_cgContext ); CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity ); CGContextSaveGState( m_cgContext ); - m_releaseContext = false; + m_contextSynthesized = false; } } @@ -1875,7 +2169,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()) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; + #ifdef __WXMAC__ wxMacCoreGraphicsBitmapData* refdata =static_cast(bmp.GetRefData()); CGImageRef image = refdata->GetBitmap(); @@ -1912,45 +2211,55 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { - EnsureIsValid(); + if (!EnsureIsValid()) + 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()) + return; CGContextSaveGState( m_cgContext ); } void wxMacCoreGraphicsContext::PopState() { - EnsureIsValid(); + if (!EnsureIsValid()) + return; CGContextRestoreGState( m_cgContext ); } -void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y ) +void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDouble y ) { - if ( m_font.IsNull() ) + wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); + + if (!EnsureIsValid()) + return; + + if (m_composition == wxCOMPOSITION_DEST) return; - EnsureIsValid(); -#if wxMAC_USE_CORE_TEXT +#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) ); @@ -1964,7 +2273,7 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub 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 ); @@ -1973,19 +2282,19 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub return; } #endif -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT { DrawText(str, x, y, 0.0); return; } #endif -#if wxMAC_USE_CG_TEXT +#if wxOSX_USE_IPHONE wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData(); CGContextSaveGState(m_cgContext); CGColorRef col = wxMacCreateCGColor( fref->GetColour() ); - CGContextSetTextDrawingMode (m_cgContext, kCGTextFill); + CGContextSetTextDrawingMode (m_cgContext, kCGTextFill); CGContextSetFillColorWithColor( m_cgContext, col ); wxCFStringRef text(str, wxLocale::GetSystemEncoding() ); @@ -1996,21 +2305,27 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub #endif } -void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) +void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, + wxDouble x, wxDouble y, + wxDouble angle) { - if ( m_font.IsNull() ) + wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); + + if (!EnsureIsValid()) return; - EnsureIsValid(); -#if wxMAC_USE_CORE_TEXT + if (m_composition == wxCOMPOSITION_DEST) + return; + +#if wxOSX_USE_CORE_TEXT if ( UMAGetSystemVersion() >= 0x1050 ) { // default implementation takes care of rotation and calls non rotated DrawText afterwards - wxGraphicsContext::DrawText( str, x, y, angle ); + wxGraphicsContext::DoDrawRotatedText( str, x, y, angle ); return; } #endif -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT { OSStatus status = noErr; ATSUTextLayout atsuLayout; @@ -2034,15 +2349,15 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub { kATSULineRotationTag , }; - ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = + ByteCount atsuSizes[WXSIZEOF(atsuTags)] = { sizeof( Fixed ) , }; - ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = + ATSUAttributeValuePtr atsuValues[WXSIZEOF(atsuTags)] = { &atsuAngle , }; - status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag), + status = ::ATSUSetLayoutControls(atsuLayout , WXSIZEOF(atsuTags), atsuTags, atsuSizes, atsuValues ); } @@ -2051,15 +2366,15 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub { kATSUCGContextTag , }; - ByteCount atsuSizes[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = + ByteCount atsuSizes[WXSIZEOF(atsuTags)] = { sizeof( CGContextRef ) , }; - ATSUAttributeValuePtr atsuValues[sizeof(atsuTags) / sizeof(ATSUAttributeTag)] = + ATSUAttributeValuePtr atsuValues[WXSIZEOF(atsuTags)] = { &m_cgContext , }; - status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags) / sizeof(ATSUAttributeTag), + status = ::ATSUSetLayoutControls(atsuLayout , WXSIZEOF(atsuTags), atsuTags, atsuSizes, atsuValues ); } @@ -2094,16 +2409,16 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub return; } #endif -#if wxMAC_USE_CG_TEXT +#if wxOSX_USE_IPHONE // default implementation takes care of rotation and calls non rotated DrawText afterwards - wxGraphicsContext::DrawText( str, x, y, angle ); + wxGraphicsContext::DoDrawRotatedText( str, x, y, angle ); #endif } void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, wxDouble *descent, wxDouble *externalLeading ) const { - wxCHECK_RET( !m_font.IsNull(), wxT("wxDC(cg)::DoGetTextExtent - no valid font set") ); + wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::GetTextExtent - no valid font set") ); if ( width ) *width = 0; @@ -2117,11 +2432,11 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid if (str.empty()) return; -#if wxMAC_USE_CORE_TEXT +#if wxOSX_USE_CORE_TEXT 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 }; @@ -2131,9 +2446,13 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid wxCFRef attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) ); wxCFRef line( CTLineCreateWithAttributedString(attrtext) ); - CGFloat w, a, d, l; - - w = CTLineGetTypographicBounds(line, &a, &d, &l) ; + // round the returned extent: this is probably more correct anyhow but + // we also need to do it to be consistent with GetPartialTextExtents() + // below and avoid strange situation when the last partial extent + // returned by it could have been greater than the full extent returned + // by us + CGFloat a, d, l; + int w = CTLineGetTypographicBounds(line, &a, &d, &l) + 0.5; if ( height ) *height = a+d+l; @@ -2146,7 +2465,7 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid return; } #endif -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT { OSStatus status = noErr; @@ -2183,12 +2502,12 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid return; } #endif -#if wxMAC_USE_CG_TEXT +#if wxOSX_USE_IPHONE wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData(); wxCFStringRef text(str, wxLocale::GetSystemEncoding() ); CGSize sz = MeasureTextInContext( fref->GetUIFont() , text.AsNSString() ); - + if ( height ) *height = sz.height; /* @@ -2207,13 +2526,15 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr widths.Empty(); widths.Add(0, text.length()); + wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); + if (text.empty()) return; -#if wxMAC_USE_CORE_TEXT +#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 }; @@ -2226,13 +2547,13 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr int chars = text.length(); for ( int pos = 0; pos < (int)chars; pos ++ ) { - widths[pos] = CTLineGetOffsetForStringIndex( line, pos+1 , NULL )+0.5; + widths[pos] = CTLineGetOffsetForStringIndex( line, pos+1 , NULL ); } return; } #endif -#if wxMAC_USE_ATSU_TEXT +#if wxOSX_USE_ATSU_TEXT { OSStatus status = noErr; ATSUTextLayout atsuLayout; @@ -2268,7 +2589,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr #else ATSLayoutRecord *layoutRecords = NULL; ItemCount glyphCount = 0; - + // Get the glyph extents OSStatus err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(atsuLayout, 0, @@ -2277,7 +2598,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr &layoutRecords, &glyphCount); wxASSERT(glyphCount == (text.length()+1)); - + if ( err == noErr && glyphCount == (text.length()+1)) { for ( int pos = 1; pos < (int)glyphCount ; pos ++ ) @@ -2285,7 +2606,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr widths[pos-1] = FixedToInt( layoutRecords[pos].realPos ); } } - + ::ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **) &layoutRecords); @@ -2293,7 +2614,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr ::ATSUDisposeTextLayout(atsuLayout); } #endif -#if wxMAC_USE_CG_TEXT +#if wxOSX_USE_IPHONE // TODO core graphics text implementation here #endif } @@ -2309,7 +2630,7 @@ void wxMacCoreGraphicsContext::ConcatTransform( const wxGraphicsMatrix& matrix ) if ( m_cgContext ) CGContextConcatCTM( m_cgContext, *(CGAffineTransform*) matrix.GetNativeMatrix()); else - m_windowTransform = CGAffineTransformConcat(m_windowTransform, *(CGAffineTransform*) matrix.GetNativeMatrix()); + m_windowTransform = CGAffineTransformConcat(*(CGAffineTransform*) matrix.GetNativeMatrix(), m_windowTransform); } // sets the transform of this context @@ -2356,7 +2677,9 @@ public : virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc); virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc); +#if wxUSE_PRINTING_ARCHITECTURE virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc); +#endif virtual wxGraphicsContext * CreateContextFromNativeContext( void * context ); @@ -2380,14 +2703,16 @@ public : virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) ; + virtual wxGraphicsBrush + CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops); - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) ; + virtual wxGraphicsBrush + CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops); // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; @@ -2395,6 +2720,9 @@ public : // create a native bitmap representation virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) ; + // create a graphics bitmap from a native bitmap + virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap ); + // create a native bitmap representation virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ; private : @@ -2414,10 +2742,6 @@ wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() return &gs_MacCoreGraphicsRenderer; } -#if defined( __WXCOCOA__ ) || wxOSX_USE_COCOA -extern CGContextRef wxMacGetContextFromCurrentNSContext() ; -#endif - wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc ) { const wxDCImpl* impl = dc.GetImpl(); @@ -2427,12 +2751,13 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& int w, h; win_impl->GetSize( &w, &h ); CGContextRef cgctx = 0; -#ifdef __WXMAC__ - cgctx = (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef()); -#else - cgctx = wxMacGetContextFromCurrentNSContext() ; -#endif - return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h ); + + wxASSERT_MSG(win_impl->GetWindow(), "Invalid wxWindow in wxMacCoreGraphicsRenderer::CreateContext"); + if (win_impl->GetWindow()) + cgctx = (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef()); + + if (cgctx != 0) + return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h ); } return NULL; } @@ -2453,9 +2778,9 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxMemoryDC& return NULL; } +#if wxUSE_PRINTING_ARCHITECTURE wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxPrinterDC& dc ) { -#if wxUSE_PRINTING_ARCHITECTURE #ifdef __WXMAC__ const wxDCImpl* impl = dc.GetImpl(); wxPrinterDCImpl *print_impl = wxDynamicCast( impl, wxPrinterDCImpl ); @@ -2466,10 +2791,10 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxPrinterDC& return new wxMacCoreGraphicsContext( this, (CGContextRef)(print_impl->GetGraphicsContext()->GetNativeContext()), (wxDouble) w, (wxDouble) h ); } -#endif #endif return NULL; } +#endif wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( void * context ) { @@ -2481,6 +2806,7 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( vo #if wxOSX_USE_CARBON return new wxMacCoreGraphicsContext(this,(WindowRef)window); #else + wxUnusedVar(window); return NULL; #endif } @@ -2546,9 +2872,19 @@ wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmap( const wxBitmap& bmp ) if ( bmp.Ok() ) { wxGraphicsBitmap p; -#ifdef __WXMAC__ p.SetRefData(new wxMacCoreGraphicsBitmapData( this , bmp.CreateCGImage(), bmp.GetDepth() == 1 ) ); -#endif + return p; + } + else + return wxNullGraphicsBitmap; +} + +wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmapFromNativeBitmap( void* bitmap ) +{ + if ( bitmap != NULL ) + { + wxGraphicsBitmap p; + p.SetRefData(new wxMacCoreGraphicsBitmapData( this , (CGImageRef) bitmap, false )); return p; } else @@ -2570,25 +2906,27 @@ wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateSubBitmap( const wxGraphicsBit return wxNullGraphicsBitmap; } -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) +wxGraphicsBrush +wxMacCoreGraphicsRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, + wxDouble x2, wxDouble y2, + const wxGraphicsGradientStops& stops) { wxGraphicsBrush p; wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2); + d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); p.SetRefData(d); return p; } -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) +wxGraphicsBrush +wxMacCoreGraphicsRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, + wxDouble xc, wxDouble yc, + wxDouble radius, + const wxGraphicsGradientStops& stops) { wxGraphicsBrush p; wxMacCoreGraphicsBrushData* d = new wxMacCoreGraphicsBrushData( this ); - d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); + d->CreateRadialGradientBrush(xo, yo, xc, yc, radius, stops); p.SetRefData(d); return p; }