+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.GetMaskBitmap();
+ 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;
+}
+
+//-----------------------------------------------------------------------------
+// wxCairoContext implementation
+//-----------------------------------------------------------------------------
+
+class wxCairoOffsetHelper
+{
+public :
+ wxCairoOffsetHelper( cairo_t* ctx , bool offset )
+ {
+ m_ctx = ctx;
+ m_offset = offset;
+ if ( m_offset )
+ cairo_translate( m_ctx, 0.5, 0.5 );
+ }
+ ~wxCairoOffsetHelper( )
+ {
+ if ( m_offset )
+ cairo_translate( m_ctx, -0.5, -0.5 );
+ }
+public :
+ cairo_t* m_ctx;
+ bool m_offset;
+} ;
+
+wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc )
+: wxGraphicsContext(renderer)
+{
+#ifdef __WXMSW__
+ // wxMSW contexts always use MM_ANISOTROPIC, which messes up
+ // text rendering when printing using Cairo. Switch it to MM_TEXT
+ // map mode to avoid this problem.
+ HDC hdc = (HDC)dc.GetHDC();
+ ::SetMapMode(hdc, MM_TEXT);
+ m_mswSurface = cairo_win32_printing_surface_create(hdc);
+ Init( cairo_create(m_mswSurface) );
+#endif
+
+#ifdef __WXGTK20__
+ const wxDCImpl *impl = dc.GetImpl();
+ Init( (cairo_t*) impl->GetCairoContext() );
+#endif
+ wxSize sz = dc.GetSize();
+ m_width = sz.x;
+ m_height = sz.y;
+
+ wxPoint org = dc.GetDeviceOrigin();
+ cairo_translate( m_context, org.x, org.y );
+
+ double sx,sy;
+ dc.GetUserScale( &sx, &sy );
+
+// TODO: Determine if these fixes are needed on other platforms too.
+// On MSW, without this the printer context will not respect wxDC SetMapMode calls.
+// For example, using dc.SetMapMode(wxMM_POINTS) can let us share printer and screen
+// drawing code
+#ifdef __WXMSW__
+ double lsx,lsy;
+ dc.GetLogicalScale( &lsx, &lsy );
+ sx *= lsx;
+ sy *= lsy;
+#endif
+ cairo_scale( m_context, sx, sy );
+
+ org = dc.GetLogicalOrigin();
+ cairo_translate( m_context, -org.x, -org.y );
+}
+
+wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc )
+: wxGraphicsContext(renderer)
+{
+ int width, height;
+ dc.GetSize( &width, &height );
+ m_width = width;
+ m_height = height;
+
+ m_enableOffset = true;
+
+#ifdef __WXMSW__
+ m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC());
+ Init( cairo_create(m_mswSurface) );
+#endif
+
+#ifdef __WXGTK3__
+ cairo_t* cr = static_cast<cairo_t*>(dc.GetImpl()->GetCairoContext());
+ if (cr)
+ Init(cr);
+#elif defined __WXGTK20__
+ wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
+ Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
+
+#if 0
+ wxGraphicsMatrix matrix = CreateMatrix();
+
+ wxPoint org = dc.GetDeviceOrigin();
+ matrix.Translate( org.x, org.y );
+
+ org = dc.GetLogicalOrigin();
+ matrix.Translate( -org.x, -org.y );
+
+ double sx,sy;
+ dc.GetUserScale( &sx, &sy );
+ matrix.Scale( sx, sy );
+
+ ConcatTransform( matrix );
+#endif
+#endif
+
+#ifdef __WXMAC__
+ CGContextRef cgcontext = (CGContextRef)dc.GetWindow()->MacGetCGContextRef();
+ cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(cgcontext, width, height);
+ Init( cairo_create( surface ) );
+ cairo_surface_destroy( surface );
+#endif
+}
+
+wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc )