X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/08f53168acef5006826b22c11fe562432193d854..cdb7bf66716a4f5c5d0e8b203e52826defdf5906:/src/generic/graphicc.cpp diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 79e6e9387d..6b29c3a902 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -11,38 +11,25 @@ #include "wx/wxprec.h" -#include "wx/dc.h" - #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif +#if wxUSE_GRAPHICS_CONTEXT + #ifndef WX_PRECOMP -#include "wx/image.h" -#include "wx/window.h" -#include "wx/dc.h" -#include "wx/utils.h" -#include "wx/dialog.h" -#include "wx/app.h" -#include "wx/bitmap.h" -#include "wx/dcmemory.h" -#include "wx/log.h" -#include "wx/icon.h" -#include "wx/dcprint.h" -#include "wx/module.h" -#endif + #include "wx/bitmap.h" + #include "wx/icon.h" -#ifdef __WXGTK__ -#include + #include "wx/dc.h" + #include "wx/dcclient.h" + #include "wx/dcmemory.h" + #include "wx/dcprint.h" #endif -#include "wx/graphics.h" +#include "wx/private/graphics.h" #include "wx/rawbmp.h" -#if wxUSE_GRAPHICS_CONTEXT - -#include - using namespace std; //----------------------------------------------------------------------------- @@ -102,6 +89,18 @@ static inline double RadToDeg(double deg) #include #ifdef __WXGTK__ #include +#include "wx/fontutil.h" +#include "wx/gtk/dc.h" +#endif + +#ifdef __WXMSW__ +#include +#endif + +#ifdef __WXMAC__ +#include "wx/osx/private.h" +#include +#include #endif class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData @@ -145,7 +144,7 @@ public : /* - // appends a rectangle as a new closed subpath + // appends a rectangle as a new closed subpath virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ; // appends an ellipsis as a new closed subpath fitting the passed rectangle virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ; @@ -166,7 +165,7 @@ public : // gets the bounding box enclosing all points (possibly including control points) virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const; - virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxWINDING_RULE) const; + virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxWINDING_RULE) const; private : cairo_t* m_pathContext; @@ -184,13 +183,13 @@ public : virtual void Concat( const wxGraphicsMatrixData *t ); // sets the matrix to the respective values - virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, + virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, wxDouble tx=0.0, wxDouble ty=0.0); // gets the component valuess of the matrix virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL, wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const; - + // makes this the inverse matrix virtual void Invert(); @@ -211,7 +210,7 @@ public : virtual void Scale( wxDouble xScale , wxDouble yScale ); // add the rotation to this matrix (radians) - virtual void Rotate( wxDouble angle ); + virtual void Rotate( wxDouble angle ); // // apply the transforms @@ -242,12 +241,12 @@ 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; @@ -266,7 +265,7 @@ public: ~wxCairoBrushData (); virtual void Apply( wxGraphicsContext* context ); - void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2 ); void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, const wxColour &oColor, const wxColour &cColor ); @@ -290,23 +289,34 @@ public: ~wxCairoFontData(); virtual void Apply( wxGraphicsContext* context ); +#ifdef __WXGTK__ + const PangoFontDescription* GetFont() const { return m_font; } + bool GetUnderlined() const { return m_underlined; } +#endif private : - wxCharBuffer m_fontName; double m_size; - cairo_font_slant_t m_slant; - cairo_font_weight_t m_weight; + bool m_underlined; double m_red; double m_green; double m_blue; double m_alpha; +#ifdef __WXMAC__ + cairo_font_face_t *m_font; +#elif defined(__WXGTK__) + PangoFontDescription* m_font; +#else + wxCharBuffer m_fontName; + cairo_font_slant_t m_slant; + cairo_font_weight_t m_weight; +#endif }; class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext { - DECLARE_NO_COPY_CLASS(wxCairoContext) - public: wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ); + wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc ); + wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc ); #ifdef __WXGTK__ wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ); #endif @@ -315,6 +325,18 @@ public: wxCairoContext(); virtual ~wxCairoContext(); + virtual bool ShouldOffset() const + { + int penwidth = 0 ; + if ( !m_pen.IsNull() ) + { + penwidth = (int)((wxCairoPenData*)m_pen.GetRefData())->GetWidth(); + if ( penwidth == 0 ) + penwidth = 1; + } + return ( penwidth % 2 ) == 1; + } + virtual void Clip( const wxRegion ®ion ); // clips drawings to the rect @@ -325,8 +347,10 @@ public: virtual void * GetNativeContext(); + virtual bool SetLogicalFunction( wxRasterOperationMode function ); + virtual void StrokePath( const wxGraphicsPath& p ); - virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxWINDING_RULE ); + virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxWINDING_RULE ); virtual void Translate( wxDouble dx , wxDouble dy ); virtual void Scale( wxDouble xScale , wxDouble yScale ); @@ -346,13 +370,18 @@ public: virtual void PushState(); virtual void PopState(); - virtual void DrawText( const wxString &str, wxDouble x, wxDouble y); virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, wxDouble *descent, wxDouble *externalLeading ) const; virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const; private: + void Init(cairo_t *context); + + virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y ); + cairo_t* m_context; + + DECLARE_NO_COPY_CLASS(wxCairoContext) }; //----------------------------------------------------------------------------- @@ -374,7 +403,7 @@ void wxCairoPenData::Init() wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) : wxGraphicsObjectRefData(renderer) -{ +{ Init(); m_pen = pen; m_width = m_pen.GetWidth(); @@ -382,7 +411,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) m_width = 0.1; m_red = m_pen.GetColour().Red()/255.0; - m_green = m_pen.GetColour().Green()/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; @@ -444,32 +473,32 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) switch ( m_pen.GetStyle() ) { - case wxSOLID : + case wxPENSTYLE_SOLID : break; - case wxDOT : + case wxPENSTYLE_DOT : m_count = WXSIZEOF(dotted); m_userLengths = new double[ m_count ] ; memcpy( m_userLengths, dotted, sizeof(dotted) ); m_lengths = m_userLengths; break; - case wxLONG_DASH : - m_lengths = dotted ; + case wxPENSTYLE_LONG_DASH : + m_lengths = dashed ; m_count = WXSIZEOF(dashed); break; - case wxSHORT_DASH : - m_lengths = dotted ; + case wxPENSTYLE_SHORT_DASH : + m_lengths = short_dashed ; m_count = WXSIZEOF(short_dashed); break; - case wxDOT_DASH : - m_lengths = dotted ; + case wxPENSTYLE_DOT_DASH : + m_lengths = dotted_dashed ; m_count = WXSIZEOF(dotted_dashed); break; - case wxUSER_DASH : + case wxPENSTYLE_USER_DASH : { wxDash *wxdashes ; m_count = m_pen.GetDashes( &wxdashes ) ; @@ -489,7 +518,7 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) m_lengths = m_userLengths ; } break; - case wxSTIPPLE : + case wxPENSTYLE_STIPPLE : { /* wxBitmap* bmp = pen.GetStipple(); @@ -505,29 +534,30 @@ wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) } break; default : - if ( m_pen.GetStyle() >= wxFIRST_HATCH && m_pen.GetStyle() <= wxLAST_HATCH ) + if ( m_pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH + && m_pen.GetStyle() <= wxPENSTYLE_LAST_HATCH ) { /* wxDELETE( m_penBrush ); HatchStyle style = HatchStyleHorizontal; switch( pen.GetStyle() ) { - case wxBDIAGONAL_HATCH : + case wxPENSTYLE_BDIAGONAL_HATCH : style = HatchStyleBackwardDiagonal; break ; - case wxCROSSDIAG_HATCH : + case wxPENSTYLE_CROSSDIAG_HATCH : style = HatchStyleDiagonalCross; break ; - case wxFDIAGONAL_HATCH : + case wxPENSTYLE_FDIAGONAL_HATCH : style = HatchStyleForwardDiagonal; break ; - case wxCROSS_HATCH : + case wxPENSTYLE_CROSS_HATCH : style = HatchStyleCross; break ; - case wxHORIZONTAL_HATCH : + case wxPENSTYLE_HORIZONTAL_HATCH : style = HatchStyleHorizontal; break ; - case wxVERTICAL_HATCH : + case wxPENSTYLE_VERTICAL_HATCH : style = HatchStyleVertical; break ; @@ -565,13 +595,13 @@ wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush : wxGraphicsObjectRefData(renderer) { Init(); - + m_red = brush.GetColour().Red()/255.0; - m_green = brush.GetColour().Green()/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() == wxSOLID) + if ( brush.GetStyle() == wxBRUSHSTYLE_SOLID) { m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() , brush.GetColour().Green() , brush.GetColour().Blue() ) ); @@ -581,22 +611,22 @@ wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush HatchStyle style = HatchStyleHorizontal; switch( brush.GetStyle() ) { - case wxBDIAGONAL_HATCH : + case wxBRUSHSTYLE_BDIAGONAL_HATCH : style = HatchStyleBackwardDiagonal; break ; - case wxCROSSDIAG_HATCH : + case wxBRUSHSTYLE_CROSSDIAG_HATCH : style = HatchStyleDiagonalCross; break ; - case wxFDIAGONAL_HATCH : + case wxBRUSHSTYLE_FDIAGONAL_HATCH : style = HatchStyleForwardDiagonal; break ; - case wxCROSS_HATCH : + case wxBRUSHSTYLE_CROSS_HATCH : style = HatchStyleCross; break ; - case wxHORIZONTAL_HATCH : + case wxBRUSHSTYLE_HORIZONTAL_HATCH : style = HatchStyleHorizontal; break ; - case wxVERTICAL_HATCH : + case wxBRUSHSTYLE_VERTICAL_HATCH : style = HatchStyleVertical; break ; @@ -604,7 +634,7 @@ wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() , brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent ); } - else + else { wxBitmap* bmp = brush.GetStipple(); if ( bmp && bmp->Ok() ) @@ -636,7 +666,7 @@ void wxCairoBrushData::Apply( wxGraphicsContext* context ) } } -void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, +void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2 ) { m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2); @@ -667,32 +697,50 @@ void wxCairoBrushData::Init() // wxCairoFontData implementation //----------------------------------------------------------------------------- -wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, +wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col ) : wxGraphicsObjectRefData(renderer) { m_red = col.Red()/255.0; - m_green = col.Green()/255.0; + m_green = col.Green()/255.0; m_blue = col.Blue()/255.0; m_alpha = col.Alpha()/255.0; - m_size = font.GetPointSize(); + m_underlined = font.GetUnderlined(); + +#ifdef __WXMAC__ + m_font = cairo_atsui_font_face_create_for_atsu_font_id( font.MacGetATSUFontID() ); +#elif defined(__WXGTK__) + m_font = pango_font_description_copy( font.GetNativeFontInfo()->description ); +#else m_fontName = font.GetFaceName().mb_str(wxConvUTF8); m_slant = font.GetStyle() == wxFONTSTYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC:CAIRO_FONT_SLANT_NORMAL; m_weight = font.GetWeight() == wxFONTWEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD:CAIRO_FONT_WEIGHT_NORMAL; +#endif } wxCairoFontData::~wxCairoFontData() { +#ifdef __WXMAC__ + cairo_font_face_destroy( m_font ); +#elif defined(__WXGTK__) + pango_font_description_free( m_font ); +#else +#endif } void wxCairoFontData::Apply( wxGraphicsContext* context ) { cairo_t * ctext = (cairo_t*) context->GetNativeContext(); cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); - cairo_select_font_face(ctext,m_fontName,m_slant,m_weight); - cairo_set_font_size(ctext,m_size); - // TODO UNDERLINE - // TODO FIX SIZE +#ifdef __WXGTK__ + // the rest is done using Pango layouts +#elif defined(__WXMAC__) + cairo_set_font_face(ctext, m_font); + cairo_set_font_size(ctext, m_size ); +#else + cairo_select_font_face(ctext, m_fontName, m_slant, m_weights ); + cairo_set_font_size(ctext, m_size ); +#endif } //----------------------------------------------------------------------------- @@ -786,7 +834,7 @@ void wxCairoPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise ) { - // as clockwise means positive in our system (y pointing downwards) + // as clockwise means positive in our system (y pointing downwards) // TODO make this interpretation dependent of the // real device trans if ( clockwise||(endAngle-startAngle)>=2*M_PI) @@ -796,14 +844,14 @@ void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAn } // transforms each point of this path by the matrix -void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix ) +void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix ) { // as we don't have a true path object, we have to apply the inverse // matrix to the context cairo_matrix_t m = *((cairo_matrix_t*) matrix->GetNativeMatrix()); cairo_matrix_invert( &m ); cairo_transform(m_pathContext,&m); -} +} // gets the bounding box enclosing all points (possibly including control points) void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const @@ -821,7 +869,7 @@ void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) *x = x1; *w = x2-x1; } - + if( y2 < y1 ) { *y = y2; @@ -834,7 +882,7 @@ void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) } } -bool wxCairoPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const +bool wxCairoPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode WXUNUSED(fillStyle) ) const { return cairo_in_stroke( m_pathContext, x, y) != 0; } @@ -850,25 +898,25 @@ wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_m m_matrix = *matrix; } -wxCairoMatrixData::~wxCairoMatrixData() +wxCairoMatrixData::~wxCairoMatrixData() { // nothing to do } -wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const +wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const { return new wxCairoMatrixData(GetRenderer(),&m_matrix); } // concatenates the matrix -void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t ) +void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t ) { - cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix()); + cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix()); } // sets the matrix to the respective values -void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) +void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) { cairo_matrix_init( &m_matrix, a, b, c, d, tx, ty); } @@ -886,21 +934,21 @@ void wxCairoMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c, } // makes this the inverse matrix -void wxCairoMatrixData::Invert() +void wxCairoMatrixData::Invert() { cairo_matrix_invert( &m_matrix ); } // returns true if the elements of the transformation matrix are equal ? -bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const +bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const { const cairo_matrix_t* tm = (cairo_matrix_t*) t->GetNativeMatrix(); - return ( - m_matrix.xx == tm->xx && - m_matrix.yx == tm->yx && - m_matrix.xy == tm->xy && - m_matrix.yy == tm->yy && - m_matrix.x0 == tm->x0 && + return ( + m_matrix.xx == tm->xx && + m_matrix.yx == tm->yx && + m_matrix.xy == tm->xy && + m_matrix.yy == tm->yy && + m_matrix.x0 == tm->x0 && m_matrix.y0 == tm->y0 ) ; } @@ -928,10 +976,10 @@ void wxCairoMatrixData::Scale( wxDouble xScale , wxDouble yScale ) } // add the rotation to this matrix (radians) -void wxCairoMatrixData::Rotate( wxDouble angle ) +void wxCairoMatrixData::Rotate( wxDouble angle ) { cairo_matrix_rotate( &m_matrix, angle) ; -} +} // // apply the transforms @@ -965,32 +1013,125 @@ void * wxCairoMatrixData::GetNativeMatrix() const // 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 __WXGTK20__ + const wxDCImpl *impl = dc.GetImpl(); + Init( (cairo_t*) impl->GetCairoContext() ); + + wxPoint org = dc.GetDeviceOrigin(); + cairo_translate( m_context, org.x, org.y ); + + double sx,sy; + dc.GetUserScale( &sx, &sy ); + cairo_scale( m_context, sx, sy ); + + org = dc.GetLogicalOrigin(); + cairo_translate( m_context, -org.x, -org.y ); +#endif +} + wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ) : wxGraphicsContext(renderer) { -#ifdef __WXGTK__ - m_context = gdk_cairo_create( dc.m_window ) ; +#ifdef __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__ + int width, height; + dc.GetSize( &width, &height ); + 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 - PushState(); - PushState(); } -#ifdef __WXGTK__ +wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc ) +: wxGraphicsContext(renderer) +{ +#ifdef __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__ + int width, height; + dc.GetSize( &width, &height ); + 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 +} + +#ifdef __WXGTK20__ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ) : wxGraphicsContext(renderer) { - m_context = gdk_cairo_create( drawable ) ; - PushState(); - PushState(); + Init( gdk_cairo_create( drawable ) ); } #endif wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ) : wxGraphicsContext(renderer) { - m_context = context ; - PushState(); - PushState(); + Init( context ); } wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) @@ -999,25 +1140,18 @@ wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) #ifdef __WXGTK__ // something along these lines (copied from dcclient) - GtkWidget *widget = window->m_wxwindow; - // Some controls don't have m_wxwindow - like wxStaticBox, but the user // code should still be able to create wxClientDCs for them, so we will // use the parent window here then. - if ( !widget ) + if (window->m_wxwindow == NULL) { window = window->GetParent(); - widget = window->m_wxwindow; } - wxASSERT_MSG( widget, wxT("wxCairoContext needs a widget") ); + wxASSERT_MSG( window->m_wxwindow, wxT("wxCairoContext needs a widget") ); - GtkPizza *pizza = GTK_PIZZA( widget ); - GdkDrawable* drawable = pizza->bin_window; - m_context = gdk_cairo_create( drawable ) ; + Init(gdk_cairo_create(window->GTKGetDrawingWindow())); #endif - PushState(); - PushState(); } wxCairoContext::~wxCairoContext() @@ -1030,6 +1164,13 @@ wxCairoContext::~wxCairoContext() } } +void wxCairoContext::Init(cairo_t *context) +{ + m_context = context ; + PushState(); + PushState(); +} + void wxCairoContext::Clip( const wxRegion& region ) { @@ -1039,16 +1180,16 @@ void wxCairoContext::Clip( const wxRegion& region ) while (ri) { path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH()); - ri++; + ++ri; } - + // Put it in the context cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; cairo_append_path(m_context, cp); // clip to that path cairo_clip(m_context); - path.UnGetNativePath(cp); + path.UnGetNativePath(cp); } void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) @@ -1063,7 +1204,7 @@ void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) // clip to that path cairo_clip(m_context); - path.UnGetNativePath(cp); + path.UnGetNativePath(cp); } void wxCairoContext::ResetClip() @@ -1075,7 +1216,8 @@ void wxCairoContext::ResetClip() void wxCairoContext::StrokePath( const wxGraphicsPath& path ) { if ( !m_pen.IsNull() ) - { + { + wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ; cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; cairo_append_path(m_context,cp); ((wxCairoPenData*)m_pen.GetRefData())->Apply(this); @@ -1084,10 +1226,11 @@ void wxCairoContext::StrokePath( const wxGraphicsPath& path ) } } -void wxCairoContext::FillPath( const wxGraphicsPath& path , int fillStyle ) +void wxCairoContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle ) { if ( !m_brush.IsNull() ) { + wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ; cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; cairo_append_path(m_context,cp); ((wxCairoBrushData*)m_brush.GetRefData())->Apply(this); @@ -1154,7 +1297,7 @@ void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wx wxBitmap bmpSource = bmp; // we need a non-const instance unsigned char* buffer = new unsigned char[bw*bh*4]; wxUint32* data = (wxUint32*)buffer; - + // 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... @@ -1164,7 +1307,7 @@ void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wx buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4); wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh)); wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data.")); - + wxAlphaPixelData::Iterator p(pixData); for (int y=0; yApply(this); +#ifdef __WXGTK__ + size_t datalen = strlen(data); + + PangoLayout *layout = pango_cairo_create_layout (m_context); + wxCairoFontData* font_data = (wxCairoFontData*) m_font.GetRefData(); + pango_layout_set_font_description( layout, font_data->GetFont()); + pango_layout_set_text(layout, data, datalen); + + if (font_data->GetUnderlined()) + { + PangoAttrList *attrs = pango_attr_list_new(); + PangoAttribute *attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + pango_attr_list_insert(attrs, attr); + pango_layout_set_attributes(layout, attrs); + pango_attr_list_unref(attrs); + } + + cairo_move_to(m_context, x, y); + pango_cairo_show_layout (m_context, layout); + + g_object_unref (layout); +#else // Cairo's x,y for drawing text is at the baseline, so we need to adjust // the position we move to by the ascent. cairo_font_extents_t fe; cairo_font_extents(m_context, &fe); cairo_move_to(m_context, x, y+fe.ascent); - - const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); - cairo_show_text(m_context,buf); + + cairo_show_text(m_context, data); +#endif } void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, wxDouble *descent, wxDouble *externalLeading ) const { - if ( m_font.IsNull() || str.empty()) + wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetTextExtent - no valid font set") ); + + if ( width ) + *width = 0; + if ( height ) + *height = 0; + if ( descent ) + *descent = 0; + if ( externalLeading ) + *externalLeading = 0; + + if ( str.empty()) return; +#ifdef __WXGTK__ + int w, h; + + PangoLayout *layout = pango_cairo_create_layout (m_context); + pango_layout_set_font_description( layout, ((wxCairoFontData*)m_font.GetRefData())->GetFont()); + const wxCharBuffer data = str.utf8_str(); + if ( !data ) + { + return; + } + pango_layout_set_text( layout, data, strlen(data) ); + pango_layout_get_pixel_size (layout, &w, &h); + if ( width ) + *width = w; + if ( height ) + *height = h; + if (descent) + { + PangoLayoutIter *iter = pango_layout_get_iter(layout); + int baseline = pango_layout_iter_get_baseline(iter); + pango_layout_iter_free(iter); + *descent = h - PANGO_PIXELS(baseline); + } + g_object_unref (layout); +#else ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this); if (width) @@ -1288,7 +1496,18 @@ void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDoub { cairo_font_extents_t fe; cairo_font_extents(m_context, &fe); - + + // some backends have negative descents + + if ( fe.descent < 0 ) + fe.descent = -fe.descent; + + if ( fe.height < (fe.ascent + fe.descent ) ) + { + // some backends are broken re height ... (eg currently ATSUI) + fe.height = fe.ascent + fe.descent; + } + if (height) *height = fe.height; if ( descent ) @@ -1296,6 +1515,7 @@ void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDoub if ( externalLeading ) *externalLeading = wxMax(0, fe.height - (fe.ascent + fe.descent)); } +#endif } void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const @@ -1303,17 +1523,67 @@ void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths.Empty(); widths.Add(0, text.length()); + wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetPartialTextExtents - no valid font set") ); + if (text.empty()) return; // TODO } -void * wxCairoContext::GetNativeContext() +void * wxCairoContext::GetNativeContext() { return m_context; } +// Cairo doesn't support bitwise logical function (a.k.a. ROP, raster output +// mode). Cairo supports Porter-Duff compositing operators, but they are quite +// different, although in some cases have similar names. +bool wxCairoContext::SetLogicalFunction( wxRasterOperationMode function ) +{ + if (m_logicalFunction == function) + return true; + + cairo_operator_t op; + + switch ( function ) + { + case wxCOPY: // (default) src + op = CAIRO_OPERATOR_OVER; // (also default) + break; + case wxOR: // src OR dst + op = CAIRO_OPERATOR_ADD; + break; + case wxNO_OP: // dst + op = CAIRO_OPERATOR_DEST; // ignore the source + break; + case wxCLEAR: // 0 + op = CAIRO_OPERATOR_CLEAR;// clear dst + break; + + case wxAND: // src AND dst + case wxAND_INVERT: // (NOT src) AND dst + case wxAND_REVERSE:// src AND (NOT dst) + case wxEQUIV: // (NOT src) XOR dst + case wxINVERT: // NOT dst + case wxNAND: // (NOT src) OR (NOT dst) + case wxNOR: // (NOT src) AND (NOT dst) + case wxOR_INVERT: // (NOT src) OR dst + case wxOR_REVERSE: // src OR (NOT dst) + case wxSET: // 1 + case wxSRC_INVERT: // NOT src + //wxXOR does _not_ correspond to CAIRO_OPERATOR_XOR + case wxXOR: // src XOR dst + default: + return false; + } + + m_logicalFunction = function; + cairo_set_operator(m_context, op); + return true; +} + + //----------------------------------------------------------------------------- // wxCairoRenderer declaration //----------------------------------------------------------------------------- @@ -1328,10 +1598,8 @@ public : // Context virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc); - -#ifdef __WXMSW__ virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc); -#endif + virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc); virtual wxGraphicsContext * CreateContextFromNativeContext( void * context ); @@ -1347,7 +1615,7 @@ public : // Matrix - virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, + virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, wxDouble tx=0.0, wxDouble ty=0.0); @@ -1356,10 +1624,10 @@ public : virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2) ; - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) + // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) // with radius r and color cColor virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, const wxColour &oColor, const wxColour &cColor) ; @@ -1367,6 +1635,20 @@ public : // sets the font virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; + // create a native bitmap representation +#if 0 + virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap ) + { + return wxGraphicsBitmap; + } + + // create a subimage from a native image representation + virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) + { + return wxGraphicsBitmap; + } +#endif + private : DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer) } ; @@ -1378,6 +1660,9 @@ 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; #ifdef __WXGTK__ wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() @@ -1391,12 +1676,22 @@ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc) return new wxCairoContext(this,dc); } -#ifdef __WXMSW__ wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc) { - return NULL; + return new wxCairoContext(this,dc); } + +wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc) +{ +#ifdef __WXGTK20__ + const wxDCImpl *impl = dc.GetImpl(); + cairo_t* context = (cairo_t*) impl->GetCairoContext(); + if (context) + return new wxCairoContext(this,dc); + else #endif + return NULL; +} wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context ) { @@ -1436,7 +1731,7 @@ wxGraphicsPath wxCairoRenderer::CreatePath() // Matrix -wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, +wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, wxDouble tx, wxDouble ty) { @@ -1447,7 +1742,7 @@ wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble return m; } -wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) +wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) { if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) return wxNullGraphicsPen; @@ -1459,7 +1754,7 @@ wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) } } -wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) +wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) { if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) return wxNullGraphicsBrush; @@ -1472,8 +1767,8 @@ wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) } // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) +wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2) { wxGraphicsBrush p; wxCairoBrushData* d = new wxCairoBrushData( this ); @@ -1482,10 +1777,10 @@ wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDoubl return p; } -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) +// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) // with radius r and color cColor wxGraphicsBrush wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) + const wxColour &oColor, const wxColour &cColor) { wxGraphicsBrush p; wxCairoBrushData* d = new wxCairoBrushData( this ); @@ -1495,10 +1790,10 @@ wxGraphicsBrush wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDoubl } // sets the font -wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) +wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) { if ( font.Ok() ) - { + { wxGraphicsFont p; p.SetRefData(new wxCairoFontData( this , font, col )); return p;