+ m_surface = cairo_image_surface_create_for_data(
+ m_buffer, format, m_width, m_height, stride);
+ m_pattern = cairo_pattern_create_for_surface(m_surface);
+}
+
+wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap ) :
+ wxGraphicsBitmapData( renderer )
+{
+ m_surface = bitmap;
+ m_pattern = cairo_pattern_create_for_surface(m_surface);
+}
+
+wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsBitmapData( renderer )
+{
+ wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
+
+#ifdef wxHAS_RAW_BITMAP
+ // 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...
+ cairo_format_t bufferFormat = bmp.GetDepth() == 32
+#if defined(__WXGTK__) && !defined(__WXGTK3__)
+ || bmp.GetMask()
+#endif
+ ? CAIRO_FORMAT_ARGB32
+ : CAIRO_FORMAT_RGB24;
+
+ int stride = InitBuffer(bmp.GetWidth(), bmp.GetHeight(), bufferFormat);
+
+ wxBitmap bmpSource = bmp; // we need a non-const instance
+ wxUint32* data = (wxUint32*)m_buffer;
+
+ if ( bufferFormat == CAIRO_FORMAT_ARGB32 )
+ {
+ // use the bitmap's alpha
+ wxAlphaPixelData
+ pixData(bmpSource, wxPoint(0, 0), wxSize(m_width, m_height));
+ wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
+
+ wxAlphaPixelData::Iterator p(pixData);
+ for (int y=0; y<m_height; y++)
+ {
+ wxAlphaPixelData::Iterator rowStart = p;
+ wxUint32* const rowStartDst = data;
+ for (int x=0; x<m_width; 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;
+ }
+
+ data = rowStartDst + stride / 4;
+ p = rowStart;
+ p.OffsetY(pixData, 1);
+ }
+ }
+ else // no alpha
+ {
+ wxNativePixelData
+ pixData(bmpSource, wxPoint(0, 0), wxSize(m_width, m_height));
+ wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
+
+ wxNativePixelData::Iterator p(pixData);
+ for (int y=0; y<m_height; y++)
+ {
+ wxNativePixelData::Iterator rowStart = p;
+ wxUint32* const rowStartDst = data;
+ for (int x=0; x<m_width; 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;
+ }
+
+ data = rowStartDst + stride / 4;
+ p = rowStart;
+ p.OffsetY(pixData, 1);
+ }
+ }
+#if defined(__WXMSW__) || defined(__WXGTK3__)
+ // if there is a mask, set the alpha bytes in the target buffer to
+ // fully transparent or fully opaque
+ if (bmpSource.GetMask())
+ {
+ wxBitmap bmpMask = bmpSource.GetMask()->GetBitmap();
+ bufferFormat = CAIRO_FORMAT_ARGB32;
+ data = (wxUint32*)m_buffer;
+ wxNativePixelData
+ pixData(bmpMask, wxPoint(0, 0), wxSize(m_width, m_height));
+ wxCHECK_RET( pixData, wxT("Failed to gain raw access to mask data."));
+
+ wxNativePixelData::Iterator p(pixData);
+ for (int y=0; y<m_height; y++)
+ {
+ wxNativePixelData::Iterator rowStart = p;
+ wxUint32* const rowStartDst = data;
+ for (int x=0; x<m_width; x++)
+ {
+ if (p.Red()+p.Green()+p.Blue() == 0)
+ *data = 0;
+ else
+ *data = (wxALPHA_OPAQUE << 24) | (*data & 0x00FFFFFF);
+ ++data;
+ ++p;
+ }
+
+ data = rowStartDst + stride / 4;
+ p = rowStart;
+ p.OffsetY(pixData, 1);
+ }
+ }
+#endif
+
+ InitSurface(bufferFormat, stride);
+#endif // wxHAS_RAW_BITMAP
+}
+
+#if wxUSE_IMAGE
+
+// Helper functions for dealing with alpha pre-multiplication.
+namespace
+{
+
+inline unsigned char Premultiply(unsigned char alpha, unsigned char data)
+{
+ return alpha ? (data * alpha)/0xff : data;
+}
+
+inline unsigned char Unpremultiply(unsigned char alpha, unsigned char data)
+{
+ return alpha ? (data * 0xff)/alpha : data;
+}
+
+} // anonymous namespace
+
+wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer,
+ const wxImage& image)
+ : wxGraphicsBitmapData(renderer)
+{
+ const cairo_format_t bufferFormat = image.HasAlpha()
+ ? CAIRO_FORMAT_ARGB32
+ : CAIRO_FORMAT_RGB24;
+
+ int stride = InitBuffer(image.GetWidth(), image.GetHeight(), bufferFormat);
+
+ // Copy wxImage data into the buffer. Notice that we work with wxUint32
+ // values and not bytes becase Cairo always works with buffers in native
+ // endianness.
+ wxUint32* dst = reinterpret_cast<wxUint32*>(m_buffer);
+ const unsigned char* src = image.GetData();
+
+ if ( bufferFormat == CAIRO_FORMAT_ARGB32 )
+ {
+ const unsigned char* alpha = image.GetAlpha();
+
+ for ( int y = 0; y < m_height; y++ )
+ {
+ wxUint32* const rowStartDst = dst;
+
+ for ( int x = 0; x < m_width; x++ )
+ {
+ const unsigned char a = *alpha++;
+
+ *dst++ = a << 24 |
+ Premultiply(a, src[0]) << 16 |
+ Premultiply(a, src[1]) << 8 |
+ Premultiply(a, src[2]);
+ src += 3;
+ }
+
+ dst = rowStartDst + stride / 4;
+ }
+ }
+ else // RGB
+ {
+ for ( int y = 0; y < m_height; y++ )
+ {
+ wxUint32* const rowStartDst = dst;
+
+ for ( int x = 0; x < m_width; x++ )
+ {
+ *dst++ = src[0] << 16 |
+ src[1] << 8 |
+ src[2];
+ src += 3;
+ }
+
+ dst = rowStartDst + stride / 4;
+ }
+ }
+
+ InitSurface(bufferFormat, stride);
+}
+
+wxImage wxCairoBitmapData::ConvertToImage() const
+{
+ wxImage image(m_width, m_height, false /* don't clear */);
+
+ // Get the surface type and format.
+ wxCHECK_MSG( cairo_surface_get_type(m_surface) == CAIRO_SURFACE_TYPE_IMAGE,
+ wxNullImage,
+ wxS("Can't convert non-image surface to image.") );
+
+ switch ( cairo_image_surface_get_format(m_surface) )
+ {
+ case CAIRO_FORMAT_ARGB32:
+ image.SetAlpha();
+ break;
+
+ case CAIRO_FORMAT_RGB24:
+ // Nothing to do, we don't use alpha by default.
+ break;
+
+ case CAIRO_FORMAT_A8:
+ case CAIRO_FORMAT_A1:
+ wxFAIL_MSG(wxS("Unsupported Cairo image surface type."));
+ return wxNullImage;
+
+ default:
+ wxFAIL_MSG(wxS("Unknown Cairo image surface type."));
+ return wxNullImage;
+ }
+
+ // Prepare for copying data.
+ const wxUint32* src = (wxUint32*)cairo_image_surface_get_data(m_surface);
+ wxCHECK_MSG( src, wxNullImage, wxS("Failed to get Cairo surface data.") );
+
+ int stride = cairo_image_surface_get_stride(m_surface);
+ wxCHECK_MSG( stride > 0, wxNullImage,
+ wxS("Failed to get Cairo surface stride.") );
+
+ // As we work with wxUint32 pointers and not char ones, we need to adjust
+ // the stride accordingly. This should be lossless as the stride must be a
+ // multiple of pixel size.
+ wxASSERT_MSG( !(stride % sizeof(wxUint32)), wxS("Unexpected stride.") );
+ stride /= sizeof(wxUint32);
+
+ unsigned char* dst = image.GetData();
+ unsigned char *alpha = image.GetAlpha();
+ if ( alpha )
+ {
+ // We need to also copy alpha and undo the pre-multiplication as Cairo
+ // stores pre-multiplied values in this format while wxImage does not.
+ for ( int y = 0; y < m_height; y++ )
+ {
+ const wxUint32* const rowStart = src;
+ for ( int x = 0; x < m_width; x++ )
+ {
+ const wxUint32 argb = *src++;
+
+ *alpha++ = (argb & 0xff000000) >> 24;
+
+ // Copy the RGB data undoing the pre-multiplication.
+ *dst++ = Unpremultiply(*alpha, (argb & 0x00ff0000) >> 16);
+ *dst++ = Unpremultiply(*alpha, (argb & 0x0000ff00) >> 8);
+ *dst++ = Unpremultiply(*alpha, (argb & 0x000000ff));
+ }
+
+ src = rowStart + stride;
+ }
+ }
+ else // RGB
+ {
+ // Things are pretty simple in this case, just copy RGB bytes.
+ for ( int y = 0; y < m_height; y++ )
+ {
+ const wxUint32* const rowStart = src;
+ for ( int x = 0; x < m_width; x++ )
+ {
+ const wxUint32 argb = *src++;
+
+ *dst++ = (argb & 0x00ff0000) >> 16;
+ *dst++ = (argb & 0x0000ff00) >> 8;
+ *dst++ = (argb & 0x000000ff);
+ }
+
+ src = rowStart + stride;
+ }
+ }
+
+ return image;
+}
+
+#endif // wxUSE_IMAGE
+
+wxCairoBitmapData::~wxCairoBitmapData()
+{
+ if (m_pattern)
+ cairo_pattern_destroy(m_pattern);
+
+ if (m_surface)
+ cairo_surface_destroy(m_surface);
+
+ delete [] m_buffer;