X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b4ff8b3e4e8e906806bafbb1acfd7248b89c5994..47e175a24f862aa8b7ca7dd4a2bb5957991e7f2d:/src/osx/carbon/graphics.cpp diff --git a/src/osx/carbon/graphics.cpp b/src/osx/carbon/graphics.cpp index 4a1e139f31..c42ffba7f7 100644 --- a/src/osx/carbon/graphics.cpp +++ b/src/osx/carbon/graphics.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/osx/carbon/dccg.cpp +// Name: src/osx/carbon/graphics.cpp // Purpose: wxDC class // Author: Stefan Csomor // Modified by: @@ -98,7 +98,7 @@ typedef enum CGCompositeOperation { kCGCompositeOperationDestinationAtop = 9, kCGCompositeOperationXOR = 10, kCGCompositeOperationPlusDarker = 11, -// NS only, unsupported by CG : Highlight +// NS only, unsupported by CG : Highlight kCGCompositeOperationPlusLighter = 12 } CGCompositeOperation ; @@ -113,11 +113,9 @@ extern "C" // constants //----------------------------------------------------------------------------- -#if !defined( __DARWIN__ ) || defined(__MWERKS__) #ifndef M_PI const double M_PI = 3.14159265358979; #endif -#endif static const double RAD2DEG = 180.0 / M_PI; @@ -149,26 +147,13 @@ OSStatus wxMacDrawCGImage( CGColorRef wxMacCreateCGColor( const wxColour& col ) { - CGColorRef retval = 0; -#ifdef __WXMAC__ - retval = col.CreateCGColor(); -#else -// TODO add conversion NSColor - CGColorRef (obj-c) -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - if ( CGColorCreateGenericRGB ) - retval = CGColorCreateGenericRGB( col.Red() / 255.0 , col.Green() / 255.0, col.Blue() / 255.0, col.Alpha() / 255.0 ); - else -#endif - { - CGFloat components[4] = { col.Red() / 255.0, col.Green() / 255.0, col.Blue() / 255.0, col.Alpha() / 255.0 } ; - retval = CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ; - } + CGColorRef retval = col.CreateCGColor(); -#endif + wxASSERT(retval != NULL); return retval; } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 && wxOSX_USE_CORE_TEXT +#if wxOSX_USE_CORE_TEXT CTFontRef wxMacCreateCTFont( const wxFont& font ) { @@ -225,7 +210,7 @@ class ImagePattern : public wxMacCoreGraphicsPattern public : ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform ) { - wxASSERT( bmp && bmp->Ok() ); + wxASSERT( bmp && bmp->IsOk() ); #ifdef __WXMAC__ Init( (CGImageRef) bmp->CreateCGImage() , transform ); #endif @@ -453,32 +438,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)) @@ -497,10 +482,10 @@ wxMacCoreGraphicsPenData::wxMacCoreGraphicsPenData( wxGraphicsRenderer* renderer m_lengths = m_userLengths; break; - case wxSTIPPLE : + case wxPENSTYLE_STIPPLE: { wxBitmap* bmp = pen.GetStipple(); - if ( bmp && bmp->Ok() ) + if ( bmp && bmp->IsOk() ) { m_colorSpace.reset( CGColorSpaceCreatePattern( NULL ) ); m_pattern.reset( (CGPatternRef) *( new ImagePattern( bmp , CGAffineTransformMakeScale( 1,-1 ) ) ) ); @@ -573,20 +558,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 @@ -661,7 +632,7 @@ wxMacCoreGraphicsColour::wxMacCoreGraphicsColour( const wxBrush &brush ) { // now brush is a bitmap wxBitmap* bmp = brush.GetStipple(); - if ( bmp && bmp->Ok() ) + if ( bmp && bmp->IsOk() ) { m_isPattern = true; m_patternColorComponents = new CGFloat[1] ; @@ -680,15 +651,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(); @@ -697,7 +671,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 ) @@ -705,19 +714,24 @@ 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_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 ; @@ -737,15 +751,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; } @@ -765,30 +776,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) { - out[i] = colors[i] + ( colors[4+i] - colors[i] ) * f; + // 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 + { + // 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, @@ -869,19 +920,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") ); @@ -904,20 +955,29 @@ wxMacCoreGraphicsFontData::~wxMacCoreGraphicsFontData() #endif } -class wxMacCoreGraphicsBitmapData : public wxGraphicsObjectRefData +class wxMacCoreGraphicsBitmapData : public wxGraphicsBitmapData { public: wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap, bool monochrome ); ~wxMacCoreGraphicsBitmapData(); virtual CGImageRef GetBitmap() { return m_bitmap; } + virtual void* GetNativeBitmap() const { return m_bitmap; } bool IsMonochrome() { return m_monochrome; } + +#if wxUSE_IMAGE + wxImage ConvertToImage() const + { + return wxBitmap(m_bitmap).ConvertToImage(); + } +#endif // wxUSE_IMAGE + private : CGImageRef m_bitmap; bool m_monochrome; }; -wxMacCoreGraphicsBitmapData::wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap, bool monochrome ) : wxGraphicsObjectRefData( renderer ), +wxMacCoreGraphicsBitmapData::wxMacCoreGraphicsBitmapData( wxGraphicsRenderer* renderer, CGImageRef bitmap, bool monochrome ) : wxGraphicsBitmapData( renderer ), m_bitmap(bitmap), m_monochrome(monochrome) { } @@ -927,6 +987,7 @@ wxMacCoreGraphicsBitmapData::~wxMacCoreGraphicsBitmapData() CGImageRelease( m_bitmap ); } + // // Graphics Matrix // @@ -1016,7 +1077,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 @@ -1152,9 +1213,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 ); @@ -1171,7 +1235,7 @@ public : virtual void Transform( const wxGraphicsMatrixData* matrix ); // gets the bounding box enclosing all points (possibly including control points) - virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *y) const; + virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const; virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxODDEVEN_RULE) const; private : @@ -1231,7 +1295,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 @@ -1310,15 +1379,10 @@ public: wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer); - wxMacCoreGraphicsContext(); - ~wxMacCoreGraphicsContext(); void Init(); - // returns the size of the graphics context in device coordinates - virtual void GetSize( wxDouble* width, wxDouble* height); - virtual void StartPage( wxDouble width, wxDouble height ); virtual void EndPage(); @@ -1344,12 +1408,14 @@ public: virtual bool SetAntialiasMode(wxAntialiasMode antialias); + virtual bool SetInterpolationQuality(wxInterpolationQuality interpolation); + virtual bool SetCompositionMode(wxCompositionMode op); virtual void BeginLayer(wxDouble opacity); virtual void EndLayer(); - + // // transformation // @@ -1386,6 +1452,9 @@ public: virtual bool ShouldOffset() const { + if ( !m_enableOffset ) + return false; + int penwidth = 0 ; if ( !m_pen.IsNull() ) { @@ -1413,13 +1482,19 @@ public: virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + + // fast convenience methods + + + virtual void DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ); void SetNativeContext( CGContextRef cg ); - DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsContext) + wxDECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext); private: bool EnsureIsValid(); + void CheckInvariants() const; virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y ); virtual void DoDrawRotatedText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ); @@ -1432,8 +1507,6 @@ private: #endif bool m_contextSynthesized; CGAffineTransform m_windowTransform; - wxDouble m_width; - wxDouble m_height; bool m_invisible; #if wxOSX_USE_COCOA_OR_CARBON @@ -1457,8 +1530,6 @@ private: // wxMacCoreGraphicsContext implementation //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext) - class wxQuartzOffsetHelper { public : @@ -1467,14 +1538,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; } ; @@ -1492,6 +1572,8 @@ void wxMacCoreGraphicsContext::Init() m_view = NULL; #endif m_invisible = false; + m_antialias = wxANTIALIAS_DEFAULT; + m_interpolation = wxINTERPOLATION_DEFAULT; } wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer) @@ -1507,6 +1589,7 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer { Init(); m_windowRef = window; + m_enableOffset = true; } #endif @@ -1514,6 +1597,7 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer { Init(); + m_enableOffset = true; wxSize sz = window->GetSize(); m_width = sz.x; m_height = sz.y; @@ -1550,24 +1634,19 @@ wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) Init(); } -wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL) -{ - Init(); - wxLogDebug(wxT("Illegal Constructor called")); -} - wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext() { SetNativeContext(NULL); } -void wxMacCoreGraphicsContext::GetSize( wxDouble* width, wxDouble* height) + +void wxMacCoreGraphicsContext::CheckInvariants() const { - *width = m_width; - *height = m_height; + // check invariants here for debugging ... } + void wxMacCoreGraphicsContext::StartPage( wxDouble width, wxDouble height ) { CGRect r; @@ -1593,16 +1672,18 @@ void wxMacCoreGraphicsContext::Flush() bool wxMacCoreGraphicsContext::EnsureIsValid() { + CheckInvariants(); + if ( !m_cgContext ) { if (m_invisible) return false; - + #if wxOSX_USE_COCOA if ( wxOSXLockFocus(m_view) ) { m_cgContext = wxOSXGetContextFromCurrentContext(); - wxASSERT_MSG( m_cgContext != NULL, _T("Unable to retrieve drawing context from View")); + wxASSERT_MSG( m_cgContext != NULL, wxT("Unable to retrieve drawing context from View")); } else { @@ -1625,16 +1706,11 @@ bool wxMacCoreGraphicsContext::EnsureIsValid() #endif if ( m_cgContext ) { - CGContextConcatCTM( m_cgContext, m_windowTransform ); CGContextSaveGState( m_cgContext ); - m_contextSynthesized = true; #if wxOSX_USE_COCOA_OR_CARBON if ( m_clipRgn.get() ) { - // 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)) { @@ -1648,8 +1724,11 @@ bool wxMacCoreGraphicsContext::EnsureIsValid() } } #endif + CGContextConcatCTM( m_cgContext, m_windowTransform ); + CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity ); + m_contextSynthesized = true; CGContextSaveGState( m_cgContext ); - + #if 0 // turn on for debugging of clientdc static float color = 0.5 ; static int channel = 0 ; @@ -1668,19 +1747,21 @@ bool wxMacCoreGraphicsContext::EnsureIsValid() #endif } } + CheckInvariants(); + return m_cgContext != NULL; } bool wxMacCoreGraphicsContext::SetAntialiasMode(wxAntialiasMode antialias) { - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return true; if (m_antialias == antialias) return true; - + m_antialias = antialias; - + bool antialiasMode; switch (antialias) { @@ -1694,67 +1775,106 @@ bool wxMacCoreGraphicsContext::SetAntialiasMode(wxAntialiasMode antialias) return false; } CGContextSetShouldAntialias(m_cgContext, antialiasMode); + CheckInvariants(); + return true; +} + +bool wxMacCoreGraphicsContext::SetInterpolationQuality(wxInterpolationQuality interpolation) +{ + if (!EnsureIsValid()) + return true; + + if (m_interpolation == interpolation) + return true; + + m_interpolation = interpolation; + CGInterpolationQuality quality; + + switch (interpolation) + { + case wxINTERPOLATION_DEFAULT: + quality = kCGInterpolationDefault; + break; + case wxINTERPOLATION_NONE: + quality = kCGInterpolationNone; + break; + case wxINTERPOLATION_FAST: + quality = kCGInterpolationLow; + break; + case wxINTERPOLATION_GOOD: +#if wxOSX_USE_COCOA_OR_CARBON + quality = UMAGetSystemVersion() < 0x1060 ? kCGInterpolationHigh : (CGInterpolationQuality) 4 /*kCGInterpolationMedium only on 10.6*/; +#else + quality = kCGInterpolationMedium; +#endif + break; + case wxINTERPOLATION_BEST: + quality = kCGInterpolationHigh; + break; + default: + return false; + } + CGContextSetInterpolationQuality(m_cgContext, quality); + CheckInvariants(); return true; } bool wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op) { - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return true; 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 ) + + // TODO REMOVE if we don't need it because of bugs in 10.5 +#if 0 { CGCompositeOperation cop = kCGCompositeOperationSourceOver; CGBlendMode mode = kCGBlendModeNormal; switch( op ) { case wxCOMPOSITION_CLEAR: - cop = kCGCompositeOperationClear; + cop = kCGCompositeOperationClear; break; case wxCOMPOSITION_SOURCE: - cop = kCGCompositeOperationCopy; + cop = kCGCompositeOperationCopy; break; case wxCOMPOSITION_OVER: - mode = kCGBlendModeNormal; + mode = kCGBlendModeNormal; break; case wxCOMPOSITION_IN: - cop = kCGCompositeOperationSourceIn; + cop = kCGCompositeOperationSourceIn; break; case wxCOMPOSITION_OUT: - cop = kCGCompositeOperationSourceOut; + cop = kCGCompositeOperationSourceOut; break; case wxCOMPOSITION_ATOP: - cop = kCGCompositeOperationSourceAtop; + cop = kCGCompositeOperationSourceAtop; break; case wxCOMPOSITION_DEST_OVER: - cop = kCGCompositeOperationDestinationOver; + cop = kCGCompositeOperationDestinationOver; break; case wxCOMPOSITION_DEST_IN: - cop = kCGCompositeOperationDestinationIn; + cop = kCGCompositeOperationDestinationIn; break; case wxCOMPOSITION_DEST_OUT: - cop = kCGCompositeOperationDestinationOut; + cop = kCGCompositeOperationDestinationOut; break; case wxCOMPOSITION_DEST_ATOP: - cop = kCGCompositeOperationDestinationAtop; + cop = kCGCompositeOperationDestinationAtop; break; case wxCOMPOSITION_XOR: - cop = kCGCompositeOperationXOR; + 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; } @@ -1764,46 +1884,44 @@ bool wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op) CGContextSetBlendMode(m_cgContext, mode); } #endif -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 - else { CGBlendMode mode = kCGBlendModeNormal; switch( op ) { case wxCOMPOSITION_CLEAR: - mode = kCGBlendModeClear; + mode = kCGBlendModeClear; break; case wxCOMPOSITION_SOURCE: - mode = kCGBlendModeCopy; + mode = kCGBlendModeCopy; break; case wxCOMPOSITION_OVER: - mode = kCGBlendModeNormal; + mode = kCGBlendModeNormal; break; case wxCOMPOSITION_IN: - mode = kCGBlendModeSourceIn; + mode = kCGBlendModeSourceIn; break; case wxCOMPOSITION_OUT: - mode = kCGBlendModeSourceOut; + mode = kCGBlendModeSourceOut; break; case wxCOMPOSITION_ATOP: - mode = kCGBlendModeSourceAtop; + mode = kCGBlendModeSourceAtop; break; case wxCOMPOSITION_DEST_OVER: - mode = kCGBlendModeDestinationOver; + mode = kCGBlendModeDestinationOver; break; case wxCOMPOSITION_DEST_IN: - mode = kCGBlendModeDestinationIn; + mode = kCGBlendModeDestinationIn; break; case wxCOMPOSITION_DEST_OUT: - mode = kCGBlendModeDestinationOut; + mode = kCGBlendModeDestinationOut; break; case wxCOMPOSITION_DEST_ATOP: - mode = kCGBlendModeDestinationAtop; + mode = kCGBlendModeDestinationAtop; break; case wxCOMPOSITION_XOR: - mode = kCGBlendModeXOR; + mode = kCGBlendModeExclusion; // Not kCGBlendModeXOR! break; - + case wxCOMPOSITION_ADD: mode = kCGBlendModePlusLighter ; break; @@ -1812,25 +1930,31 @@ bool wxMacCoreGraphicsContext::SetCompositionMode(wxCompositionMode op) } CGContextSetBlendMode(m_cgContext, mode); } -#endif + + CheckInvariants(); return true; } void wxMacCoreGraphicsContext::BeginLayer(wxDouble opacity) { + CheckInvariants(); CGContextSaveGState(m_cgContext); CGContextSetAlpha(m_cgContext, (CGFloat) opacity); CGContextBeginTransparencyLayer(m_cgContext, 0); + CheckInvariants(); } void wxMacCoreGraphicsContext::EndLayer() { + CheckInvariants(); CGContextEndTransparencyLayer(m_cgContext); CGContextRestoreGState(m_cgContext); + CheckInvariants(); } void wxMacCoreGraphicsContext::Clip( const wxRegion ®ion ) { + CheckInvariants(); #if wxOSX_USE_COCOA_OR_CARBON if( m_cgContext ) { @@ -1861,11 +1985,13 @@ void wxMacCoreGraphicsContext::Clip( const wxRegion ®ion ) // allow usage as measuring context // wxASSERT_MSG( m_cgContext != NULL, "Needs a valid context for clipping" ); #endif + CheckInvariants(); } // clips drawings to the rect void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { + CheckInvariants(); CGRect r = CGRectMake( (CGFloat) x , (CGFloat) y , (CGFloat) w , (CGFloat) h ); if ( m_cgContext ) { @@ -1877,12 +2003,14 @@ void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDoubl // the clipping itself must be stored as device coordinates, otherwise // we cannot apply it back correctly r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform ); + r.size= CGSizeApplyAffineTransform(r.size, m_windowTransform); m_clipRgn.reset(HIShapeCreateWithRect(&r)); #else // allow usage as measuring context // wxFAIL_MSG( "Needs a valid context for clipping" ); #endif } + CheckInvariants(); } // resets the clipping to original extent @@ -1909,6 +2037,7 @@ void wxMacCoreGraphicsContext::ResetClip() // wxFAIL_MSG( "Needs a valid context for clipping" ); #endif } + CheckInvariants(); } void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) @@ -1916,9 +2045,9 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) if ( m_pen.IsNull() ) return ; - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; - + if (m_composition == wxCOMPOSITION_DEST) return; @@ -1927,13 +2056,15 @@ void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ) ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextStrokePath( m_cgContext ); + + CheckInvariants(); } void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle ) { - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; - + if (m_composition == wxCOMPOSITION_DEST) return; @@ -1980,6 +2111,8 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , wxPolygonF CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextDrawPath( m_cgContext , mode ); + + CheckInvariants(); } void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonFillMode fillStyle ) @@ -1987,9 +2120,9 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF if ( m_brush.IsNull() ) return; - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; - + if (m_composition == wxCOMPOSITION_DEST) return; @@ -2010,6 +2143,8 @@ void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , wxPolygonF else CGContextFillPath( m_cgContext ); } + + CheckInvariants(); } void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ) @@ -2019,13 +2154,11 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ) if ( m_cgContext ) { + CheckInvariants(); CGContextRestoreGState( m_cgContext ); CGContextRestoreGState( m_cgContext ); if ( m_contextSynthesized ) { - // TODO: in case of performance problems, try issuing this not too - // frequently (half of refresh rate) - CGContextFlush(m_cgContext); #if wxOSX_USE_CARBON QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext); #endif @@ -2088,19 +2221,19 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; if (m_composition == wxCOMPOSITION_DEST) return; - + #ifdef __WXMAC__ - wxMacCoreGraphicsBitmapData* refdata =static_cast(bmp.GetRefData()); + wxMacCoreGraphicsBitmapData* refdata = static_cast(bmp.GetRefData()); CGImageRef image = refdata->GetBitmap(); CGRect r = CGRectMake( (CGFloat) x , (CGFloat) y , (CGFloat) w , (CGFloat) h ); if ( refdata->IsMonochrome() == 1 ) { - // is is a mask, the '1' in the mask tell where to draw the current brush + // is a mask, the '1' in the mask tell where to draw the current brush if ( !m_brush.IsNull() ) { if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) @@ -2126,40 +2259,44 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble wxMacDrawCGImage( m_cgContext , &r , image ); } #endif + + CheckInvariants(); } void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) { - if (EnsureIsValid()==false) + 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_COCOA_OR_CARBON + CGRect r = CGRectMake( (CGFloat) 0.0 , (CGFloat) 0.0 , (CGFloat) w , (CGFloat) h ); PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone , NULL , kPlotIconRefNormalFlags , icon.GetHICON() ); #endif CGContextRestoreGState( m_cgContext ); + + CheckInvariants(); } void wxMacCoreGraphicsContext::PushState() { - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; - + CGContextSaveGState( m_cgContext ); } void wxMacCoreGraphicsContext::PopState() { - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; - + CGContextRestoreGState( m_cgContext ); } @@ -2167,23 +2304,28 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo { wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); - if (EnsureIsValid()==false) + if (!EnsureIsValid()) 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->OSXGetCTFont(); CGColorRef col = wxMacCreateCGColor( fref->GetColour() ); +#if 0 + // right now there's no way to get continuous underlines, only words, so we emulate it CTUnderlineStyle ustyle = fref->GetUnderlined() ? kCTUnderlineStyleSingle : kCTUnderlineStyleNone ; wxCFRef underlined( CFNumberCreate(NULL, kCFNumberSInt32Type, &ustyle) ); CFStringRef keys[] = { kCTFontAttributeName , kCTForegroundColorAttributeName, kCTUnderlineStyleAttributeName }; CFTypeRef values[] = { font, col, underlined }; +#else + CFStringRef keys[] = { kCTFontAttributeName , kCTForegroundColorAttributeName }; + CFTypeRef values[] = { font, col }; +#endif wxCFRef attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values, WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) ); wxCFRef attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) ); @@ -2192,12 +2334,30 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo y += CTFontGetAscent(font); CGContextSaveGState(m_cgContext); + CGAffineTransform textMatrix = CGContextGetTextMatrix(m_cgContext); + CGContextTranslateCTM(m_cgContext, (CGFloat) x, (CGFloat) y); CGContextScaleCTM(m_cgContext, 1, -1); - CGContextSetTextPosition(m_cgContext, 0, 0); + CGContextSetTextMatrix(m_cgContext, CGAffineTransformIdentity); + CTLineDraw( line, m_cgContext ); + + if ( fref->GetUnderlined() ) { + //AKT: draw horizontal line 1 pixel thick and with 1 pixel gap under baseline + CGFloat width = CTLineGetTypographicBounds(line, NULL, NULL, NULL); + + CGPoint points[] = { {0.0, -2.0}, {width, -2.0} }; + + CGContextSetStrokeColorWithColor(m_cgContext, col); + CGContextSetShouldAntialias(m_cgContext, false); + CGContextSetLineWidth(m_cgContext, 1.0); + CGContextStrokeLineSegments(m_cgContext, points, 2); + } + CGContextRestoreGState(m_cgContext); - CFRelease( col ); + CGContextSetTextMatrix(m_cgContext, textMatrix); + CGColorRelease( col ); + CheckInvariants(); return; } #endif @@ -2222,6 +2382,8 @@ void wxMacCoreGraphicsContext::DoDrawText( const wxString &str, wxDouble x, wxDo CGContextRestoreGState(m_cgContext); CFRelease( col ); #endif + + CheckInvariants(); } void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, @@ -2230,14 +2392,13 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, { wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") ); - if (EnsureIsValid()==false) + if (!EnsureIsValid()) return; - + 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::DoDrawRotatedText( str, x, y, angle ); @@ -2268,15 +2429,15 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, { 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 ); } @@ -2285,15 +2446,15 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, { 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 ); } @@ -2306,8 +2467,8 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") ); Rect rect; - x += (int)(sin(angle) * FixedToInt(ascent)); - y += (int)(cos(angle) * FixedToInt(ascent)); + x += (int)(sin(angle) * FixedToFloat(ascent)); + y += (int)(cos(angle) * FixedToFloat(ascent)); status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, IntToFixed(x) , IntToFixed(y) , &rect ); @@ -2324,6 +2485,7 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, CGContextRestoreGState(m_cgContext); ::ATSUDisposeTextLayout(atsuLayout); + CheckInvariants(); return; } @@ -2332,6 +2494,8 @@ void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str, // default implementation takes care of rotation and calls non rotated DrawText afterwards wxGraphicsContext::DoDrawRotatedText( str, x, y, angle ); #endif + + CheckInvariants(); } void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, @@ -2352,7 +2516,6 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid return; #if wxOSX_USE_CORE_TEXT - if ( UMAGetSystemVersion() >= 0x1050 ) { wxMacCoreGraphicsFontData* fref = (wxMacCoreGraphicsFontData*)m_font.GetRefData(); CTFontRef font = fref->OSXGetCTFont(); @@ -2365,10 +2528,8 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid wxCFRef attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) ); wxCFRef line( CTLineCreateWithAttributedString(attrtext) ); - double w; - CGFloat a, d, l; - - w = CTLineGetTypographicBounds(line, &a, &d, &l) ; + CGFloat a, d, l, w; + w = CTLineGetTypographicBounds(line, &a, &d, &l); if ( height ) *height = a+d+l; @@ -2405,13 +2566,13 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid &textBefore , &textAfter, &textAscent , &textDescent ); if ( height ) - *height = FixedToInt(textAscent + textDescent); + *height = FixedToFloat(textAscent + textDescent); if ( descent ) - *descent = FixedToInt(textDescent); + *descent = FixedToFloat(textDescent); if ( externalLeading ) *externalLeading = 0; if ( width ) - *width = FixedToInt(textAfter - textBefore); + *width = FixedToFloat(textAfter - textBefore); ::ATSUDisposeTextLayout(atsuLayout); @@ -2428,13 +2589,15 @@ void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *wid *height = sz.height; /* if ( descent ) - *descent = FixedToInt(textDescent); + *descent = FixedToFloat(textDescent); if ( externalLeading ) *externalLeading = 0; */ if ( width ) *width = sz.width; #endif + + CheckInvariants(); } void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const @@ -2463,7 +2626,7 @@ 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; @@ -2499,7 +2662,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr if (result != noErr || actualNumberOfBounds != 1 ) return; - widths[pos] = FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ); + widths[pos] = FixedToFloat( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ); //unsigned char uch = s[i]; } #else @@ -2519,7 +2682,7 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr { for ( int pos = 1; pos < (int)glyphCount ; pos ++ ) { - widths[pos-1] = FixedToInt( layoutRecords[pos].realPos ); + widths[pos-1] = FixedToFloat( layoutRecords[pos].realPos ); } } @@ -2533,6 +2696,8 @@ void wxMacCoreGraphicsContext::GetPartialTextExtents(const wxString& text, wxArr #if wxOSX_USE_IPHONE // TODO core graphics text implementation here #endif + + CheckInvariants(); } void * wxMacCoreGraphicsContext::GetNativeContext() @@ -2540,18 +2705,50 @@ void * wxMacCoreGraphicsContext::GetNativeContext() return m_cgContext; } + +void wxMacCoreGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + if (!EnsureIsValid()) + return; + + if (m_composition == wxCOMPOSITION_DEST) + return; + + // when using shading, we have to go back to drawing paths + if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) + { + wxGraphicsContext::DrawRectangle( x,y,w,h ); + return; + } + + CGRect rect = CGRectMake( (CGFloat) x , (CGFloat) y , (CGFloat) w , (CGFloat) h ); + if ( !m_brush.IsNull() ) + { + ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this); + CGContextFillRect(m_cgContext, rect); + } + + wxQuartzOffsetHelper helper( m_cgContext , ShouldOffset() ); + if ( !m_pen.IsNull() ) + { + ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this); + CGContextStrokeRect(m_cgContext, rect); + } +} + // concatenates this transform with the current transform of this context 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 void wxMacCoreGraphicsContext::SetTransform( const wxGraphicsMatrix& matrix ) { + CheckInvariants(); if ( m_cgContext ) { CGAffineTransform transform = CGContextGetCTM( m_cgContext ); @@ -2563,6 +2760,7 @@ void wxMacCoreGraphicsContext::SetTransform( const wxGraphicsMatrix& matrix ) { m_windowTransform = *(CGAffineTransform*) matrix.GetNativeMatrix(); } + CheckInvariants(); } // gets the matrix of this context @@ -2574,6 +2772,49 @@ wxGraphicsMatrix wxMacCoreGraphicsContext::GetTransform() const return m; } + +#if wxUSE_IMAGE + +// ---------------------------------------------------------------------------- +// wxMacCoreGraphicsImageContext +// ---------------------------------------------------------------------------- + +// This is a GC that can be used to draw on wxImage. In this implementation we +// simply draw on a wxBitmap using wxMemoryDC and then convert it to wxImage in +// the end so it's not especially interesting and exists mainly for +// compatibility with the other platforms. +class wxMacCoreGraphicsImageContext : public wxMacCoreGraphicsContext +{ +public: + wxMacCoreGraphicsImageContext(wxGraphicsRenderer* renderer, + wxImage& image) : + wxMacCoreGraphicsContext(renderer), + m_image(image), + m_bitmap(image), + m_memDC(m_bitmap) + { + SetNativeContext + ( + (CGContextRef)(m_memDC.GetGraphicsContext()->GetNativeContext()) + ); + m_width = image.GetWidth(); + m_height = image.GetHeight(); + } + + virtual ~wxMacCoreGraphicsImageContext() + { + m_memDC.SelectObject(wxNullBitmap); + m_image = m_bitmap.ConvertToImage(); + } + +private: + wxImage& m_image; + wxBitmap m_bitmap; + wxMemoryDC m_memDC; +}; + +#endif // wxUSE_IMAGE + // // Renderer // @@ -2603,6 +2844,10 @@ public : virtual wxGraphicsContext * CreateContext( wxWindow* window ); +#if wxUSE_IMAGE + virtual wxGraphicsContext * CreateContextFromImage(wxImage& image); +#endif // wxUSE_IMAGE + virtual wxGraphicsContext * CreateMeasuringContext(); // Path @@ -2619,21 +2864,35 @@ 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 ) ; + virtual wxGraphicsFont CreateFont(double sizeInPixels, + const wxString& facename, + int flags = wxFONTFLAG_DEFAULT, + const wxColour& col = *wxBLACK); // create a native bitmap representation virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) ; +#if wxUSE_IMAGE + virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image); + virtual wxImage CreateImageFromBitmap(const wxGraphicsBitmap& bmp); +#endif // wxUSE_IMAGE + + // 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 : @@ -2667,8 +2926,12 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& if (win_impl->GetWindow()) cgctx = (CGContextRef)(win_impl->GetWindow()->MacGetCGContextRef()); - if (cgctx != 0) - return new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h ); + // having a cgctx being NULL is fine (will be created on demand) + // this is the case for all wxWindowDCs except wxPaintDC + wxMacCoreGraphicsContext *context = + new wxMacCoreGraphicsContext( this, cgctx, (wxDouble) w, (wxDouble) h ); + context->EnableOffset(true); + return context; } return NULL; } @@ -2682,8 +2945,10 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxMemoryDC& { int w, h; mem_impl->GetSize( &w, &h ); - return new wxMacCoreGraphicsContext( this, + wxMacCoreGraphicsContext* context = new wxMacCoreGraphicsContext( this, (CGContextRef)(mem_impl->GetGraphicsContext()->GetNativeContext()), (wxDouble) w, (wxDouble) h ); + context->EnableOffset(true); + return context; } #endif return NULL; @@ -2715,7 +2980,9 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeContext( v wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContextFromNativeWindow( void * window ) { #if wxOSX_USE_CARBON - return new wxMacCoreGraphicsContext(this,(WindowRef)window); + wxMacCoreGraphicsContext* context = new wxMacCoreGraphicsContext(this,(WindowRef)window); + context->EnableOffset(true); + return context; #else wxUnusedVar(window); return NULL; @@ -2732,6 +2999,16 @@ wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateMeasuringContext() return new wxMacCoreGraphicsContext(this); } +#if wxUSE_IMAGE + +wxGraphicsContext* +wxMacCoreGraphicsRenderer::CreateContextFromImage(wxImage& image) +{ + return new wxMacCoreGraphicsImageContext(this, image); +} + +#endif // wxUSE_IMAGE + // Path wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath() @@ -2756,7 +3033,7 @@ wxGraphicsMatrix wxMacCoreGraphicsRenderer::CreateMatrix( wxDouble a, wxDouble b wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen) { - if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) + if ( !pen.IsOk() || pen.GetStyle() == wxTRANSPARENT ) return wxNullGraphicsPen; else { @@ -2768,7 +3045,7 @@ wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen) wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush ) { - if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) + if ( !brush.IsOk() || brush.GetStyle() == wxTRANSPARENT ) return wxNullGraphicsBrush; else { @@ -2780,12 +3057,44 @@ wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush ) wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmap( const wxBitmap& bmp ) { - if ( bmp.Ok() ) + if ( bmp.IsOk() ) { wxGraphicsBitmap p; -#ifdef __WXMAC__ p.SetRefData(new wxMacCoreGraphicsBitmapData( this , bmp.CreateCGImage(), bmp.GetDepth() == 1 ) ); -#endif + return p; + } + else + return wxNullGraphicsBitmap; +} + +#if wxUSE_IMAGE + +wxGraphicsBitmap +wxMacCoreGraphicsRenderer::CreateBitmapFromImage(const wxImage& image) +{ + // We don't have any direct way to convert wxImage to CGImage so pass by + // wxBitmap. This makes this function pretty useless in this implementation + // but it allows to have the same API as with Cairo backend where we can + // convert wxImage to a Cairo surface directly, bypassing wxBitmap. + return CreateBitmap(wxBitmap(image)); +} + +wxImage wxMacCoreGraphicsRenderer::CreateImageFromBitmap(const wxGraphicsBitmap& bmp) +{ + wxMacCoreGraphicsBitmapData* const + data = static_cast(bmp.GetRefData()); + + return data ? data->ConvertToImage() : wxNullImage; +} + +#endif // wxUSE_IMAGE + +wxGraphicsBitmap wxMacCoreGraphicsRenderer::CreateBitmapFromNativeBitmap( void* bitmap ) +{ + if ( bitmap != NULL ) + { + wxGraphicsBitmap p; + p.SetRefData(new wxMacCoreGraphicsBitmapData( this , (CGImageRef) bitmap, false )); return p; } else @@ -2807,33 +3116,34 @@ 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; } -// sets the font wxGraphicsFont wxMacCoreGraphicsRenderer::CreateFont( const wxFont &font , const wxColour &col ) { - if ( font.Ok() ) + if ( font.IsOk() ) { wxGraphicsFont p; p.SetRefData(new wxMacCoreGraphicsFontData( this , font, col )); @@ -2843,6 +3153,32 @@ wxGraphicsFont wxMacCoreGraphicsRenderer::CreateFont( const wxFont &font , const return wxNullGraphicsFont; } +wxGraphicsFont +wxMacCoreGraphicsRenderer::CreateFont(double sizeInPixels, + const wxString& facename, + int flags, + const wxColour& col) +{ + // This implementation is not ideal as we don't support fractional font + // sizes right now, but it's the simplest one. + // + // Notice that under Mac we always use 72 DPI so the font size in pixels is + // the same as the font size in points and we can pass it directly to wxFont + // ctor. + wxFont font(wxRound(sizeInPixels), + wxFONTFAMILY_DEFAULT, + flags & wxFONTFLAG_ITALIC ? wxFONTSTYLE_ITALIC + : wxFONTSTYLE_NORMAL, + flags & wxFONTFLAG_BOLD ? wxFONTWEIGHT_BOLD + : wxFONTWEIGHT_NORMAL, + (flags & wxFONTFLAG_UNDERLINED) != 0, + facename); + + wxGraphicsFont f; + f.SetRefData(new wxMacCoreGraphicsFontData(this, font, col)); + return f; +} + // // CoreGraphics Helper Methods //