]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/graphicc.cpp
build fix for wxUSE_LOG==0
[wxWidgets.git] / src / generic / graphicc.cpp
index 70cd642a7d9978f083bd9384429ec2f40128c15a..942357e984a6681ff53856db058ccfe9d0799c2c 100644 (file)
 
 #include "wx/graphics.h"
 
+#if wxUSE_CAIRO
+
+#include "wx/cairo.h"
+
 #ifndef WX_PRECOMP
     #include "wx/bitmap.h"
     #include "wx/icon.h"
     #include "wx/dcclient.h"
     #include "wx/dcmemory.h"
     #include "wx/dcprint.h"
+    #ifdef __WXGTK__
+        #include "wx/window.h"
+    #endif
 #endif
 
 #include "wx/private/graphics.h"
@@ -60,6 +67,10 @@ using namespace std;
 #endif
 
 #include <cairo.h>
+#ifdef __WXMSW__
+#include <cairo-win32.h>
+#endif
+
 #ifdef __WXGTK__
 #include <gtk/gtk.h>
 #include "wx/fontutil.h"
@@ -240,14 +251,20 @@ public:
     ~wxCairoBrushData ();
 
     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);
 
 protected:
     virtual void Init();
 
+    // common part of Create{Linear,Radial}GradientBrush()
+    void AddGradientStops(const wxGraphicsGradientStops& stops);
+
 private :
     double m_red;
     double m_green;
@@ -284,12 +301,16 @@ private :
     cairo_font_slant_t m_slant;
     cairo_font_weight_t m_weight;
 #endif
+#ifdef __WXMSW__
+    wxCairoContext( wxGraphicsRenderer* renderer, HDC context );
+#endif
 };
 
 class wxCairoBitmapData : public wxGraphicsObjectRefData
 {
 public:
     wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp );
+    wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap );
     ~wxCairoBitmapData();
 
     virtual cairo_surface_t* GetCairoSurface() { return m_surface; }
@@ -330,6 +351,9 @@ public:
     }
 
     virtual void Clip( const wxRegion &region );
+#ifdef __WXMSW__
+    cairo_surface_t* m_mswSurface;
+#endif
 
     // clips drawings to the rect
     virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
@@ -346,7 +370,7 @@ public:
     virtual void BeginLayer(wxDouble opacity);
 
     virtual void EndLayer();
-    
+
     virtual void StrokePath( const wxGraphicsPath& p );
     virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxWINDING_RULE );
 
@@ -363,6 +387,7 @@ public:
     // gets the matrix of this context
     virtual wxGraphicsMatrix GetTransform() const;
 
+    virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
     virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
     virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
     virtual void PushState();
@@ -379,7 +404,7 @@ private:
     void Init(cairo_t *context);
 
     cairo_t* m_context;
-    
+
     wxVector<float> m_layerOpacities;
 
     wxDECLARE_NO_COPY_CLASS(wxCairoContext);
@@ -667,26 +692,50 @@ void wxCairoBrushData::Apply( wxGraphicsContext* context )
     }
 }
 
-void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
-        const wxColour&c1, const wxColour&c2 )
+void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops)
+{
+    // loop over all the stops, they include the beginning and ending ones
+    const unsigned numStops = stops.GetCount();
+    for ( unsigned n = 0; n < numStops; n++ )
+    {
+        const wxGraphicsGradientStop stop = stops.Item(n);
+
+        const wxColour col = stop.GetColour();
+
+        cairo_pattern_add_color_stop_rgba
+        (
+            m_brushPattern,
+            stop.GetPosition(),
+            col.Red()/255.0,
+            col.Green()/255.0,
+            col.Blue()/255.0,
+            col.Alpha()/255.0
+        );
+    }
+
+    wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS,
+                 wxT("Couldn't create cairo pattern"));
+}
+
+void
+wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                                            wxDouble x2, wxDouble y2,
+                                            const wxGraphicsGradientStops& stops)
 {
     m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2);
-    cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,c1.Red()/255.0,
-        c1.Green()/255.0, c1.Blue()/255.0,c1.Alpha()/255.0);
-    cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,c2.Red()/255.0,
-        c2.Green()/255.0, c2.Blue()/255.0,c2.Alpha()/255.0);
-    wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern"));
+
+    AddGradientStops(stops);
 }
 
-void wxCairoBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-        const wxColour &oColor, const wxColour &cColor )
+void
+wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                                            wxDouble xc, wxDouble yc,
+                                            wxDouble radius,
+                                            const wxGraphicsGradientStops& stops)
 {
     m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
-    cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,oColor.Red()/255.0,
-        oColor.Green()/255.0, oColor.Blue()/255.0,oColor.Alpha()/255.0);
-    cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,cColor.Red()/255.0,
-        cColor.Green()/255.0, cColor.Blue()/255.0,cColor.Alpha()/255.0);
-    wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern"));
+
+    AddGradientStops(stops);
 }
 
 void wxCairoBrushData::Init()
@@ -739,7 +788,7 @@ void wxCairoFontData::Apply( wxGraphicsContext* context )
     cairo_set_font_face(ctext, m_font);
     cairo_set_font_size(ctext, m_size );
 #else
-    cairo_select_font_face(ctext, m_fontName, m_slant, m_weights );
+    cairo_select_font_face(ctext, m_fontName, m_slant, m_weight );
     cairo_set_font_size(ctext, m_size );
 #endif
 }
@@ -883,9 +932,10 @@ void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h)
     }
 }
 
-bool wxCairoPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode WXUNUSED(fillStyle) ) const
+bool wxCairoPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
 {
-    return cairo_in_stroke( m_pathContext, x, y) != 0;
+    cairo_set_fill_rule(m_pathContext,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+    return cairo_in_fill( m_pathContext, x, y) != 0;
 }
 
 //-----------------------------------------------------------------------------
@@ -1013,13 +1063,20 @@ void * wxCairoMatrixData::GetNativeMatrix() const
 // wxCairoBitmap implementation
 //-----------------------------------------------------------------------------
 
+wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap ) :
+    wxGraphicsObjectRefData( renderer )
+{
+    m_surface = bitmap;
+    m_pattern = cairo_pattern_create_for_surface(m_surface);
+}
+
 wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsObjectRefData( renderer )
 {
     wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
 
-    cairo_surface_t* surface;
-    int bw = bmp.GetWidth();
-    int bh = bmp.GetHeight();
+#ifdef wxHAS_RAW_BITMAP
+    int bw = m_width = bmp.GetWidth();
+    int bh = m_height = bmp.GetHeight();
     wxBitmap bmpSource = bmp;  // we need a non-const instance
     m_buffer = new unsigned char[bw*bh*4];
     wxUint32* data = (wxUint32*)m_buffer;
@@ -1084,12 +1141,18 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm
             p.OffsetY(pixData, 1);
         }
     }
+    m_pattern = cairo_pattern_create_for_surface(m_surface);
+#endif // wxHAS_RAW_BITMAP
 }
 
 wxCairoBitmapData::~wxCairoBitmapData()
 {
-    cairo_pattern_destroy(m_pattern);
-    cairo_surface_destroy(m_surface);
+    if (m_pattern)
+        cairo_pattern_destroy(m_pattern);
+
+    if (m_surface)
+        cairo_surface_destroy(m_surface);
+
     delete [] m_buffer;
 }
 
@@ -1126,6 +1189,10 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC&
     const wxDCImpl *impl = dc.GetImpl();
     Init( (cairo_t*) impl->GetCairoContext() );
 
+    wxSize sz = dc.GetSize();
+    m_width = sz.x;
+    m_height = sz.y;
+
     wxPoint org = dc.GetDeviceOrigin();
     cairo_translate( m_context, org.x, org.y );
 
@@ -1141,6 +1208,11 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC&
 wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc )
 : wxGraphicsContext(renderer)
 {
+    int width, height;
+    dc.GetSize( &width, &height );
+    m_width = width;
+    m_height = height;
+
 #ifdef __WXGTK20__
     wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
     Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
@@ -1163,8 +1235,6 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC&
 #endif
 
 #ifdef __WXMAC__
-    int width, height;
-    dc.GetSize( &width, &height );
     CGContextRef cgcontext = (CGContextRef)dc.GetWindow()->MacGetCGContextRef();
     cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(cgcontext, width, height);
     Init( cairo_create( surface ) );
@@ -1175,6 +1245,11 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC&
 wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc )
 : wxGraphicsContext(renderer)
 {
+    int width, height;
+    dc.GetSize( &width, &height );
+    m_width = width;
+    m_height = height;
+
 #ifdef __WXGTK20__
     wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
     Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
@@ -1197,8 +1272,6 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC&
 #endif
 
 #ifdef __WXMAC__
-    int width, height;
-    dc.GetSize( &width, &height );
     CGContextRef cgcontext = (CGContextRef)dc.GetWindow()->MacGetCGContextRef();
     cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(cgcontext, width, height);
     Init( cairo_create( surface ) );
@@ -1211,13 +1284,32 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawa
 : wxGraphicsContext(renderer)
 {
     Init( gdk_cairo_create( drawable ) );
+
+    int width, height;
+    gdk_drawable_get_size( drawable, &width, &height );
+    m_width = width;
+    m_height = height;
+}
+#endif
+
+#ifdef __WXMSW__
+wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, HDC handle )
+: wxGraphicsContext(renderer)
+{
+    m_mswSurface = cairo_win32_surface_create(handle);
+    Init( cairo_create(m_mswSurface) );
+    m_width =
+    m_height = 0;
 }
 #endif
 
+
 wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context )
 : wxGraphicsContext(renderer)
 {
     Init( context );
+    m_width =
+    m_height = 0;
 }
 
 wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window)
@@ -1237,6 +1329,10 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window)
     wxASSERT_MSG( window->m_wxwindow, wxT("wxCairoContext needs a widget") );
 
     Init(gdk_cairo_create(window->GTKGetDrawingWindow()));
+
+    wxSize sz = window->GetSize();
+    m_width = sz.x;
+    m_height = sz.y;
 #endif
 }
 
@@ -1245,9 +1341,17 @@ wxCairoContext::~wxCairoContext()
     if ( m_context )
     {
         PopState();
+#ifdef __WXMSW__
+    m_mswSurface = cairo_win32_surface_create((HDC)window->GetHandle());
+    m_context = cairo_create(m_mswSurface);
+#endif
         PopState();
         cairo_destroy(m_context);
     }
+#ifdef __WXMSW__
+    if ( m_mswSurface )
+        cairo_surface_destroy(m_mswSurface);
+#endif
 }
 
 void wxCairoContext::Init(cairo_t *context)
@@ -1393,10 +1497,10 @@ void wxCairoContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDoubl
 
     wxDouble scaleX = w / size.GetWidth();
     wxDouble scaleY = h / size.GetHeight();
-    cairo_scale(m_context, scaleX, scaleY);
 
     // prepare to draw the image
     cairo_translate(m_context, x, y);
+    cairo_scale(m_context, scaleX, scaleY);
     cairo_set_source(m_context, pattern);
     // use the original size here since the context is scaled already...
     cairo_rectangle(m_context, 0, 0, size.GetWidth(), size.GetHeight());
@@ -1436,8 +1540,8 @@ void wxCairoContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
     wxCairoFontData* font_data = (wxCairoFontData*) m_font.GetRefData();
     pango_layout_set_font_description( layout, font_data->GetFont());
     pango_layout_set_text(layout, data, datalen);
-    
-    if (font_data->GetUnderlined()) 
+
+    if (font_data->GetUnderlined())
     {
         PangoAttrList *attrs = pango_attr_list_new();
         PangoAttribute *attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
@@ -1563,7 +1667,7 @@ bool wxCairoContext::SetAntialiasMode(wxAntialiasMode antialias)
         return true;
 
     m_antialias = antialias;
-    
+
     cairo_antialias_t antialiasMode;
     switch (antialias)
     {
@@ -1584,7 +1688,7 @@ bool wxCairoContext::SetCompositionMode(wxCompositionMode op)
 {
     if ( m_composition == op )
         return true;
-        
+
     m_composition = op;
     cairo_operator_t cop;
     switch (op)
@@ -1648,7 +1752,7 @@ void wxCairoContext::EndLayer()
     cairo_pop_group_to_source(m_context);
     cairo_paint_with_alpha(m_context,opacity);
 }
-    
+
 //-----------------------------------------------------------------------------
 // wxCairoRenderer declaration
 //-----------------------------------------------------------------------------
@@ -1688,14 +1792,16 @@ public :
 
     virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
 
-    // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
-    virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
-        const wxColour&c1, const wxColour&c2) ;
+    virtual wxGraphicsBrush
+    CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                              wxDouble x2, wxDouble y2,
+                              const wxGraphicsGradientStops& stops);
 
-    // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
-    // with radius r and color cColor
-    virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-        const wxColour &oColor, const wxColour &cColor) ;
+    virtual wxGraphicsBrush
+    CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                              wxDouble xc, wxDouble yc,
+                              wxDouble radius,
+                              const wxGraphicsGradientStops& stops);
 
     // sets the font
     virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
@@ -1703,6 +1809,9 @@ public :
     // create a native bitmap representation
     virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
 
+    // create a graphics bitmap from a native bitmap
+    virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
+
     // create a subimage from a native image representation
     virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h  );
 
@@ -1721,13 +1830,6 @@ static wxCairoRenderer gs_cairoGraphicsRenderer;
 extern wxGraphicsRenderer* gCairoRenderer;
 wxGraphicsRenderer* gCairoRenderer = &gs_cairoGraphicsRenderer;
 
-#ifdef __WXGTK__
-wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
-{
-    return &gs_cairoGraphicsRenderer;
-}
-#endif
-
 wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc)
 {
     return new wxCairoContext(this,dc);
@@ -1752,7 +1854,11 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc)
 
 wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context )
 {
+#ifdef __WXMSW__
+    return new wxCairoContext(this,(HDC)context);
+#else
     return new wxCairoContext(this,(cairo_t*)context);
+#endif
 }
 
 
@@ -1826,25 +1932,26 @@ wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush )
     }
 }
 
-// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
-wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
-                                                                      const wxColour&c1, const wxColour&c2)
+wxGraphicsBrush
+wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                                           wxDouble x2, wxDouble y2,
+                                           const wxGraphicsGradientStops& stops)
 {
     wxGraphicsBrush p;
     wxCairoBrushData* d = new wxCairoBrushData( 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 wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-                                                                      const wxColour &oColor, const wxColour &cColor)
+wxGraphicsBrush
+wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                                           wxDouble xc, wxDouble yc, wxDouble r,
+                                           const wxGraphicsGradientStops& stops)
 {
     wxGraphicsBrush p;
     wxCairoBrushData* d = new wxCairoBrushData( this );
-    d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
+    d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops);
     p.SetRefData(d);
     return p;
 }
@@ -1862,7 +1969,7 @@ wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour
         return wxNullGraphicsFont;
 }
 
-wxGraphicsBitmap wxGraphicsRenderer::CreateBitmap( const wxBitmap& bmp )
+wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp )
 {
     if ( bmp.Ok() )
     {
@@ -1874,10 +1981,50 @@ wxGraphicsBitmap wxGraphicsRenderer::CreateBitmap( const wxBitmap& bmp )
         return wxNullGraphicsBitmap;
 }
 
-wxGraphicsBitmap wxGraphicsRenderer::CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h  )
+wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
+{
+    if ( bitmap != NULL )
+    {
+        wxGraphicsBitmap p;
+        p.SetRefData(new wxCairoBitmapData( this , (cairo_surface_t*) bitmap ));
+        return p;
+    }
+    else
+        return wxNullGraphicsBitmap;
+}
+
+wxGraphicsBitmap
+wxCairoRenderer::CreateSubBitmap(const wxGraphicsBitmap& WXUNUSED(bitmap),
+                                 wxDouble WXUNUSED(x),
+                                 wxDouble WXUNUSED(y),
+                                 wxDouble WXUNUSED(w),
+                                 wxDouble WXUNUSED(h))
 {
     wxFAIL_MSG("wxCairoRenderer::CreateSubBitmap is not implemented.");
     return wxNullGraphicsBitmap;
 }
 
-#endif  // wxUSE_GRAPHICS_CONTEXT
+wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()
+{
+    return &gs_cairoGraphicsRenderer;
+}
+
+#else // !wxUSE_CAIRO
+
+wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()
+{
+    return NULL;
+}
+
+#endif  // wxUSE_CAIRO/!wxUSE_CAIRO
+
+// MSW and OS X have their own native default renderers, but the other ports
+// use Cairo by default
+#if !(defined(__WXMSW__) || defined(__WXOSX__))
+wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
+{
+    return GetCairoRenderer();
+}
+#endif // !(__WXMSW__ || __WXOSX__)
+
+#endif // wxUSE_GRAPHICS_CONTEXT