]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/graphicc.cpp
In wxComboPopupEvtHandler::OnMouseEvent(), when need to relay event to drop-down...
[wxWidgets.git] / src / generic / graphicc.cpp
index 67805459146d1ebed33ba278bf138d5a23446a7f..b21d03e9d7d80d8727c2b969f939e1ce6816c3bd 100644 (file)
 
 #if wxUSE_GRAPHICS_CONTEXT
 
+#include "wx/graphics.h"
+
+#if wxUSE_CAIRO
+
+#include "wx/cairo.h"
+
 #ifndef WX_PRECOMP
     #include "wx/bitmap.h"
     #include "wx/icon.h"
-
-    #include "wx/dc.h"
     #include "wx/dcclient.h"
     #include "wx/dcmemory.h"
     #include "wx/dcprint.h"
 
 #include "wx/private/graphics.h"
 #include "wx/rawbmp.h"
+#include "wx/vector.h"
 
 using namespace std;
 
-//-----------------------------------------------------------------------------
-// constants
-//-----------------------------------------------------------------------------
-
-const double RAD2DEG = 180.0 / M_PI;
-
-//-----------------------------------------------------------------------------
-// Local functions
-//-----------------------------------------------------------------------------
-
-static inline double dmin(double a, double b)
-{
-    return a < b ? a : b;
-}
-static inline double dmax(double a, double b)
-{
-    return a > b ? a : b;
-}
-
-static inline double DegToRad(double deg)
-{
-    return (deg * M_PI) / 180.0;
-}
-static inline double RadToDeg(double deg)
-{
-    return (deg * 180.0) / M_PI;
-}
-
 //-----------------------------------------------------------------------------
 // device context implementation
 //
@@ -87,6 +64,10 @@ static inline double RadToDeg(double deg)
 #endif
 
 #include <cairo.h>
+#ifdef __WXMSW__
+#include <cairo-win32.h>
+#endif
+
 #ifdef __WXGTK__
 #include <gtk/gtk.h>
 #include "wx/fontutil.h"
@@ -165,7 +146,7 @@ public :
     // gets the bounding box enclosing all points (possibly including control points)
     virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
 
-    virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxWINDING_RULE) const;
+    virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxWINDING_RULE) const;
 
 private :
     cairo_t* m_pathContext;
@@ -255,6 +236,8 @@ private :
     double *m_userLengths;
 
     wxPen m_pen;
+
+    wxDECLARE_NO_COPY_CLASS(wxCairoPenData);
 };
 
 class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData
@@ -265,14 +248,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;
@@ -291,9 +280,11 @@ public:
     virtual void Apply( wxGraphicsContext* context );
 #ifdef __WXGTK__
     const PangoFontDescription* GetFont() const { return m_font; }
+    bool GetUnderlined() const { return m_underlined; }
 #endif
 private :
     double m_size;
+    bool m_underlined;
     double m_red;
     double m_green;
     double m_blue;
@@ -307,6 +298,27 @@ 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; }
+    virtual cairo_pattern_t* GetCairoPattern() { return m_pattern; }
+    virtual wxSize GetSize() { return wxSize(m_width, m_height); }
+private :
+    cairo_surface_t* m_surface;
+    cairo_pattern_t* m_pattern;
+    int m_width;
+    int m_height;
+    unsigned char* m_buffer;
 };
 
 class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext
@@ -336,6 +348,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 );
@@ -345,10 +360,16 @@ public:
 
     virtual void * GetNativeContext();
 
-    virtual bool SetLogicalFunction( int function );
+    virtual bool SetAntialiasMode(wxAntialiasMode antialias);
+
+    virtual bool SetCompositionMode(wxCompositionMode op);
+
+    virtual void BeginLayer(wxDouble opacity);
+
+    virtual void EndLayer();
 
     virtual void StrokePath( const wxGraphicsPath& p );
-    virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxWINDING_RULE );
+    virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxWINDING_RULE );
 
     virtual void Translate( wxDouble dx , wxDouble dy );
     virtual void Scale( wxDouble xScale , wxDouble yScale );
@@ -363,6 +384,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();
@@ -372,14 +394,17 @@ public:
                                 wxDouble *descent, wxDouble *externalLeading ) const;
     virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
 
+protected:
+    virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
+
 private:
     void Init(cairo_t *context);
 
-    virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
-
     cairo_t* m_context;
 
-    DECLARE_NO_COPY_CLASS(wxCairoContext)
+    wxVector<float> m_layerOpacities;
+
+    wxDECLARE_NO_COPY_CLASS(wxCairoContext);
 };
 
 //-----------------------------------------------------------------------------
@@ -532,7 +557,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
         }
         break;
     default :
-        if ( m_pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH 
+        if ( m_pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH
             && m_pen.GetStyle() <= wxPENSTYLE_LAST_HATCH )
         {
             /*
@@ -664,26 +689,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()
@@ -703,9 +752,10 @@ wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &fo
     m_blue = col.Blue()/255.0;
     m_alpha = col.Alpha()/255.0;
     m_size = font.GetPointSize();
+    m_underlined = font.GetUnderlined();
 
 #ifdef __WXMAC__
-    m_font = cairo_atsui_font_face_create_for_atsu_font_id( font.MacGetATSUFontID() );
+    m_font = cairo_quartz_font_face_create_for_cgfont( font.OSXGetCGFont() );
 #elif defined(__WXGTK__)
     m_font = pango_font_description_copy( font.GetNativeFontInfo()->description );
 #else
@@ -879,9 +929,10 @@ void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h)
     }
 }
 
-bool wxCairoPathData::Contains( wxDouble x, wxDouble y, int 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;
 }
 
 //-----------------------------------------------------------------------------
@@ -1006,6 +1057,102 @@ void * wxCairoMatrixData::GetNativeMatrix() const
     return (void*) &m_matrix;
 }
 
+// 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"));
+
+    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;
+
+    // Create a surface object and copy the bitmap pixel data to it.  if the
+    // image has alpha (or a mask represented as alpha) then we'll use a
+    // different format and iterator than if it doesn't...
+    if (bmpSource.HasAlpha() || bmpSource.GetMask())
+    {
+        m_surface = cairo_image_surface_create_for_data(
+            m_buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4);
+        wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
+        wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
+
+        wxAlphaPixelData::Iterator p(pixData);
+        for (int y=0; y<bh; y++)
+        {
+            wxAlphaPixelData::Iterator rowStart = p;
+            for (int x=0; x<bw; x++)
+            {
+                // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
+                // with alpha in the upper 8 bits, then red, then green, then
+                // blue. The 32-bit quantities are stored native-endian.
+                // Pre-multiplied alpha is used.
+                unsigned char alpha = p.Alpha();
+                if (alpha == 0)
+                    *data = 0;
+                else
+                    *data = ( alpha                      << 24
+                              | (p.Red() * alpha/255)    << 16
+                              | (p.Green() * alpha/255)  <<  8
+                              | (p.Blue() * alpha/255) );
+                ++data;
+                ++p;
+            }
+            p = rowStart;
+            p.OffsetY(pixData, 1);
+        }
+    }
+    else  // no alpha
+    {
+        m_surface = cairo_image_surface_create_for_data(
+            m_buffer, CAIRO_FORMAT_RGB24, bw, bh, bw*4);
+        wxNativePixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
+        wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
+
+        wxNativePixelData::Iterator p(pixData);
+        for (int y=0; y<bh; y++)
+        {
+            wxNativePixelData::Iterator rowStart = p;
+            for (int x=0; x<bw; x++)
+            {
+                // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
+                // the upper 8 bits unused. Red, Green, and Blue are stored in
+                // the remaining 24 bits in that order.  The 32-bit quantities
+                // are stored native-endian.
+                *data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
+                ++data;
+                ++p;
+            }
+            p = rowStart;
+            p.OffsetY(pixData, 1);
+        }
+    }
+    m_pattern = cairo_pattern_create_for_surface(m_surface);
+}
+
+wxCairoBitmapData::~wxCairoBitmapData()
+{
+    if (m_pattern)
+        cairo_pattern_destroy(m_pattern);
+
+    if (m_surface)
+        cairo_surface_destroy(m_surface);
+
+    delete [] m_buffer;
+}
+
+
+
 //-----------------------------------------------------------------------------
 // wxCairoContext implementation
 //-----------------------------------------------------------------------------
@@ -1125,6 +1272,18 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawa
 }
 #endif
 
+#ifdef __WXMSW__
+wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, HDC handle )
+: wxGraphicsContext(renderer)
+{
+    m_mswSurface = cairo_win32_surface_create(handle);
+    m_context = cairo_create(m_mswSurface);
+    PushState();
+    PushState();
+}
+#endif
+
+
 wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context )
 : wxGraphicsContext(renderer)
 {
@@ -1156,9 +1315,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)
@@ -1223,7 +1390,7 @@ void wxCairoContext::StrokePath( const wxGraphicsPath& path )
     }
 }
 
-void wxCairoContext::FillPath( const wxGraphicsPath& path , int fillStyle )
+void wxCairoContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
 {
     if ( !m_brush.IsNull() )
     {
@@ -1286,99 +1453,34 @@ void wxCairoContext::PopState()
 
 void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
-    wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
-
-    cairo_surface_t* surface;
-    int bw = bmp.GetWidth();
-    int bh = bmp.GetHeight();
-    wxBitmap bmpSource = bmp;  // we need a non-const instance
-    unsigned char* buffer = new unsigned char[bw*bh*4];
-    wxUint32* data = (wxUint32*)buffer;
-
-    // Create a surface object and copy the bitmap pixel data to it.  if the
-    // image has alpha (or a mask represented as alpha) then we'll use a
-    // different format and iterator than if it doesn't...
-    if (bmpSource.HasAlpha() || bmpSource.GetMask())
-    {
-        surface = cairo_image_surface_create_for_data(
-            buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4);
-        wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
-        wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
-
-        wxAlphaPixelData::Iterator p(pixData);
-        for (int y=0; y<bh; y++)
-        {
-            wxAlphaPixelData::Iterator rowStart = p;
-            for (int x=0; x<bw; x++)
-            {
-                // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
-                // with alpha in the upper 8 bits, then red, then green, then
-                // blue. The 32-bit quantities are stored native-endian.
-                // Pre-multiplied alpha is used.
-                unsigned char alpha = p.Alpha();
-                if (alpha == 0)
-                    *data = 0;
-                else
-                    *data = ( alpha                      << 24
-                              | (p.Red() * alpha/255)    << 16
-                              | (p.Green() * alpha/255)  <<  8
-                              | (p.Blue() * alpha/255) );
-                ++data;
-                ++p;
-            }
-            p = rowStart;
-            p.OffsetY(pixData, 1);
-        }
-    }
-    else  // no alpha
-    {
-        surface = cairo_image_surface_create_for_data(
-            buffer, CAIRO_FORMAT_RGB24, bw, bh, bw*4);
-        wxNativePixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
-        wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
-
-        wxNativePixelData::Iterator p(pixData);
-        for (int y=0; y<bh; y++)
-        {
-            wxNativePixelData::Iterator rowStart = p;
-            for (int x=0; x<bw; x++)
-            {
-                // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
-                // the upper 8 bits unused. Red, Green, and Blue are stored in
-                // the remaining 24 bits in that order.  The 32-bit quantities
-                // are stored native-endian.
-                *data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
-                ++data;
-                ++p;
-            }
-            p = rowStart;
-            p.OffsetY(pixData, 1);
-        }
-    }
+    wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
+    DrawBitmap(bitmap, x, y, w, h);
 
+}
 
+void wxCairoContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
+{
     PushState();
 
     // In case we're scaling the image by using a width and height different
     // than the bitmap's size create a pattern transformation on the surface and
     // draw the transformed pattern.
-    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
-    wxDouble scaleX = w / bw;
-    wxDouble scaleY = h / bh;
+    wxCairoBitmapData* data = static_cast<wxCairoBitmapData*>(bmp.GetRefData());
+    cairo_pattern_t* pattern = data->GetCairoPattern();
+    wxSize size = data->GetSize();
+
+    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_set_source(m_context, pattern);
     // use the original size here since the context is scaled already...
-    cairo_rectangle(m_context, 0, 0, bw, bh);
+    cairo_rectangle(m_context, 0, 0, size.GetWidth(), size.GetHeight());
     // fill the rectangle using the pattern
     cairo_fill(m_context);
 
-    // clean up
-    cairo_pattern_destroy(pattern);
-    cairo_surface_destroy(surface);
-    delete [] buffer;
     PopState();
 }
 
@@ -1409,8 +1511,19 @@ void wxCairoContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
     size_t datalen = strlen(data);
 
     PangoLayout *layout = pango_cairo_create_layout (m_context);
-    pango_layout_set_font_description( layout, ((wxCairoFontData*)m_font.GetRefData())->GetFont());
+    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())
+    {
+        PangoAttrList *attrs = pango_attr_list_new();
+        PangoAttribute *attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
+        pango_attr_list_insert(attrs, attr);
+        pango_layout_set_attributes(layout, attrs);
+        pango_attr_list_unref(attrs);
+    }
+
     cairo_move_to(m_context, x, y);
     pango_cairo_show_layout (m_context, layout);
 
@@ -1522,53 +1635,97 @@ void * wxCairoContext::GetNativeContext()
     return m_context;
 }
 
-// Cairo doesn't support bitwise logical function (a.k.a. ROP, raster output
-// mode). Cairo supports Porter-Duff compositing operators, but they are quite
-// different, although in some cases have similar names.
-bool wxCairoContext::SetLogicalFunction( int function )
+bool wxCairoContext::SetAntialiasMode(wxAntialiasMode antialias)
 {
-    if (m_logicalFunction == function)
+    if (m_antialias == antialias)
         return true;
 
-    cairo_operator_t op;
+    m_antialias = antialias;
 
-    switch ( function )
+    cairo_antialias_t antialiasMode;
+    switch (antialias)
     {
-        case wxCOPY:       // (default) src
-            op = CAIRO_OPERATOR_OVER; // (also default)
+        case wxANTIALIAS_DEFAULT:
+            antialiasMode = CAIRO_ANTIALIAS_DEFAULT;
             break;
-        case wxOR:         // src OR dst
-            op = CAIRO_OPERATOR_ADD;
+        case wxANTIALIAS_NONE:
+            antialiasMode = CAIRO_ANTIALIAS_NONE;
             break;
-        case wxNO_OP:      // dst
-            op = CAIRO_OPERATOR_DEST; // ignore the source
+        default:
+            return false;
+    }
+    cairo_set_antialias(m_context, antialiasMode);
+    return true;
+}
+
+bool wxCairoContext::SetCompositionMode(wxCompositionMode op)
+{
+    if ( m_composition == op )
+        return true;
+
+    m_composition = op;
+    cairo_operator_t cop;
+    switch (op)
+    {
+        case wxCOMPOSITION_CLEAR:
+            cop = CAIRO_OPERATOR_CLEAR;
             break;
-        case wxCLEAR:      // 0
-            op = CAIRO_OPERATOR_CLEAR;// clear dst
+        case wxCOMPOSITION_SOURCE:
+            cop = CAIRO_OPERATOR_SOURCE;
+            break;
+        case wxCOMPOSITION_OVER:
+            cop = CAIRO_OPERATOR_OVER;
+            break;
+        case wxCOMPOSITION_IN:
+            cop = CAIRO_OPERATOR_IN;
+            break;
+        case wxCOMPOSITION_OUT:
+            cop = CAIRO_OPERATOR_OUT;
+            break;
+        case wxCOMPOSITION_ATOP:
+            cop = CAIRO_OPERATOR_ATOP;
+            break;
+        case wxCOMPOSITION_DEST:
+            cop = CAIRO_OPERATOR_DEST;
+            break;
+        case wxCOMPOSITION_DEST_OVER:
+            cop = CAIRO_OPERATOR_DEST_OVER;
+            break;
+        case wxCOMPOSITION_DEST_IN:
+            cop = CAIRO_OPERATOR_DEST_IN;
+            break;
+        case wxCOMPOSITION_DEST_OUT:
+            cop = CAIRO_OPERATOR_DEST_OUT;
+            break;
+        case wxCOMPOSITION_DEST_ATOP:
+            cop = CAIRO_OPERATOR_DEST_ATOP;
+            break;
+        case wxCOMPOSITION_XOR:
+            cop = CAIRO_OPERATOR_XOR;
+            break;
+        case wxCOMPOSITION_ADD:
+            cop = CAIRO_OPERATOR_ADD;
             break;
-
-        case wxAND:        // src AND dst
-        case wxAND_INVERT: // (NOT src) AND dst
-        case wxAND_REVERSE:// src AND (NOT dst)
-        case wxEQUIV:      // (NOT src) XOR dst
-        case wxINVERT:     // NOT dst
-        case wxNAND:       // (NOT src) OR (NOT dst)
-        case wxNOR:        // (NOT src) AND (NOT dst)
-        case wxOR_INVERT:  // (NOT src) OR dst
-        case wxOR_REVERSE: // src OR (NOT dst)
-        case wxSET:        // 1
-        case wxSRC_INVERT: // NOT src
-        //wxXOR does _not_ correspond to CAIRO_OPERATOR_XOR
-        case wxXOR:        // src XOR dst
         default:
             return false;
     }
-
-    m_logicalFunction = function;
-    cairo_set_operator(m_context, op);
+    cairo_set_operator(m_context, cop);
     return true;
 }
 
+void wxCairoContext::BeginLayer(wxDouble opacity)
+{
+    m_layerOpacities.push_back(opacity);
+    cairo_push_group(m_context);
+}
+
+void wxCairoContext::EndLayer()
+{
+    float opacity = m_layerOpacities.back();
+    m_layerOpacities.pop_back();
+    cairo_pop_group_to_source(m_context);
+    cairo_paint_with_alpha(m_context,opacity);
+}
 
 //-----------------------------------------------------------------------------
 // wxCairoRenderer declaration
@@ -1609,31 +1766,28 @@ 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 ) ;
 
     // create a native bitmap representation
-#if 0
-    virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap )
-    {
-      return wxGraphicsBitmap;
-    }
+    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  )
-    {
-      return wxGraphicsBitmap;
-    }
-#endif
+    virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h  );
 
 private :
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer)
@@ -1650,13 +1804,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);
@@ -1681,7 +1828,12 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc)
 
 wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context )
 {
+#ifdef __WXMSW__
+    return new wxCairoContext(this,(HDC)context);
+#endif
+#ifdef __WXGTK__
     return new wxCairoContext(this,(cairo_t*)context);
+#endif
 }
 
 
@@ -1696,6 +1848,9 @@ wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * windo
 
 wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext()
 {
+#ifdef __WXGTK__
+    return CreateContextFromNativeWindow(gdk_get_default_root_window());
+#endif
     return NULL;
     // TODO
 }
@@ -1730,7 +1885,7 @@ wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble
 
 wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen)
 {
-    if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
+    if ( !pen.Ok() || pen.GetStyle() == wxPENSTYLE_TRANSPARENT )
         return wxNullGraphicsPen;
     else
     {
@@ -1742,7 +1897,7 @@ wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen)
 
 wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush )
 {
-    if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
+    if ( !brush.Ok() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT )
         return wxNullGraphicsBrush;
     else
     {
@@ -1752,25 +1907,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;
 }
@@ -1788,4 +1944,62 @@ wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour
         return wxNullGraphicsFont;
 }
 
-#endif  // wxUSE_GRAPHICS_CONTEXT
+wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp )
+{
+    if ( bmp.Ok() )
+    {
+        wxGraphicsBitmap p;
+        p.SetRefData(new wxCairoBitmapData( this , bmp ));
+        return p;
+    }
+    else
+        return wxNullGraphicsBitmap;
+}
+
+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;
+}
+
+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