+#ifdef __WXGTK3__
+wxMask::wxMask(cairo_surface_t* bitmap)
+#else
+wxMask::wxMask(GdkPixmap* bitmap)
+#endif
+{
+ m_bitmap = bitmap;
+}
+
+wxMask::~wxMask()
+{
+ if (m_bitmap)
+ {
+#ifdef __WXGTK3__
+ cairo_surface_destroy(m_bitmap);
+#else
+ g_object_unref (m_bitmap);
+#endif
+ }
+}
+
+void wxMask::FreeData()
+{
+ if (m_bitmap)
+ {
+#ifdef __WXGTK3__
+ cairo_surface_destroy(m_bitmap);
+#else
+ g_object_unref (m_bitmap);
+#endif
+ m_bitmap = NULL;
+ }
+}
+
+bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
+{
+ const int w = bitmap.GetWidth();
+ const int h = bitmap.GetHeight();
+
+#ifdef __WXGTK3__
+ m_bitmap = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
+ GdkPixbuf* pixbuf = bitmap.GetPixbufNoMask();
+ const guchar* src = gdk_pixbuf_get_pixels(pixbuf);
+ guchar* dst = cairo_image_surface_get_data(m_bitmap);
+ const int stride_src = gdk_pixbuf_get_rowstride(pixbuf);
+ const int stride_dst = cairo_image_surface_get_stride(m_bitmap);
+ const int src_inc = gdk_pixbuf_get_n_channels(pixbuf);
+ const guchar r = colour.Red();
+ const guchar g = colour.Green();
+ const guchar b = colour.Blue();
+ for (int j = 0; j < h; j++, src += stride_src, dst += stride_dst)
+ {
+ const guchar* s = src;
+ for (int i = 0; i < w; i++, s += src_inc)
+ {
+ dst[i] = 0xff;
+ if (s[0] == r && s[1] == g && s[2] == b)
+ dst[i] = 0;
+ }
+ }
+ cairo_surface_mark_dirty(m_bitmap);
+#else
+ // create mask as XBM format bitmap
+
+ // one bit per pixel, each row starts on a byte boundary
+ const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
+ wxByte* out = new wxByte[out_size];
+ // set bits are unmasked
+ memset(out, 0xff, out_size);
+ unsigned bit_index = 0;
+ if (bitmap.HasPixbuf())
+ {
+ const wxByte r_mask = colour.Red();
+ const wxByte g_mask = colour.Green();
+ const wxByte b_mask = colour.Blue();
+ GdkPixbuf* pixbuf = bitmap.GetPixbuf();
+ const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
+ const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
+ const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
+ for (int y = 0; y < h; y++, in += rowpadding)
+ {
+ for (int x = 0; x < w; x++, in += inc, bit_index++)
+ if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
+ out[bit_index >> 3] ^= 1 << (bit_index & 7);
+ // move index to next byte boundary
+ bit_index = (bit_index + 7) & ~7u;
+ }
+ }
+ else
+ {
+ GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
+ GdkColormap* colormap = gdk_image_get_colormap(image);
+ guint32 mask_pixel;
+ if (colormap == NULL)
+ // mono bitmap, white is pixel value 0
+ mask_pixel = guint32(colour.Red() != 255 || colour.Green() != 255 || colour.Blue() != 255);
+ else
+ {
+ wxColor c(colour);
+ c.CalcPixel(colormap);
+ mask_pixel = c.GetPixel();
+ }
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++, bit_index++)
+ if (gdk_image_get_pixel(image, x, y) == mask_pixel)
+ out[bit_index >> 3] ^= 1 << (bit_index & 7);
+ bit_index = (bit_index + 7) & ~7u;
+ }
+ g_object_unref(image);
+ }
+ m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
+ delete[] out;
+#endif
+ return true;
+}
+
+bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
+{
+ if (!bitmap.IsOk()) return false;
+
+ wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
+
+#ifdef __WXGTK3__
+ InitFromColour(bitmap, *wxBLACK);
+#else
+ m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
+
+ if (!m_bitmap) return false;
+
+ wxGtkObject<GdkGC> gc(gdk_gc_new( m_bitmap ));
+ gdk_gc_set_function(gc, GDK_COPY_INVERT);
+ gdk_draw_drawable(m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight());
+#endif
+
+ return true;
+}
+
+#ifdef __WXGTK3__
+cairo_surface_t* wxMask::GetBitmap() const
+#else
+GdkPixmap* wxMask::GetBitmap() const
+#endif