X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/239e6af724de1df0cfc338a927417650d1d8b39b..07aaf32633ecf18ec3edfbb41793a112914792d0:/src/generic/graphicc.cpp diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 76efcf4b2a..5e7da3dcba 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -25,7 +25,9 @@ // the wx dll in order to load them dynamically. #define cairo_public -#include "wx/cairo.h" +#include + +bool wxCairoInit(); #ifndef WX_PRECOMP #include "wx/bitmap.h" @@ -71,16 +73,18 @@ using namespace std; #include #ifdef __WXMSW__ #include +// Notice that the order is important: cairo-win32.h includes windows.h which +// pollutes the global name space with macros so include our own header which +// #undefines them after it. +#include "wx/msw/private.h" #endif #ifdef __WXGTK__ #include #include "wx/fontutil.h" +#ifndef __WXGTK3__ #include "wx/gtk/dc.h" #endif - -#ifdef __WXMSW__ -#include #endif #ifdef __WXMAC__ @@ -214,7 +218,44 @@ private: cairo_matrix_t m_matrix ; } ; -class WXDLLIMPEXP_CORE wxCairoPenData : public wxGraphicsObjectRefData +// Common base class for pens and brushes. +class wxCairoPenBrushBaseData : public wxGraphicsObjectRefData +{ +public: + wxCairoPenBrushBaseData(wxGraphicsRenderer* renderer, + const wxColour& col, + bool isTransparent); + virtual ~wxCairoPenBrushBaseData(); + + virtual void Apply( wxGraphicsContext* context ); + +protected: + // Call this to use the given bitmap as stipple. Bitmap must be non-null + // and valid. + void InitStipple(wxBitmap* bmp); + + // Call this to use the given hatch style. Hatch style must be valid. + void InitHatch(wxHatchStyle hatchStyle); + + + double m_red; + double m_green; + double m_blue; + double m_alpha; + + cairo_pattern_t* m_pattern; + class wxCairoBitmapData* m_bmpdata; + +private: + // Called once to allocate m_pattern if needed. + void InitHatchPattern(cairo_t* ctext); + + wxHatchStyle m_hatchStyle; + + wxDECLARE_NO_COPY_CLASS(wxCairoPenBrushBaseData); +}; + +class WXDLLIMPEXP_CORE wxCairoPenData : public wxCairoPenBrushBaseData { public: wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ); @@ -228,11 +269,6 @@ public: private : double m_width; - double m_red; - double m_green; - double m_blue; - double m_alpha; - cairo_line_cap_t m_cap; cairo_line_join_t m_join; @@ -240,19 +276,14 @@ private : const double *m_lengths; double *m_userLengths; - wxPen m_pen; - wxDECLARE_NO_COPY_CLASS(wxCairoPenData); }; -class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData +class WXDLLIMPEXP_CORE wxCairoBrushData : public wxCairoPenBrushBaseData { public: wxCairoBrushData( wxGraphicsRenderer* renderer ); wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ); - ~wxCairoBrushData (); - - virtual void Apply( wxGraphicsContext* context ); void CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, @@ -266,14 +297,6 @@ protected: // common part of Create{Linear,Radial}GradientBrush() void AddGradientStops(const wxGraphicsGradientStops& stops); - -private : - double m_red; - double m_green; - double m_blue; - double m_alpha; - - cairo_pattern_t* m_brushPattern; }; class wxCairoFontData : public wxGraphicsObjectRefData @@ -323,7 +346,7 @@ private : cairo_font_weight_t m_weight; }; -class wxCairoBitmapData : public wxGraphicsObjectRefData +class wxCairoBitmapData : public wxGraphicsBitmapData { public: wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ); @@ -335,6 +358,7 @@ public: virtual cairo_surface_t* GetCairoSurface() { return m_surface; } virtual cairo_pattern_t* GetCairoPattern() { return m_pattern; } + virtual void* GetNativeBitmap() const { return m_surface; } virtual wxSize GetSize() { return wxSize(m_width, m_height); } #if wxUSE_IMAGE @@ -366,7 +390,7 @@ public: wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc ); wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc ); #ifdef __WXGTK__ - wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ); + wxCairoContext( wxGraphicsRenderer* renderer, GdkWindow *window ); #endif #ifdef __WXMSW__ wxCairoContext( wxGraphicsRenderer* renderer, HDC context ); @@ -397,6 +421,7 @@ public: virtual void Clip( const wxRegion ®ion ); #ifdef __WXMSW__ cairo_surface_t* m_mswSurface; + WindowHDC m_mswWindowHDC; #endif // clips drawings to the rect @@ -485,6 +510,139 @@ private: }; #endif // wxUSE_IMAGE +// ---------------------------------------------------------------------------- +// wxCairoPenBrushBaseData implementation +//----------------------------------------------------------------------------- + +wxCairoPenBrushBaseData::wxCairoPenBrushBaseData(wxGraphicsRenderer* renderer, + const wxColour& col, + bool isTransparent) + : wxGraphicsObjectRefData(renderer) +{ + m_hatchStyle = wxHATCHSTYLE_INVALID; + m_pattern = NULL; + m_bmpdata = NULL; + + if ( isTransparent ) + { + m_red = + m_green = + m_blue = + m_alpha = 0; + } + else // non-transparent + { + m_red = col.Red()/255.0; + m_green = col.Green()/255.0; + m_blue = col.Blue()/255.0; + m_alpha = col.Alpha()/255.0; + } +} + +wxCairoPenBrushBaseData::~wxCairoPenBrushBaseData() +{ + if (m_bmpdata) + { + // Deleting the bitmap data also deletes the pattern referenced by + // m_pattern, so set it to NULL to avoid deleting it twice. + delete m_bmpdata; + m_pattern = NULL; + } + if (m_pattern) + cairo_pattern_destroy(m_pattern); +} + +void wxCairoPenBrushBaseData::InitHatchPattern(cairo_t* ctext) +{ + cairo_surface_t* const + surface = cairo_surface_create_similar( + cairo_get_target(ctext), CAIRO_CONTENT_COLOR_ALPHA, 10, 10 + ); + + cairo_t* const cr = cairo_create(surface); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_width(cr, 1); + cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER); + + switch ( m_hatchStyle ) + { + case wxHATCHSTYLE_CROSS: + cairo_move_to(cr, 5, 0); + cairo_line_to(cr, 5, 10); + cairo_move_to(cr, 0, 5); + cairo_line_to(cr, 10, 5); + break; + + case wxHATCHSTYLE_BDIAGONAL: + cairo_move_to(cr, 0, 10); + cairo_line_to(cr, 10, 0); + break; + + case wxHATCHSTYLE_FDIAGONAL: + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, 10, 10); + break; + + case wxHATCHSTYLE_CROSSDIAG: + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, 10, 10); + cairo_move_to(cr, 10, 0); + cairo_line_to(cr, 0, 10); + break; + + case wxHATCHSTYLE_HORIZONTAL: + cairo_move_to(cr, 0, 5); + cairo_line_to(cr, 10, 5); + break; + + case wxHATCHSTYLE_VERTICAL: + cairo_move_to(cr, 5, 0); + cairo_line_to(cr, 5, 10); + break; + + default: + wxFAIL_MSG(wxS("Invalid hatch pattern style.")); + } + + cairo_set_source_rgba(cr, m_red, m_green, m_blue, m_alpha); + cairo_stroke(cr); + + cairo_destroy(cr); + + m_pattern = cairo_pattern_create_for_surface(surface); + cairo_surface_destroy(surface); + cairo_pattern_set_extend(m_pattern, CAIRO_EXTEND_REPEAT); +} + +void wxCairoPenBrushBaseData::InitStipple(wxBitmap* bmp) +{ + wxCHECK_RET( bmp && bmp->IsOk(), wxS("Invalid stippled bitmap") ); + + m_bmpdata = new wxCairoBitmapData(GetRenderer(), *bmp); + m_pattern = m_bmpdata->GetCairoPattern(); + cairo_pattern_set_extend(m_pattern, CAIRO_EXTEND_REPEAT); +} + +void wxCairoPenBrushBaseData::InitHatch(wxHatchStyle hatchStyle) +{ + // We can't create m_pattern right now as we don't have the Cairo context + // needed for it, so just remember that we need to do it. + m_hatchStyle = hatchStyle; +} + +void wxCairoPenBrushBaseData::Apply( wxGraphicsContext* context ) +{ + cairo_t* const ctext = (cairo_t*) context->GetNativeContext(); + + if ( m_hatchStyle != wxHATCHSTYLE_INVALID && !m_pattern ) + InitHatchPattern(ctext); + + if ( m_pattern ) + cairo_set_source(ctext, m_pattern); + else + cairo_set_source_rgba(ctext, m_red, m_green, m_blue, m_alpha); +} + //----------------------------------------------------------------------------- // wxCairoPenData implementation //----------------------------------------------------------------------------- @@ -503,20 +661,14 @@ void wxCairoPenData::Init() } wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) -: wxGraphicsObjectRefData(renderer) + : wxCairoPenBrushBaseData(renderer, pen.GetColour(), pen.IsTransparent()) { Init(); - m_pen = pen; - m_width = m_pen.GetWidth(); + m_width = pen.GetWidth(); if (m_width <= 0.0) m_width = 0.1; - m_red = m_pen.GetColour().Red()/255.0; - m_green = m_pen.GetColour().Green()/255.0; - m_blue = m_pen.GetColour().Blue()/255.0; - m_alpha = m_pen.GetColour().Alpha()/255.0; - - switch ( m_pen.GetCap() ) + switch ( pen.GetCap() ) { case wxCAP_ROUND : m_cap = CAIRO_LINE_CAP_ROUND; @@ -535,7 +687,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) break; } - switch ( m_pen.GetJoin() ) + switch ( pen.GetJoin() ) { case wxJOIN_BEVEL : m_join = CAIRO_LINE_JOIN_BEVEL; @@ -572,7 +724,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) 9.0 , 6.0 , 3.0 , 3.0 }; - switch ( m_pen.GetStyle() ) + switch ( pen.GetStyle() ) { case wxPENSTYLE_SOLID : break; @@ -602,7 +754,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) case wxPENSTYLE_USER_DASH : { wxDash *wxdashes ; - m_count = m_pen.GetDashes( &wxdashes ) ; + m_count = pen.GetDashes( &wxdashes ) ; if ((wxdashes != NULL) && (m_count > 0)) { m_userLengths = new double[m_count] ; @@ -619,54 +771,18 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) m_lengths = m_userLengths ; } break; + case wxPENSTYLE_STIPPLE : - { - /* - wxBitmap* bmp = pen.GetStipple(); - if ( bmp && bmp->IsOk() ) - { - wxDELETE( m_penImage ); - wxDELETE( m_penBrush ); - m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); - m_penBrush = new TextureBrush(m_penImage); - m_pen->SetBrush( m_penBrush ); - } - */ - } + case wxPENSTYLE_STIPPLE_MASK : + case wxPENSTYLE_STIPPLE_MASK_OPAQUE : + InitStipple(pen.GetStipple()); break; + default : - if ( m_pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH - && m_pen.GetStyle() <= wxPENSTYLE_LAST_HATCH ) + if ( pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH + && pen.GetStyle() <= wxPENSTYLE_LAST_HATCH ) { - /* - wxDELETE( m_penBrush ); - HatchStyle style = HatchStyleHorizontal; - switch( pen.GetStyle() ) - { - case wxPENSTYLE_BDIAGONAL_HATCH : - style = HatchStyleBackwardDiagonal; - break ; - case wxPENSTYLE_CROSSDIAG_HATCH : - style = HatchStyleDiagonalCross; - break ; - case wxPENSTYLE_FDIAGONAL_HATCH : - style = HatchStyleForwardDiagonal; - break ; - case wxPENSTYLE_CROSS_HATCH : - style = HatchStyleCross; - break ; - case wxPENSTYLE_HORIZONTAL_HATCH : - style = HatchStyleHorizontal; - break ; - case wxPENSTYLE_VERTICAL_HATCH : - style = HatchStyleVertical; - break ; - - } - m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() , - pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent ); - m_pen->SetBrush( m_penBrush ) - */ + InitHatch(static_cast(pen.GetStyle())); } break; } @@ -674,9 +790,10 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) void wxCairoPenData::Apply( wxGraphicsContext* context ) { + wxCairoPenBrushBaseData::Apply(context); + cairo_t * ctext = (cairo_t*) context->GetNativeContext(); cairo_set_line_width(ctext,m_width); - cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); cairo_set_line_cap(ctext,m_cap); cairo_set_line_join(ctext,m_join); cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0); @@ -687,83 +804,29 @@ void wxCairoPenData::Apply( wxGraphicsContext* context ) //----------------------------------------------------------------------------- wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer ) - : wxGraphicsObjectRefData( renderer ) + : wxCairoPenBrushBaseData(renderer, wxColour(), true /* transparent */) { Init(); } -wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ) - : wxGraphicsObjectRefData(renderer) +wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, + const wxBrush &brush ) + : wxCairoPenBrushBaseData(renderer, brush.GetColour(), brush.IsTransparent()) { Init(); - m_red = brush.GetColour().Red()/255.0; - m_green = brush.GetColour().Green()/255.0; - m_blue = brush.GetColour().Blue()/255.0; - m_alpha = brush.GetColour().Alpha()/255.0; - /* - if ( brush.GetStyle() == wxBRUSHSTYLE_SOLID) - { - m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() , - brush.GetColour().Green() , brush.GetColour().Blue() ) ); - } - else if ( brush.IsHatch() ) + switch ( brush.GetStyle() ) { - HatchStyle style = HatchStyleHorizontal; - switch( brush.GetStyle() ) - { - case wxBRUSHSTYLE_BDIAGONAL_HATCH : - style = HatchStyleBackwardDiagonal; - break ; - case wxBRUSHSTYLE_CROSSDIAG_HATCH : - style = HatchStyleDiagonalCross; - break ; - case wxBRUSHSTYLE_FDIAGONAL_HATCH : - style = HatchStyleForwardDiagonal; - break ; - case wxBRUSHSTYLE_CROSS_HATCH : - style = HatchStyleCross; - break ; - case wxBRUSHSTYLE_HORIZONTAL_HATCH : - style = HatchStyleHorizontal; - break ; - case wxBRUSHSTYLE_VERTICAL_HATCH : - style = HatchStyleVertical; - break ; - - } - m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() , - brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent ); - } - else - { - wxBitmap* bmp = brush.GetStipple(); - if ( bmp && bmp->IsOk() ) - { - wxDELETE( m_brushImage ); - m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); - m_brush = new TextureBrush(m_brushImage); - } - } - */ -} - -wxCairoBrushData::~wxCairoBrushData () -{ - if (m_brushPattern) - cairo_pattern_destroy(m_brushPattern); -} + case wxBRUSHSTYLE_STIPPLE: + case wxBRUSHSTYLE_STIPPLE_MASK: + case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE: + InitStipple(brush.GetStipple()); + break; -void wxCairoBrushData::Apply( wxGraphicsContext* context ) -{ - cairo_t * ctext = (cairo_t*) context->GetNativeContext(); - if ( m_brushPattern ) - { - cairo_set_source(ctext,m_brushPattern); - } - else - { - cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); + default: + if ( brush.IsHatch() ) + InitHatch(static_cast(brush.GetStyle())); + break; } } @@ -779,7 +842,7 @@ void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops) cairo_pattern_add_color_stop_rgba ( - m_brushPattern, + m_pattern, stop.GetPosition(), col.Red()/255.0, col.Green()/255.0, @@ -788,7 +851,7 @@ void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops) ); } - wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, + wxASSERT_MSG(cairo_pattern_status(m_pattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); } @@ -797,7 +860,7 @@ wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxGraphicsGradientStops& stops) { - m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2); + m_pattern = cairo_pattern_create_linear(x1,y1,x2,y2); AddGradientStops(stops); } @@ -808,14 +871,15 @@ wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxDouble radius, const wxGraphicsGradientStops& stops) { - m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius); + m_pattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius); AddGradientStops(stops); } void wxCairoBrushData::Init() { - m_brushPattern = NULL; + m_pattern = NULL; + m_bmpdata = NULL; } //----------------------------------------------------------------------------- @@ -1247,13 +1311,13 @@ void wxCairoBitmapData::InitSurface(cairo_format_t format, int stride) } wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap ) : - wxGraphicsObjectRefData( renderer ) + wxGraphicsBitmapData( renderer ) { m_surface = bitmap; m_pattern = cairo_pattern_create_for_surface(m_surface); } -wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsObjectRefData( renderer ) +wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsBitmapData( renderer ) { wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap")); @@ -1262,7 +1326,7 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm // 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 -#ifdef __WXGTK__ +#if defined(__WXGTK__) && !defined(__WXGTK3__) || bmp.GetMask() #endif ? CAIRO_FORMAT_ARGB32 @@ -1335,12 +1399,12 @@ wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitm p.OffsetY(pixData, 1); } } -#ifdef __WXMSW__ +#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(); + wxBitmap bmpMask = bmpSource.GetMask()->GetBitmap(); bufferFormat = CAIRO_FORMAT_ARGB32; data = (wxUint32*)m_buffer; wxNativePixelData @@ -1393,7 +1457,7 @@ inline unsigned char Unpremultiply(unsigned char alpha, unsigned char data) wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer, const wxImage& image) - : wxGraphicsObjectRefData(renderer) + : wxGraphicsBitmapData(renderer) { const cairo_format_t bufferFormat = image.HasAlpha() ? CAIRO_FORMAT_ARGB32 @@ -1634,7 +1698,11 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& Init( cairo_create(m_mswSurface) ); #endif -#ifdef __WXGTK20__ +#ifdef __WXGTK3__ + cairo_t* cr = static_cast(dc.GetImpl()->GetCairoContext()); + if (cr) + Init(cr); +#elif defined __WXGTK20__ wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl(); Init( gdk_cairo_create( impldc->GetGDKWindow() ) ); @@ -1674,11 +1742,42 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& m_enableOffset = true; #ifdef __WXMSW__ - m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC()); + + HDC hdc = (HDC)dc.GetHDC(); + + HBITMAP bitmap = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP); + + BITMAP info; + bool hasBitmap = false; + + // cairo_win32_surface_create creates a 24-bit bitmap, + // so if we have alpha, we need to create a 32-bit surface instead. + if (!GetObject(bitmap, sizeof(info), &info) || info.bmBitsPixel < 32) + m_mswSurface = cairo_win32_surface_create(hdc); + else { + hasBitmap = true; + m_mswSurface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, + CAIRO_FORMAT_ARGB32, + info.bmWidth, + info.bmHeight, + info.bmWidthBytes); + } + Init( cairo_create(m_mswSurface) ); + // If we've created a image surface, we need to flip the Y axis so that + // all drawing will appear right side up. + if (hasBitmap) { + cairo_matrix_t matrix; + cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, height); + cairo_set_matrix(m_context, &matrix); + } #endif -#ifdef __WXGTK20__ +#ifdef __WXGTK3__ + cairo_t* cr = static_cast(dc.GetImpl()->GetCairoContext()); + if (cr) + Init(cr); +#elif defined __WXGTK20__ wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl(); Init( gdk_cairo_create( impldc->GetGDKWindow() ) ); @@ -1708,15 +1807,20 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& } #ifdef __WXGTK20__ -wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ) +wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkWindow *window ) : wxGraphicsContext(renderer) { - Init( gdk_cairo_create( drawable ) ); + Init( gdk_cairo_create( window ) ); +#ifdef __WXGTK3__ + m_width = gdk_window_get_width(window); + m_height = gdk_window_get_height(window); +#else int width, height; - gdk_drawable_get_size( drawable, &width, &height ); + gdk_drawable_get_size(window, &width, &height); m_width = width; m_height = height; +#endif } #endif @@ -1741,7 +1845,10 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ) } wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) -: wxGraphicsContext(renderer) + : wxGraphicsContext(renderer) +#ifdef __WXMSW__ + , m_mswWindowHDC(GetHwndOf(window)) +#endif { m_enableOffset = true; #ifdef __WXGTK__ @@ -1765,7 +1872,7 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) #endif #ifdef __WXMSW__ - m_mswSurface = cairo_win32_surface_create((HDC)window->GetHandle()); + m_mswSurface = cairo_win32_surface_create((HDC)m_mswWindowHDC); Init(cairo_create(m_mswSurface)); #endif @@ -2080,14 +2187,33 @@ void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDoub void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const { widths.Empty(); - widths.Add(0, text.length()); - wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetPartialTextExtents - no valid font set") ); - - if (text.empty()) - return; - +#ifdef __WXGTK__ + const wxCharBuffer data = text.utf8_str(); + int w = 0; + if (data.length()) + { + PangoLayout* layout = pango_cairo_create_layout(m_context); + const wxFont& font = static_cast(m_font.GetRefData())->GetFont(); + pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description); + pango_layout_set_text(layout, data, data.length()); + PangoLayoutIter* iter = pango_layout_get_iter(layout); + PangoRectangle rect; + do { + pango_layout_iter_get_cluster_extents(iter, NULL, &rect); + w += rect.width; + widths.Add(PANGO_PIXELS(w)); + } while (pango_layout_iter_next_cluster(iter)); + pango_layout_iter_free(iter); + g_object_unref(layout); + } + size_t i = widths.GetCount(); + const size_t len = text.length(); + while (i++ < len) + widths.Add(PANGO_PIXELS(w)); +#else // TODO +#endif } void * wxCairoContext::GetNativeContext() @@ -2270,13 +2396,6 @@ public : // create a subimage from a native image representation virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); -protected : - bool EnsureIsLoaded(); - void Load(); - void Unload(); - friend class wxCairoModule; -private : - int m_loaded; DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer) } ; @@ -2287,34 +2406,14 @@ private : IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer,wxGraphicsRenderer) static wxCairoRenderer gs_cairoGraphicsRenderer; -// temporary hack to allow creating a cairo context on any platform -extern wxGraphicsRenderer* gCairoRenderer; -wxGraphicsRenderer* gCairoRenderer = &gs_cairoGraphicsRenderer; -bool wxCairoRenderer::EnsureIsLoaded() -{ -#ifndef __WXGTK__ - Load(); - return wxCairoInit(); +#ifdef __WXGTK__ + #define ENSURE_LOADED_OR_RETURN(returnOnFail) #else - return true; + #define ENSURE_LOADED_OR_RETURN(returnOnFail) \ + if (!wxCairoInit()) \ + return returnOnFail #endif -} - -void wxCairoRenderer::Load() -{ - wxCairoInit(); -} - -void wxCairoRenderer::Unload() -{ - wxCairoCleanUp(); -} - -// call EnsureIsLoaded() and return returnOnFail value if it fails -#define ENSURE_LOADED_OR_RETURN(returnOnFail) \ - if ( !EnsureIsLoaded() ) \ - return (returnOnFail) wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc) { @@ -2338,7 +2437,6 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc) #if wxUSE_ENH_METAFILE wxGraphicsContext * wxCairoRenderer::CreateContext( const wxEnhMetaFileDC& WXUNUSED(dc) ) { - ENSURE_LOADED_OR_RETURN(NULL); return NULL; } #endif @@ -2357,9 +2455,8 @@ wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * cont wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window ) { - ENSURE_LOADED_OR_RETURN(NULL); #ifdef __WXGTK__ - return new wxCairoContext(this,(GdkDrawable*)window); + return new wxCairoContext(this, static_cast(window)); #else wxUnusedVar(window); return NULL; @@ -2369,18 +2466,19 @@ wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * windo #if wxUSE_IMAGE wxGraphicsContext * wxCairoRenderer::CreateContextFromImage(wxImage& image) { + ENSURE_LOADED_OR_RETURN(NULL); return new wxCairoImageContext(this, image); } #endif // wxUSE_IMAGE wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext() { - ENSURE_LOADED_OR_RETURN(NULL); #ifdef __WXGTK__ return CreateContextFromNativeWindow(gdk_get_default_root_window()); -#endif +#else return NULL; // TODO +#endif } wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window ) @@ -2393,8 +2491,8 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window ) wxGraphicsPath wxCairoRenderer::CreatePath() { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath); wxGraphicsPath path; + ENSURE_LOADED_OR_RETURN(path); path.SetRefData( new wxCairoPathData(this) ); return path; } @@ -2406,8 +2504,8 @@ wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble wxDouble tx, wxDouble ty) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix); wxGraphicsMatrix m; + ENSURE_LOADED_OR_RETURN(m); wxCairoMatrixData* data = new wxCairoMatrixData( this ); data->Set( a,b,c,d,tx,ty ) ; m.SetRefData(data); @@ -2416,28 +2514,24 @@ wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen); - if ( !pen.IsOk() || pen.GetStyle() == wxPENSTYLE_TRANSPARENT ) - return wxNullGraphicsPen; - else + wxGraphicsPen p; + ENSURE_LOADED_OR_RETURN(p); + if (pen.IsOk() && pen.GetStyle() != wxPENSTYLE_TRANSPARENT) { - wxGraphicsPen p; p.SetRefData(new wxCairoPenData( this, pen )); - return p; } + return p; } wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); - if ( !brush.IsOk() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT ) - return wxNullGraphicsBrush; - else + wxGraphicsBrush p; + ENSURE_LOADED_OR_RETURN(p); + if (brush.IsOk() && brush.GetStyle() != wxBRUSHSTYLE_TRANSPARENT) { - wxGraphicsBrush p; p.SetRefData(new wxCairoBrushData( this, brush )); - return p; } + return p; } wxGraphicsBrush @@ -2445,8 +2539,8 @@ wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxGraphicsGradientStops& stops) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); wxGraphicsBrush p; + ENSURE_LOADED_OR_RETURN(p); wxCairoBrushData* d = new wxCairoBrushData( this ); d->CreateLinearGradientBrush(x1, y1, x2, y2, stops); p.SetRefData(d); @@ -2458,8 +2552,8 @@ wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble r, const wxGraphicsGradientStops& stops) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush); wxGraphicsBrush p; + ENSURE_LOADED_OR_RETURN(p); wxCairoBrushData* d = new wxCairoBrushData( this ); d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops); p.SetRefData(d); @@ -2468,15 +2562,13 @@ wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo, wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont); + wxGraphicsFont p; + ENSURE_LOADED_OR_RETURN(p); if ( font.IsOk() ) { - wxGraphicsFont p; p.SetRefData(new wxCairoFontData( this , font, col )); - return p; } - else - return wxNullGraphicsFont; + return p; } wxGraphicsFont @@ -2485,24 +2577,21 @@ wxCairoRenderer::CreateFont(double sizeInPixels, int flags, const wxColour& col) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont); - wxGraphicsFont font; + ENSURE_LOADED_OR_RETURN(font); font.SetRefData(new wxCairoFontData(this, sizeInPixels, facename, flags, col)); return font; } wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp ) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap); + wxGraphicsBitmap p; + ENSURE_LOADED_OR_RETURN(p); if ( bmp.IsOk() ) { - wxGraphicsBitmap p; p.SetRefData(new wxCairoBitmapData( this , bmp )); - return p; } - else - return wxNullGraphicsBitmap; + return p; } #if wxUSE_IMAGE @@ -2523,12 +2612,15 @@ wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromImage(const wxImage& image) wxImage wxCairoRenderer::CreateImageFromBitmap(const wxGraphicsBitmap& bmp) { - ENSURE_LOADED_OR_RETURN(wxNullImage); + wxImage image; + ENSURE_LOADED_OR_RETURN(image); const wxCairoBitmapData* const data = static_cast(bmp.GetGraphicsData()); + if (data) + image = data->ConvertToImage(); - return data ? data->ConvertToImage() : wxNullImage; + return image; } #endif // wxUSE_IMAGE @@ -2536,15 +2628,13 @@ wxImage wxCairoRenderer::CreateImageFromBitmap(const wxGraphicsBitmap& bmp) wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromNativeBitmap( void* bitmap ) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap); + wxGraphicsBitmap p; + ENSURE_LOADED_OR_RETURN(p); if ( bitmap != NULL ) { - wxGraphicsBitmap p; p.SetRefData(new wxCairoBitmapData( this , (cairo_surface_t*) bitmap )); - return p; } - else - return wxNullGraphicsBitmap; + return p; } wxGraphicsBitmap @@ -2554,9 +2644,9 @@ wxCairoRenderer::CreateSubBitmap(const wxGraphicsBitmap& WXUNUSED(bitmap), wxDouble WXUNUSED(w), wxDouble WXUNUSED(h)) { - ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap); + wxGraphicsBitmap p; wxFAIL_MSG("wxCairoRenderer::CreateSubBitmap is not implemented."); - return wxNullGraphicsBitmap; + return p; } wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()