+    wxBitmapRefData* bmpData = M_BMPDATA;
+    cairo_t* cr;
+    if (bmpData->m_surface)
+        cr = cairo_create(bmpData->m_surface);
+    else
+    {
+        GdkPixbuf* pixbuf = bmpData->m_pixbufNoMask;
+        const bool useAlpha = bmpData->m_bpp == 32 || (pixbuf && gdk_pixbuf_get_has_alpha(pixbuf));
+        bmpData->m_surface = cairo_image_surface_create(
+            useAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
+            bmpData->m_width, bmpData->m_height);
+        cr = cairo_create(bmpData->m_surface);
+        if (pixbuf)
+        {
+            gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+            cairo_paint(cr);
+            cairo_set_source_rgb(cr, 0, 0, 0);
+        }
+    }
+    if (bmpData->m_pixbufNoMask)
+    {
+        g_object_unref(bmpData->m_pixbufNoMask);
+        bmpData->m_pixbufNoMask = NULL;
+    }
+    if (bmpData->m_pixbufMask)
+    {
+        g_object_unref(bmpData->m_pixbufMask);
+        bmpData->m_pixbufMask = NULL;
+    }
+    wxASSERT(cr && cairo_status(cr) == 0);
+    return cr;
+}
+
+void wxBitmap::Draw(cairo_t* cr, int x, int y, bool useMask, const wxColour* fg, const wxColour* bg) const
+{
+    wxCHECK_RET(IsOk(), "invalid bitmap");
+
+    wxBitmapRefData* bmpData = M_BMPDATA;
+    SetSourceSurface(cr, x, y, fg, bg);
+    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
+    cairo_surface_t* mask = NULL;
+    if (useMask && bmpData->m_mask)
+        mask = *bmpData->m_mask;
+    if (mask)
+        cairo_mask_surface(cr, mask, x, y);
+    else
+        cairo_paint(cr);
+}
+#endif
+
+GdkPixbuf *wxBitmap::GetPixbuf() const
+{
+    wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
+
+    wxBitmapRefData* bmpData = M_BMPDATA;
+#ifdef __WXGTK3__
+    if (bmpData->m_pixbufMask)
+        return bmpData->m_pixbufMask;
+
+    if (bmpData->m_pixbufNoMask == NULL)
+        GetPixbufNoMask();
+    cairo_surface_t* mask = NULL;
+    if (bmpData->m_mask)
+        mask = *bmpData->m_mask;
+    if (mask == NULL)
+        return bmpData->m_pixbufNoMask;
+
+    const int w = bmpData->m_width;
+    const int h = bmpData->m_height;
+    bmpData->m_pixbufMask = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, w, h);
+
+    guchar* dst = gdk_pixbuf_get_pixels(bmpData->m_pixbufMask);
+    const int dstStride = gdk_pixbuf_get_rowstride(bmpData->m_pixbufMask);
+    CopyImageData(dst, 4, dstStride,
+        gdk_pixbuf_get_pixels(bmpData->m_pixbufNoMask),
+        gdk_pixbuf_get_n_channels(bmpData->m_pixbufNoMask),
+        gdk_pixbuf_get_rowstride(bmpData->m_pixbufNoMask),
+        w, h);
+
+    const guchar* src = cairo_image_surface_get_data(mask);
+    const int srcStride = cairo_image_surface_get_stride(mask);
+    for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
+        for (int i = 0; i < w; i++)
+            if (src[i] == 0)
+                dst[i * 4 + 3] = 0;
+
+    return bmpData->m_pixbufMask;
+#else
+    if (bmpData->m_pixbuf)
+        return bmpData->m_pixbuf;
+
+    const int w = bmpData->m_width;
+    const int h = bmpData->m_height;
+    GdkPixmap* mask = NULL;
+    if (bmpData->m_mask)
+        mask = *bmpData->m_mask;
+    const bool useAlpha = bmpData->m_alphaRequested || mask;
+    bmpData->m_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, useAlpha, 8, w, h);
+    if (bmpData->m_pixmap)
+        PixmapToPixbuf(bmpData->m_pixmap, bmpData->m_pixbuf, w, h);
+    if (mask)
+        MaskToAlpha(mask, bmpData->m_pixbuf, w, h);
+    return bmpData->m_pixbuf;
+#endif