/////////////////////////////////////////////////////////////////////////////
-// Name: src/osx/carbon/dccg.cpp
+// Name: src/osx/carbon/graphics.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
/////////////////////////////////////////////////////////////////////////////
#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"
#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
+
//-----------------------------------------------------------------------------
// 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;
#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
}
}
#endif
+ wxASSERT(retval != NULL);
return retval;
}
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
public :
ImagePattern( const wxBitmap* bmp , const CGAffineTransform& transform )
{
- wxASSERT( bmp && bmp->Ok() );
+ wxASSERT( bmp && bmp->IsOk() );
#ifdef __WXMAC__
Init( (CGImageRef) bmp->CreateCGImage() , transform );
#endif
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))
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 ) ) ) );
}
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 );
}
}
// 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
{
// 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] ;
~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();
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 )
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 ;
}
if( m_gradientFunction )
CGFunctionRelease(m_gradientFunction);
-
- delete[] m_gradientComponents;
}
void wxMacCoreGraphicsBrushData::Init()
{
m_gradientFunction = NULL;
m_shading = NULL;
- m_gradientComponents = NULL;
m_isShading = false;
}
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)
{
- out[i] = colors[i] + ( colors[4+i] - colors[i] ) * f;
+ // 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
+ {
+ // 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,
virtual ATSUStyle GetATSUStyle() { return m_macATSUIStyle; }
#endif
#if wxOSX_USE_CORE_TEXT
- CTFontRef GetCTFont() const { return m_ctFont ; }
+ CTFontRef OSXGetCTFont() const { return m_ctFont ; }
#endif
wxColour GetColour() const { return m_colour ; }
// 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[] =
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") );
virtual CGImageRef GetBitmap() { 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;
CGImageRelease( m_bitmap );
}
+
//
// Graphics Matrix
//
// 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
// 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 );
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, int fillStyle = wxODDEVEN_RULE) const;
+ virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxODDEVEN_RULE) const;
private :
CGMutablePathRef m_path;
};
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
*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 );
}
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();
virtual void * GetNativeContext();
- bool SetLogicalFunction( int function );
+ virtual bool SetAntialiasMode(wxAntialiasMode antialias);
+
+ virtual bool SetInterpolationQuality(wxInterpolationQuality interpolation);
+
+ virtual bool SetCompositionMode(wxCompositionMode op);
+
+ virtual void BeginLayer(wxDouble opacity);
+
+ virtual void EndLayer();
+
//
// transformation
//
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
{
+ if ( !m_enableOffset )
+ return false;
+
int penwidth = 0 ;
if ( !m_pen.IsNull() )
{
// 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;
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 DrawRectangleX( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
void SetNativeContext( CGContextRef cg );
- DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacCoreGraphicsContext)
+ wxDECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext);
private:
- void EnsureIsValid();
+ 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 );
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<HIShapeRef> m_clipRgn;
#endif
};
// wxMacCoreGraphicsContext implementation
//-----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
-
class wxQuartzOffsetHelper
{
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;
} ;
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;
+ m_antialias = wxANTIALIAS_DEFAULT;
+ m_interpolation = wxINTERPOLATION_DEFAULT;
}
wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext, wxDouble width, wxDouble height ) : wxGraphicsContext(renderer)
{
Init();
m_windowRef = window;
+ m_enableOffset = true;
}
#endif
{
Init();
+ m_enableOffset = true;
+ 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)
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;
CGContextFlush(m_cgContext);
}
-void wxMacCoreGraphicsContext::EnsureIsValid()
+bool wxMacCoreGraphicsContext::EnsureIsValid()
{
+ CheckInvariants();
+
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<HIMutableShapeRef> 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 );
+#if wxOSX_USE_COCOA_OR_CARBON
+ if ( m_clipRgn.get() )
{
- CGRect empty = CGRectMake( 0,0,0,0 );
- CGContextClipToRect( m_cgContext, empty );
+ wxCFRef<HIMutableShapeRef> hishape( HIShapeCreateMutableCopy( m_clipRgn ) );
+ // 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
+ 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 ;
+ 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
+ }
}
-}
+ CheckInvariants();
-// TODO test whether the private CGContextSetCompositeOperation works under 10.3 (using NSCompositingModes)
+ return m_cgContext != NULL;
+}
-bool wxMacCoreGraphicsContext::SetLogicalFunction( int function )
+bool wxMacCoreGraphicsContext::SetAntialiasMode(wxAntialiasMode antialias)
{
- if (m_logicalFunction == function)
+ if (!EnsureIsValid())
return true;
- EnsureIsValid();
+ if (m_antialias == antialias)
+ return true;
- bool retval = false;
- bool shouldAntiAlias = true;
- CGBlendMode mode = kCGBlendModeNormal;
+ m_antialias = antialias;
-#if defined(__WXMAC__) && ( wxOSX_USE_IPHONE || ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 ) )
-#if wxOSX_USE_IPHONE
- if ( 1 )
+ bool antialiasMode;
+ switch (antialias)
+ {
+ case wxANTIALIAS_DEFAULT:
+ antialiasMode = true;
+ break;
+ case wxANTIALIAS_NONE:
+ antialiasMode = false;
+ break;
+ default:
+ 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
- if ( UMAGetSystemVersion() >= 0x1050 )
+ 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())
+ 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 )
{
- 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 )
+ CGBlendMode mode = kCGBlendModeNormal;
+ switch( op )
{
- retval = true;
- }
- else if ( function == wxINVERT || function == wxXOR )
- {
- // 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
+ CheckInvariants();
+ return true;
+}
- if (retval)
- {
- m_logicalFunction = function;
- CGContextSetBlendMode( m_cgContext, mode );
- CGContextSetShouldAntialias(m_cgContext, shouldAntiAlias);
- }
- return retval ;
+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 )
{
-#if wxOSX_USE_CARBON
+ CheckInvariants();
+#if wxOSX_USE_COCOA_OR_CARBON
if( m_cgContext )
{
wxCFRef<HIShapeRef> shape = wxCFRefFromGet(region.GetWXHRGN());
// 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 )
{
}
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 );
+ 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
}
else
{
-#if wxOSX_USE_CARBON
+#if wxOSX_USE_COCOA_OR_CARBON
m_clipRgn.reset();
#else
// allow usage as measuring context
// wxFAIL_MSG( "Needs a valid context for clipping" );
#endif
}
+ CheckInvariants();
}
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() );
((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this);
CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
CGContextStrokePath( m_cgContext );
+
+ CheckInvariants();
}
-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
}
}
- EnsureIsValid();
-
if ( !m_brush.IsNull() )
((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this);
if ( !m_pen.IsNull() )
CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() );
CGContextDrawPath( m_cgContext , mode );
+
+ CheckInvariants();
}
-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() )
{
else
CGContextFillPath( m_cgContext );
}
+
+ CheckInvariants();
}
void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
if ( m_cgContext )
{
- // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext );
+ CheckInvariants();
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
CGContextSaveGState( m_cgContext );
CGContextSetTextMatrix( m_cgContext, CGAffineTransformIdentity );
CGContextSaveGState( m_cgContext );
- m_releaseContext = false;
+ m_contextSynthesized = false;
}
}
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<wxMacCoreGraphicsBitmapData*>(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() )
wxMacDrawCGImage( m_cgContext , &r , image );
}
#endif
+
+ CheckInvariants();
}
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 );
+
+ CheckInvariants();
}
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 )
{
wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") );
- EnsureIsValid();
+ 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->GetCTFont();
+ 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<CFNumberRef> 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<CFDictionaryRef> attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**) &keys, (const void**) &values,
WXSIZEOF( keys ), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) );
wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
y += CTFontGetAscent(font);
CGContextSaveGState(m_cgContext);
- CGContextTranslateCTM(m_cgContext, x, y);
+ 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);
+ CGContextSetTextMatrix(m_cgContext, textMatrix);
CFRelease( col );
+ CheckInvariants();
return;
}
#endif
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() );
CGContextRestoreGState(m_cgContext);
CFRelease( col );
#endif
+
+ CheckInvariants();
}
-void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
+void wxMacCoreGraphicsContext::DoDrawRotatedText(const wxString &str,
+ wxDouble x, wxDouble y,
+ wxDouble angle)
{
wxCHECK_RET( !m_font.IsNull(), wxT("wxMacCoreGraphicsContext::DrawText - no valid font set") );
- EnsureIsValid();
+ 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::DrawText( str, x, y, angle );
+ wxGraphicsContext::DoDrawRotatedText( str, x, y, angle );
return;
}
#endif
{
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 );
}
{
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 );
}
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 );
CGContextRestoreGState(m_cgContext);
::ATSUDisposeTextLayout(atsuLayout);
+ CheckInvariants();
return;
}
#endif
#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
+
+ CheckInvariants();
}
void wxMacCoreGraphicsContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
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 };
wxCFRef<CFAttributedStringRef> attrtext( CFAttributedStringCreate(kCFAllocatorDefault, text, attributes) );
wxCFRef<CTLineRef> line( CTLineCreateWithAttributedString(attrtext) );
- CGFloat w, 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;
&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);
wxCFStringRef text(str, wxLocale::GetSystemEncoding() );
CGSize sz = MeasureTextInContext( fref->GetUIFont() , text.AsNSString() );
-
+
if ( height )
*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
#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 };
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;
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
ATSLayoutRecord *layoutRecords = NULL;
ItemCount glyphCount = 0;
-
+
// Get the glyph extents
OSStatus err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(atsuLayout,
0,
&layoutRecords,
&glyphCount);
wxASSERT(glyphCount == (text.length()+1));
-
+
if ( err == noErr && glyphCount == (text.length()+1))
{
for ( int pos = 1; pos < (int)glyphCount ; pos ++ )
{
- widths[pos-1] = FixedToInt( layoutRecords[pos].realPos );
+ widths[pos-1] = FixedToFloat( layoutRecords[pos].realPos );
}
}
-
+
::ATSUDirectReleaseLayoutDataArrayPtr(NULL,
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void **) &layoutRecords);
#if wxOSX_USE_IPHONE
// TODO core graphics text implementation here
#endif
+
+ CheckInvariants();
}
void * wxMacCoreGraphicsContext::GetNativeContext()
return m_cgContext;
}
+
+void wxMacCoreGraphicsContext::DrawRectangleX( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
+{
+ if (m_composition == wxCOMPOSITION_DEST)
+ 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 );
{
m_windowTransform = *(CGAffineTransform*) matrix.GetNativeMatrix();
}
+ CheckInvariants();
}
// gets the matrix of this context
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
//
virtual wxGraphicsContext * CreateContext( wxWindow* window );
+#if wxUSE_IMAGE
+ virtual wxGraphicsContext * CreateContextFromImage(wxImage& image);
+#endif // wxUSE_IMAGE
+
virtual wxGraphicsContext * CreateMeasuringContext();
// Path
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 :
return &gs_MacCoreGraphicsRenderer;
}
-#if defined( __WXCOCOA__ ) || wxOSX_USE_COCOA
-extern CGContextRef wxMacGetContextFromCurrentNSContext() ;
-#endif
-
wxGraphicsContext * wxMacCoreGraphicsRenderer::CreateContext( const wxWindowDC& dc )
{
const wxDCImpl* impl = dc.GetImpl();
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());
+
+ // 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;
}
{
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;
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;
#endif
}
return new wxMacCoreGraphicsContext(this);
}
+#if wxUSE_IMAGE
+
+wxGraphicsContext*
+wxMacCoreGraphicsRenderer::CreateContextFromImage(wxImage& image)
+{
+ return new wxMacCoreGraphicsImageContext(this, image);
+}
+
+#endif // wxUSE_IMAGE
+
// Path
wxGraphicsPath wxMacCoreGraphicsRenderer::CreatePath()
wxGraphicsPen wxMacCoreGraphicsRenderer::CreatePen(const wxPen& pen)
{
- if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
+ if ( !pen.IsOk() || pen.GetStyle() == wxTRANSPARENT )
return wxNullGraphicsPen;
else
{
wxGraphicsBrush wxMacCoreGraphicsRenderer::CreateBrush(const wxBrush& brush )
{
- if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
+ if ( !brush.IsOk() || brush.GetStyle() == wxTRANSPARENT )
return wxNullGraphicsBrush;
else
{
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<wxMacCoreGraphicsBitmapData*>(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
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 ));
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
//