1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/graphicc.cpp
3 // Purpose: cairo device context class
4 // Author: Stefan Csomor
8 // Copyright: (c) 2006 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
22 #include "wx/window.h"
25 #include "wx/dialog.h"
27 #include "wx/bitmap.h"
28 #include "wx/dcmemory.h"
31 #include "wx/dcprint.h"
32 #include "wx/module.h"
36 #include "wx/gtk/win_gtk.h"
39 #include "wx/graphics.h"
40 #include "wx/rawbmp.h"
42 #if wxUSE_GRAPHICS_CONTEXT
48 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
52 const double RAD2DEG
= 180.0 / M_PI
;
54 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
58 static inline double dmin(double a
, double b
)
62 static inline double dmax(double a
, double b
)
67 static inline double DegToRad(double deg
)
69 return (deg
* M_PI
) / 180.0;
71 static inline double RadToDeg(double deg
)
73 return (deg
* 180.0) / M_PI
;
76 //-----------------------------------------------------------------------------
77 // device context implementation
79 // more and more of the dc functionality should be implemented by calling
80 // the appropricate wxCairoContext, but we will have to do that step by step
81 // also coordinate conversions should be moved to native matrix ops
82 //-----------------------------------------------------------------------------
84 // we always stock two context states, one at entry, to be able to preserve the
85 // state we were called with, the other one after changing to HI Graphics orientation
86 // (this one is used for getting back clippings etc)
88 //-----------------------------------------------------------------------------
89 // wxGraphicsPath implementation
90 //-----------------------------------------------------------------------------
92 // TODO remove this dependency (gdiplus needs the macros)
95 #define max(a,b) (((a) > (b)) ? (a) : (b))
99 #define min(a,b) (((a) < (b)) ? (a) : (b))
107 class WXDLLIMPEXP_CORE wxCairoPathData
: public wxGraphicsPathData
110 wxCairoPathData(wxGraphicsRenderer
* renderer
, cairo_t
* path
= NULL
);
113 virtual wxGraphicsObjectRefData
*Clone() const;
116 // These are the path primitives from which everything else can be constructed
119 // begins a new subpath at (x,y)
120 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
122 // adds a straight line from the current point to (x,y)
123 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
125 // adds a cubic Bezier curve from the current point, using two control points and an end point
126 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
129 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
130 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
132 // gets the last point of the current path, (0,0) if not yet set
133 virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const;
136 virtual void AddPath( const wxGraphicsPathData
* path
);
138 // closes the current sub-path
139 virtual void CloseSubpath();
142 // These are convenience functions which - if not available natively will be assembled
143 // using the primitives from above
148 // appends a rectangle as a new closed subpath
149 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
150 // appends an ellipsis as a new closed subpath fitting the passed rectangle
151 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
153 // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
154 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
157 // returns the native path
158 virtual void * GetNativePath() const ;
160 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
161 virtual void UnGetNativePath(void *p
) const;
163 // transforms each point of this path by the matrix
164 virtual void Transform( const wxGraphicsMatrixData
* matrix
) ;
166 // gets the bounding box enclosing all points (possibly including control points)
167 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const;
169 virtual bool Contains( wxDouble x
, wxDouble y
, int fillStyle
= wxWINDING_RULE
) const;
172 cairo_t
* m_pathContext
;
175 class WXDLLIMPEXP_CORE wxCairoMatrixData
: public wxGraphicsMatrixData
178 wxCairoMatrixData(wxGraphicsRenderer
* renderer
, const cairo_matrix_t
* matrix
= NULL
) ;
179 virtual ~wxCairoMatrixData() ;
181 virtual wxGraphicsObjectRefData
*Clone() const ;
183 // concatenates the matrix
184 virtual void Concat( const wxGraphicsMatrixData
*t
);
186 // sets the matrix to the respective values
187 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
188 wxDouble tx
=0.0, wxDouble ty
=0.0);
190 // gets the component valuess of the matrix
191 virtual void Get(wxDouble
* a
=NULL
, wxDouble
* b
=NULL
, wxDouble
* c
=NULL
,
192 wxDouble
* d
=NULL
, wxDouble
* tx
=NULL
, wxDouble
* ty
=NULL
) const;
194 // makes this the inverse matrix
195 virtual void Invert();
197 // returns true if the elements of the transformation matrix are equal ?
198 virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ;
200 // return true if this is the identity matrix
201 virtual bool IsIdentity() const;
207 // add the translation to this matrix
208 virtual void Translate( wxDouble dx
, wxDouble dy
);
210 // add the scale to this matrix
211 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
213 // add the rotation to this matrix (radians)
214 virtual void Rotate( wxDouble angle
);
217 // apply the transforms
220 // applies that matrix to the point
221 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
) const;
223 // applies the matrix except for translations
224 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const;
226 // returns the native representation
227 virtual void * GetNativeMatrix() const;
229 cairo_matrix_t m_matrix
;
232 class WXDLLIMPEXP_CORE wxCairoPenData
: public wxGraphicsObjectRefData
235 wxCairoPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
240 virtual void Apply( wxGraphicsContext
* context
);
241 virtual wxDouble
GetWidth() { return m_width
; }
251 cairo_line_cap_t m_cap
;
252 cairo_line_join_t m_join
;
255 const double *m_lengths
;
256 double *m_userLengths
;
261 class WXDLLIMPEXP_CORE wxCairoBrushData
: public wxGraphicsObjectRefData
264 wxCairoBrushData( wxGraphicsRenderer
* renderer
);
265 wxCairoBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
266 ~wxCairoBrushData ();
268 virtual void Apply( wxGraphicsContext
* context
);
269 void CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
270 const wxColour
&c1
, const wxColour
&c2
);
271 void CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
272 const wxColour
&oColor
, const wxColour
&cColor
);
283 cairo_pattern_t
* m_brushPattern
;
286 class wxCairoFontData
: public wxGraphicsObjectRefData
289 wxCairoFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
, const wxColour
& col
);
292 virtual void Apply( wxGraphicsContext
* context
);
294 wxCharBuffer m_fontName
;
296 cairo_font_slant_t m_slant
;
297 cairo_font_weight_t m_weight
;
304 class WXDLLIMPEXP_CORE wxCairoContext
: public wxGraphicsContext
306 DECLARE_NO_COPY_CLASS(wxCairoContext
)
309 wxCairoContext( wxGraphicsRenderer
* renderer
, const wxWindowDC
& dc
);
311 wxCairoContext( wxGraphicsRenderer
* renderer
, GdkDrawable
*drawable
);
313 wxCairoContext( wxGraphicsRenderer
* renderer
, cairo_t
*context
);
314 wxCairoContext( wxGraphicsRenderer
* renderer
, wxWindow
*window
);
316 virtual ~wxCairoContext();
318 virtual void Clip( const wxRegion
®ion
);
320 // clips drawings to the rect
321 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
323 // resets the clipping to original extent
324 virtual void ResetClip();
326 virtual void * GetNativeContext();
328 virtual void StrokePath( const wxGraphicsPath
& p
);
329 virtual void FillPath( const wxGraphicsPath
& p
, int fillStyle
= wxWINDING_RULE
);
331 virtual void Translate( wxDouble dx
, wxDouble dy
);
332 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
333 virtual void Rotate( wxDouble angle
);
335 // concatenates this transform with the current transform of this context
336 virtual void ConcatTransform( const wxGraphicsMatrix
& matrix
);
338 // sets the transform of this context
339 virtual void SetTransform( const wxGraphicsMatrix
& matrix
);
341 // gets the matrix of this context
342 virtual wxGraphicsMatrix
GetTransform() const;
344 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
345 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
346 virtual void PushState();
347 virtual void PopState();
349 virtual void DrawText( const wxString
&str
, wxDouble x
, wxDouble y
);
350 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
351 wxDouble
*descent
, wxDouble
*externalLeading
) const;
352 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
358 //-----------------------------------------------------------------------------
359 // wxCairoPenData implementation
360 //-----------------------------------------------------------------------------
362 wxCairoPenData::~wxCairoPenData()
364 delete[] m_userLengths
;
367 void wxCairoPenData::Init()
370 m_userLengths
= NULL
;
375 wxCairoPenData::wxCairoPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
376 : wxGraphicsObjectRefData(renderer
)
380 m_width
= m_pen
.GetWidth();
384 m_red
= m_pen
.GetColour().Red()/255.0;
385 m_green
= m_pen
.GetColour().Green()/255.0;
386 m_blue
= m_pen
.GetColour().Blue()/255.0;
387 m_alpha
= m_pen
.GetColour().Alpha()/255.0;
389 switch ( m_pen
.GetCap() )
392 m_cap
= CAIRO_LINE_CAP_ROUND
;
395 case wxCAP_PROJECTING
:
396 m_cap
= CAIRO_LINE_CAP_SQUARE
;
400 m_cap
= CAIRO_LINE_CAP_BUTT
;
404 m_cap
= CAIRO_LINE_CAP_BUTT
;
408 switch ( m_pen
.GetJoin() )
411 m_join
= CAIRO_LINE_JOIN_BEVEL
;
415 m_join
= CAIRO_LINE_JOIN_MITER
;
419 m_join
= CAIRO_LINE_JOIN_ROUND
;
423 m_join
= CAIRO_LINE_JOIN_MITER
;
427 const double dashUnit
= m_width
< 1.0 ? 1.0 : m_width
;
428 const double dotted
[] =
430 dashUnit
, dashUnit
+ 2.0
432 static const double short_dashed
[] =
436 static const double dashed
[] =
440 static const double dotted_dashed
[] =
442 9.0 , 6.0 , 3.0 , 3.0
445 switch ( m_pen
.GetStyle() )
451 m_count
= WXSIZEOF(dotted
);
452 m_userLengths
= new double[ m_count
] ;
453 memcpy( m_userLengths
, dotted
, sizeof(dotted
) );
454 m_lengths
= m_userLengths
;
459 m_count
= WXSIZEOF(dashed
);
464 m_count
= WXSIZEOF(short_dashed
);
469 m_count
= WXSIZEOF(dotted_dashed
);
475 m_count
= m_pen
.GetDashes( &wxdashes
) ;
476 if ((wxdashes
!= NULL
) && (m_count
> 0))
478 m_userLengths
= new double[m_count
] ;
479 for ( int i
= 0 ; i
< m_count
; ++i
)
481 m_userLengths
[i
] = wxdashes
[i
] * dashUnit
;
483 if ( i
% 2 == 1 && m_userLengths
[i
] < dashUnit
+ 2.0 )
484 m_userLengths
[i
] = dashUnit
+ 2.0 ;
485 else if ( i
% 2 == 0 && m_userLengths
[i
] < dashUnit
)
486 m_userLengths
[i
] = dashUnit
;
489 m_lengths
= m_userLengths
;
495 wxBitmap* bmp = pen.GetStipple();
496 if ( bmp && bmp->Ok() )
498 wxDELETE( m_penImage );
499 wxDELETE( m_penBrush );
500 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
501 m_penBrush = new TextureBrush(m_penImage);
502 m_pen->SetBrush( m_penBrush );
508 if ( m_pen
.GetStyle() >= wxFIRST_HATCH
&& m_pen
.GetStyle() <= wxLAST_HATCH
)
511 wxDELETE( m_penBrush );
512 HatchStyle style = HatchStyleHorizontal;
513 switch( pen.GetStyle() )
515 case wxBDIAGONAL_HATCH :
516 style = HatchStyleBackwardDiagonal;
518 case wxCROSSDIAG_HATCH :
519 style = HatchStyleDiagonalCross;
521 case wxFDIAGONAL_HATCH :
522 style = HatchStyleForwardDiagonal;
525 style = HatchStyleCross;
527 case wxHORIZONTAL_HATCH :
528 style = HatchStyleHorizontal;
530 case wxVERTICAL_HATCH :
531 style = HatchStyleVertical;
535 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
536 pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent );
537 m_pen->SetBrush( m_penBrush )
544 void wxCairoPenData::Apply( wxGraphicsContext
* context
)
546 cairo_t
* ctext
= (cairo_t
*) context
->GetNativeContext();
547 cairo_set_line_width(ctext
,m_width
);
548 cairo_set_source_rgba(ctext
,m_red
,m_green
, m_blue
,m_alpha
);
549 cairo_set_line_cap(ctext
,m_cap
);
550 cairo_set_line_join(ctext
,m_join
);
551 cairo_set_dash(ctext
,(double*)m_lengths
,m_count
,0.0);
554 //-----------------------------------------------------------------------------
555 // wxCairoBrushData implementation
556 //-----------------------------------------------------------------------------
558 wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer
* renderer
)
559 : wxGraphicsObjectRefData( renderer
)
564 wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
565 : wxGraphicsObjectRefData(renderer
)
569 m_red
= brush
.GetColour().Red()/255.0;
570 m_green
= brush
.GetColour().Green()/255.0;
571 m_blue
= brush
.GetColour().Blue()/255.0;
572 m_alpha
= brush
.GetColour().Alpha()/255.0;
574 if ( brush.GetStyle() == wxSOLID)
576 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
577 brush.GetColour().Green() , brush.GetColour().Blue() ) );
579 else if ( brush.IsHatch() )
581 HatchStyle style = HatchStyleHorizontal;
582 switch( brush.GetStyle() )
584 case wxBDIAGONAL_HATCH :
585 style = HatchStyleBackwardDiagonal;
587 case wxCROSSDIAG_HATCH :
588 style = HatchStyleDiagonalCross;
590 case wxFDIAGONAL_HATCH :
591 style = HatchStyleForwardDiagonal;
594 style = HatchStyleCross;
596 case wxHORIZONTAL_HATCH :
597 style = HatchStyleHorizontal;
599 case wxVERTICAL_HATCH :
600 style = HatchStyleVertical;
604 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
605 brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent );
609 wxBitmap* bmp = brush.GetStipple();
610 if ( bmp && bmp->Ok() )
612 wxDELETE( m_brushImage );
613 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
614 m_brush = new TextureBrush(m_brushImage);
620 wxCairoBrushData::~wxCairoBrushData ()
623 cairo_pattern_destroy(m_brushPattern
);
626 void wxCairoBrushData::Apply( wxGraphicsContext
* context
)
628 cairo_t
* ctext
= (cairo_t
*) context
->GetNativeContext();
629 if ( m_brushPattern
)
631 cairo_set_source(ctext
,m_brushPattern
);
635 cairo_set_source_rgba(ctext
,m_red
,m_green
, m_blue
,m_alpha
);
639 void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
640 const wxColour
&c1
, const wxColour
&c2
)
642 m_brushPattern
= cairo_pattern_create_linear(x1
,y1
,x2
,y2
);
643 cairo_pattern_add_color_stop_rgba(m_brushPattern
,0.0,c1
.Red()/255.0,
644 c1
.Green()/255.0, c1
.Blue()/255.0,c1
.Alpha()/255.0);
645 cairo_pattern_add_color_stop_rgba(m_brushPattern
,1.0,c2
.Red()/255.0,
646 c2
.Green()/255.0, c2
.Blue()/255.0,c2
.Alpha()/255.0);
647 wxASSERT_MSG(cairo_pattern_status(m_brushPattern
) == CAIRO_STATUS_SUCCESS
, wxT("Couldn't create cairo pattern"));
650 void wxCairoBrushData::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
651 const wxColour
&oColor
, const wxColour
&cColor
)
653 m_brushPattern
= cairo_pattern_create_radial(xo
,yo
,0.0,xc
,yc
,radius
);
654 cairo_pattern_add_color_stop_rgba(m_brushPattern
,0.0,oColor
.Red()/255.0,
655 oColor
.Green()/255.0, oColor
.Blue()/255.0,oColor
.Alpha()/255.0);
656 cairo_pattern_add_color_stop_rgba(m_brushPattern
,1.0,cColor
.Red()/255.0,
657 cColor
.Green()/255.0, cColor
.Blue()/255.0,cColor
.Alpha()/255.0);
658 wxASSERT_MSG(cairo_pattern_status(m_brushPattern
) == CAIRO_STATUS_SUCCESS
, wxT("Couldn't create cairo pattern"));
661 void wxCairoBrushData::Init()
663 m_brushPattern
= NULL
;
666 //-----------------------------------------------------------------------------
667 // wxCairoFontData implementation
668 //-----------------------------------------------------------------------------
670 wxCairoFontData::wxCairoFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
,
671 const wxColour
& col
) : wxGraphicsObjectRefData(renderer
)
673 m_red
= col
.Red()/255.0;
674 m_green
= col
.Green()/255.0;
675 m_blue
= col
.Blue()/255.0;
676 m_alpha
= col
.Alpha()/255.0;
678 m_size
= font
.GetPointSize();
679 m_fontName
= font
.GetFaceName().mb_str(wxConvUTF8
);
680 m_slant
= font
.GetStyle() == wxFONTSTYLE_ITALIC
? CAIRO_FONT_SLANT_ITALIC
:CAIRO_FONT_SLANT_NORMAL
;
681 m_weight
= font
.GetWeight() == wxFONTWEIGHT_BOLD
? CAIRO_FONT_WEIGHT_BOLD
:CAIRO_FONT_WEIGHT_NORMAL
;
684 wxCairoFontData::~wxCairoFontData()
688 void wxCairoFontData::Apply( wxGraphicsContext
* context
)
690 cairo_t
* ctext
= (cairo_t
*) context
->GetNativeContext();
691 cairo_set_source_rgba(ctext
,m_red
,m_green
, m_blue
,m_alpha
);
692 cairo_select_font_face(ctext
,m_fontName
,m_slant
,m_weight
);
693 cairo_set_font_size(ctext
,m_size
);
698 //-----------------------------------------------------------------------------
699 // wxCairoPathData implementation
700 //-----------------------------------------------------------------------------
702 wxCairoPathData::wxCairoPathData( wxGraphicsRenderer
* renderer
, cairo_t
* pathcontext
)
703 : wxGraphicsPathData(renderer
)
707 m_pathContext
= pathcontext
;
711 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,1,1);
712 m_pathContext
= cairo_create(surface
);
713 cairo_surface_destroy (surface
);
717 wxCairoPathData::~wxCairoPathData()
719 cairo_destroy(m_pathContext
);
722 wxGraphicsObjectRefData
*wxCairoPathData::Clone() const
724 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,1,1);
725 cairo_t
* pathcontext
= cairo_create(surface
);
726 cairo_surface_destroy (surface
);
728 cairo_path_t
* path
= cairo_copy_path(m_pathContext
);
729 cairo_append_path(pathcontext
, path
);
730 cairo_path_destroy(path
);
731 return new wxCairoPathData( GetRenderer() ,pathcontext
);
735 void* wxCairoPathData::GetNativePath() const
737 return cairo_copy_path(m_pathContext
) ;
740 void wxCairoPathData::UnGetNativePath(void *p
) const
742 cairo_path_destroy((cairo_path_t
*)p
);
749 void wxCairoPathData::MoveToPoint( wxDouble x
, wxDouble y
)
751 cairo_move_to(m_pathContext
,x
,y
);
754 void wxCairoPathData::AddLineToPoint( wxDouble x
, wxDouble y
)
756 cairo_line_to(m_pathContext
,x
,y
);
759 void wxCairoPathData::AddPath( const wxGraphicsPathData
* path
)
761 cairo_path_t
* p
= (cairo_path_t
*)path
->GetNativePath();
762 cairo_append_path(m_pathContext
, p
);
766 void wxCairoPathData::CloseSubpath()
768 cairo_close_path(m_pathContext
);
771 void wxCairoPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
773 cairo_curve_to(m_pathContext
,cx1
,cy1
,cx2
,cy2
,x
,y
);
776 // gets the last point of the current path, (0,0) if not yet set
777 void wxCairoPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const
780 cairo_get_current_point(m_pathContext
,&dx
,&dy
);
787 void wxCairoPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
789 // as clockwise means positive in our system (y pointing downwards)
790 // TODO make this interpretation dependent of the
792 if ( clockwise
||(endAngle
-startAngle
)>=2*M_PI
)
793 cairo_arc(m_pathContext
,x
,y
,r
,startAngle
,endAngle
);
795 cairo_arc_negative(m_pathContext
,x
,y
,r
,startAngle
,endAngle
);
798 // transforms each point of this path by the matrix
799 void wxCairoPathData::Transform( const wxGraphicsMatrixData
* matrix
)
801 // as we don't have a true path object, we have to apply the inverse
802 // matrix to the context
803 cairo_matrix_t m
= *((cairo_matrix_t
*) matrix
->GetNativeMatrix());
804 cairo_matrix_invert( &m
);
805 cairo_transform(m_pathContext
,&m
);
808 // gets the bounding box enclosing all points (possibly including control points)
809 void wxCairoPathData::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const
813 cairo_stroke_extents( m_pathContext
, &x1
, &y1
, &x2
, &y2
);
837 bool wxCairoPathData::Contains( wxDouble x
, wxDouble y
, int fillStyle
) const
839 return cairo_in_stroke( m_pathContext
, x
, y
) != 0;
842 //-----------------------------------------------------------------------------
843 // wxCairoMatrixData implementation
844 //-----------------------------------------------------------------------------
846 wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer
* renderer
, const cairo_matrix_t
* matrix
)
847 : wxGraphicsMatrixData(renderer
)
853 wxCairoMatrixData::~wxCairoMatrixData()
858 wxGraphicsObjectRefData
*wxCairoMatrixData::Clone() const
860 return new wxCairoMatrixData(GetRenderer(),&m_matrix
);
863 // concatenates the matrix
864 void wxCairoMatrixData::Concat( const wxGraphicsMatrixData
*t
)
866 cairo_matrix_multiply( &m_matrix
, &m_matrix
, (cairo_matrix_t
*) t
->GetNativeMatrix());
869 // sets the matrix to the respective values
870 void wxCairoMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
871 wxDouble tx
, wxDouble ty
)
873 cairo_matrix_init( &m_matrix
, a
, b
, c
, d
, tx
, ty
);
876 // gets the component valuess of the matrix
877 void wxCairoMatrixData::Get(wxDouble
* a
, wxDouble
* b
, wxDouble
* c
,
878 wxDouble
* d
, wxDouble
* tx
, wxDouble
* ty
) const
880 if (a
) *a
= m_matrix
.xx
;
881 if (b
) *b
= m_matrix
.yx
;
882 if (c
) *c
= m_matrix
.xy
;
883 if (d
) *d
= m_matrix
.yy
;
884 if (tx
) *tx
= m_matrix
.x0
;
885 if (ty
) *ty
= m_matrix
.y0
;
888 // makes this the inverse matrix
889 void wxCairoMatrixData::Invert()
891 cairo_matrix_invert( &m_matrix
);
894 // returns true if the elements of the transformation matrix are equal ?
895 bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const
897 const cairo_matrix_t
* tm
= (cairo_matrix_t
*) t
->GetNativeMatrix();
899 m_matrix
.xx
== tm
->xx
&&
900 m_matrix
.yx
== tm
->yx
&&
901 m_matrix
.xy
== tm
->xy
&&
902 m_matrix
.yy
== tm
->yy
&&
903 m_matrix
.x0
== tm
->x0
&&
904 m_matrix
.y0
== tm
->y0
) ;
907 // return true if this is the identity matrix
908 bool wxCairoMatrixData::IsIdentity() const
910 return ( m_matrix
.xx
== 1 && m_matrix
.yy
== 1 &&
911 m_matrix
.yx
== 0 && m_matrix
.xy
== 0 && m_matrix
.x0
== 0 && m_matrix
.y0
== 0);
918 // add the translation to this matrix
919 void wxCairoMatrixData::Translate( wxDouble dx
, wxDouble dy
)
921 cairo_matrix_translate( &m_matrix
, dx
, dy
) ;
924 // add the scale to this matrix
925 void wxCairoMatrixData::Scale( wxDouble xScale
, wxDouble yScale
)
927 cairo_matrix_scale( &m_matrix
, xScale
, yScale
) ;
930 // add the rotation to this matrix (radians)
931 void wxCairoMatrixData::Rotate( wxDouble angle
)
933 cairo_matrix_rotate( &m_matrix
, angle
) ;
937 // apply the transforms
940 // applies that matrix to the point
941 void wxCairoMatrixData::TransformPoint( wxDouble
*x
, wxDouble
*y
) const
943 double lx
= *x
, ly
= *y
;
944 cairo_matrix_transform_point( &m_matrix
, &lx
, &ly
);
949 // applies the matrix except for translations
950 void wxCairoMatrixData::TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const
952 double lx
= *dx
, ly
= *dy
;
953 cairo_matrix_transform_distance( &m_matrix
, &lx
, &ly
);
958 // returns the native representation
959 void * wxCairoMatrixData::GetNativeMatrix() const
961 return (void*) &m_matrix
;
964 //-----------------------------------------------------------------------------
965 // wxCairoContext implementation
966 //-----------------------------------------------------------------------------
968 wxCairoContext::wxCairoContext( wxGraphicsRenderer
* renderer
, const wxWindowDC
& dc
)
969 : wxGraphicsContext(renderer
)
972 m_context
= gdk_cairo_create( dc
.m_window
) ;
979 wxCairoContext::wxCairoContext( wxGraphicsRenderer
* renderer
, GdkDrawable
*drawable
)
980 : wxGraphicsContext(renderer
)
982 m_context
= gdk_cairo_create( drawable
) ;
988 wxCairoContext::wxCairoContext( wxGraphicsRenderer
* renderer
, cairo_t
*context
)
989 : wxGraphicsContext(renderer
)
991 m_context
= context
;
996 wxCairoContext::wxCairoContext( wxGraphicsRenderer
* renderer
, wxWindow
*window
)
997 : wxGraphicsContext(renderer
)
1000 // something along these lines (copied from dcclient)
1002 GtkWidget
*widget
= window
->m_wxwindow
;
1004 // Some controls don't have m_wxwindow - like wxStaticBox, but the user
1005 // code should still be able to create wxClientDCs for them, so we will
1006 // use the parent window here then.
1009 window
= window
->GetParent();
1010 widget
= window
->m_wxwindow
;
1013 wxASSERT_MSG( widget
, wxT("wxCairoContext needs a widget") );
1015 GtkPizza
*pizza
= GTK_PIZZA( widget
);
1016 GdkDrawable
* drawable
= pizza
->bin_window
;
1017 m_context
= gdk_cairo_create( drawable
) ;
1023 wxCairoContext::~wxCairoContext()
1029 cairo_destroy(m_context
);
1034 void wxCairoContext::Clip( const wxRegion
& region
)
1036 // Create a path with all the rectangles in the region
1037 wxGraphicsPath path
= GetRenderer()->CreatePath();
1038 wxRegionIterator
ri(region
);
1041 path
.AddRectangle(ri
.GetX(), ri
.GetY(), ri
.GetW(), ri
.GetH());
1045 // Put it in the context
1046 cairo_path_t
* cp
= (cairo_path_t
*) path
.GetNativePath() ;
1047 cairo_append_path(m_context
, cp
);
1049 // clip to that path
1050 cairo_clip(m_context
);
1051 path
.UnGetNativePath(cp
);
1054 void wxCairoContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1056 // Create a path with this rectangle
1057 wxGraphicsPath path
= GetRenderer()->CreatePath();
1058 path
.AddRectangle(x
,y
,w
,h
);
1060 // Put it in the context
1061 cairo_path_t
* cp
= (cairo_path_t
*) path
.GetNativePath() ;
1062 cairo_append_path(m_context
, cp
);
1064 // clip to that path
1065 cairo_clip(m_context
);
1066 path
.UnGetNativePath(cp
);
1069 void wxCairoContext::ResetClip()
1071 cairo_reset_clip(m_context
);
1075 void wxCairoContext::StrokePath( const wxGraphicsPath
& path
)
1077 if ( !m_pen
.IsNull() )
1079 cairo_path_t
* cp
= (cairo_path_t
*) path
.GetNativePath() ;
1080 cairo_append_path(m_context
,cp
);
1081 ((wxCairoPenData
*)m_pen
.GetRefData())->Apply(this);
1082 cairo_stroke(m_context
);
1083 path
.UnGetNativePath(cp
);
1087 void wxCairoContext::FillPath( const wxGraphicsPath
& path
, int fillStyle
)
1089 if ( !m_brush
.IsNull() )
1091 cairo_path_t
* cp
= (cairo_path_t
*) path
.GetNativePath() ;
1092 cairo_append_path(m_context
,cp
);
1093 ((wxCairoBrushData
*)m_brush
.GetRefData())->Apply(this);
1094 cairo_set_fill_rule(m_context
,fillStyle
==wxODDEVEN_RULE
? CAIRO_FILL_RULE_EVEN_ODD
: CAIRO_FILL_RULE_WINDING
);
1095 cairo_fill(m_context
);
1096 path
.UnGetNativePath(cp
);
1100 void wxCairoContext::Rotate( wxDouble angle
)
1102 cairo_rotate(m_context
,angle
);
1105 void wxCairoContext::Translate( wxDouble dx
, wxDouble dy
)
1107 cairo_translate(m_context
,dx
,dy
);
1110 void wxCairoContext::Scale( wxDouble xScale
, wxDouble yScale
)
1112 cairo_scale(m_context
,xScale
,yScale
);
1115 // concatenates this transform with the current transform of this context
1116 void wxCairoContext::ConcatTransform( const wxGraphicsMatrix
& matrix
)
1118 cairo_transform(m_context
,(const cairo_matrix_t
*) matrix
.GetNativeMatrix());
1121 // sets the transform of this context
1122 void wxCairoContext::SetTransform( const wxGraphicsMatrix
& matrix
)
1124 cairo_set_matrix(m_context
,(const cairo_matrix_t
*) matrix
.GetNativeMatrix());
1127 // gets the matrix of this context
1128 wxGraphicsMatrix
wxCairoContext::GetTransform() const
1130 wxGraphicsMatrix matrix
= CreateMatrix();
1131 cairo_get_matrix(m_context
,(cairo_matrix_t
*) matrix
.GetNativeMatrix());
1137 void wxCairoContext::PushState()
1139 cairo_save(m_context
);
1142 void wxCairoContext::PopState()
1144 cairo_restore(m_context
);
1147 void wxCairoContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1149 wxCHECK_RET( bmp
.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
1151 cairo_surface_t
* surface
;
1152 int bw
= bmp
.GetWidth();
1153 int bh
= bmp
.GetHeight();
1154 wxBitmap bmpSource
= bmp
; // we need a non-const instance
1155 unsigned char* buffer
= new unsigned char[bw
*bh
*4];
1156 wxUint32
* data
= (wxUint32
*)buffer
;
1158 // Create a surface object and copy the bitmap pixel data to it. if the
1159 // image has alpha (or a mask represented as alpha) then we'll use a
1160 // different format and iterator than if it doesn't...
1161 if (bmpSource
.HasAlpha() || bmpSource
.GetMask())
1163 surface
= cairo_image_surface_create_for_data(
1164 buffer
, CAIRO_FORMAT_ARGB32
, bw
, bh
, bw
*4);
1165 wxAlphaPixelData
pixData(bmpSource
, wxPoint(0,0), wxSize(bw
, bh
));
1166 wxCHECK_RET( pixData
, wxT("Failed to gain raw access to bitmap data."));
1168 wxAlphaPixelData::Iterator
p(pixData
);
1169 for (int y
=0; y
<bh
; y
++)
1171 wxAlphaPixelData::Iterator rowStart
= p
;
1172 for (int x
=0; x
<bw
; x
++)
1174 // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
1175 // with alpha in the upper 8 bits, then red, then green, then
1176 // blue. The 32-bit quantities are stored native-endian.
1177 // Pre-multiplied alpha is used.
1178 unsigned char alpha
= p
.Alpha();
1182 *data
= ( alpha
<< 24
1183 | (p
.Red() * alpha
/255) << 16
1184 | (p
.Green() * alpha
/255) << 8
1185 | (p
.Blue() * alpha
/255) );
1190 p
.OffsetY(pixData
, 1);
1195 surface
= cairo_image_surface_create_for_data(
1196 buffer
, CAIRO_FORMAT_RGB24
, bw
, bh
, bw
*4);
1197 wxNativePixelData
pixData(bmpSource
, wxPoint(0,0), wxSize(bw
, bh
));
1198 wxCHECK_RET( pixData
, wxT("Failed to gain raw access to bitmap data."));
1200 wxNativePixelData::Iterator
p(pixData
);
1201 for (int y
=0; y
<bh
; y
++)
1203 wxNativePixelData::Iterator rowStart
= p
;
1204 for (int x
=0; x
<bw
; x
++)
1206 // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
1207 // the upper 8 bits unused. Red, Green, and Blue are stored in
1208 // the remaining 24 bits in that order. The 32-bit quantities
1209 // are stored native-endian.
1210 *data
= ( p
.Red() << 16 | p
.Green() << 8 | p
.Blue() );
1215 p
.OffsetY(pixData
, 1);
1222 // In case we're scaling the image by using a width and height different
1223 // than the bitmap's size create a pattern transformation on the surface and
1224 // draw the transformed pattern.
1225 cairo_pattern_t
* pattern
= cairo_pattern_create_for_surface(surface
);
1226 wxDouble scaleX
= w
/ bw
;
1227 wxDouble scaleY
= h
/ bh
;
1228 cairo_scale(m_context
, scaleX
, scaleY
);
1230 // prepare to draw the image
1231 cairo_translate(m_context
, x
, y
);
1232 cairo_set_source(m_context
, pattern
);
1233 // use the original size here since the context is scaled already...
1234 cairo_rectangle(m_context
, 0, 0, bw
, bh
);
1235 // fill the rectangle using the pattern
1236 cairo_fill(m_context
);
1239 cairo_pattern_destroy(pattern
);
1240 cairo_surface_destroy(surface
);
1245 void wxCairoContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1247 // An icon is a bitmap on wxGTK, so do this the easy way. When we want to
1248 // start using the Cairo backend on other platforms then we may need to
1249 // fiddle with this...
1250 DrawBitmap(icon
, x
, y
, w
, h
);
1254 void wxCairoContext::DrawText( const wxString
&str
, wxDouble x
, wxDouble y
)
1256 if ( m_font
.IsNull() || str
.empty())
1259 ((wxCairoFontData
*)m_font
.GetRefData())->Apply(this);
1261 // Cairo's x,y for drawing text is at the baseline, so we need to adjust
1262 // the position we move to by the ascent.
1263 cairo_font_extents_t fe
;
1264 cairo_font_extents(m_context
, &fe
);
1265 cairo_move_to(m_context
, x
, y
+fe
.ascent
);
1267 const wxWX2MBbuf
buf(str
.mb_str(wxConvUTF8
));
1268 cairo_show_text(m_context
,buf
);
1271 void wxCairoContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1272 wxDouble
*descent
, wxDouble
*externalLeading
) const
1274 if ( m_font
.IsNull() || str
.empty())
1277 ((wxCairoFontData
*)m_font
.GetRefData())->Apply((wxCairoContext
*)this);
1281 const wxWX2MBbuf
buf(str
.mb_str(wxConvUTF8
));
1282 cairo_text_extents_t te
;
1283 cairo_text_extents(m_context
, buf
, &te
);
1287 if (height
|| descent
|| externalLeading
)
1289 cairo_font_extents_t fe
;
1290 cairo_font_extents(m_context
, &fe
);
1293 *height
= fe
.height
;
1295 *descent
= fe
.descent
;
1296 if ( externalLeading
)
1297 *externalLeading
= wxMax(0, fe
.height
- (fe
.ascent
+ fe
.descent
));
1301 void wxCairoContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1304 widths
.Add(0, text
.length());
1312 void * wxCairoContext::GetNativeContext()
1317 //-----------------------------------------------------------------------------
1318 // wxCairoRenderer declaration
1319 //-----------------------------------------------------------------------------
1321 class WXDLLIMPEXP_CORE wxCairoRenderer
: public wxGraphicsRenderer
1324 wxCairoRenderer() {}
1326 virtual ~wxCairoRenderer() {}
1330 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
1333 virtual wxGraphicsContext
* CreateContext( const wxMemoryDC
& dc
);
1336 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
1338 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
1340 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
1342 virtual wxGraphicsContext
* CreateMeasuringContext();
1346 virtual wxGraphicsPath
CreatePath();
1350 virtual wxGraphicsMatrix
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
1351 wxDouble tx
=0.0, wxDouble ty
=0.0);
1354 virtual wxGraphicsPen
CreatePen(const wxPen
& pen
) ;
1356 virtual wxGraphicsBrush
CreateBrush(const wxBrush
& brush
) ;
1358 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1359 virtual wxGraphicsBrush
CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1360 const wxColour
&c1
, const wxColour
&c2
) ;
1362 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1363 // with radius r and color cColor
1364 virtual wxGraphicsBrush
CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1365 const wxColour
&oColor
, const wxColour
&cColor
) ;
1368 virtual wxGraphicsFont
CreateFont( const wxFont
&font
, const wxColour
&col
= *wxBLACK
) ;
1371 DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer
)
1374 //-----------------------------------------------------------------------------
1375 // wxCairoRenderer implementation
1376 //-----------------------------------------------------------------------------
1378 IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer
,wxGraphicsRenderer
)
1380 static wxCairoRenderer gs_cairoGraphicsRenderer
;
1383 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1385 return &gs_cairoGraphicsRenderer
;
1389 wxGraphicsContext
* wxCairoRenderer::CreateContext( const wxWindowDC
& dc
)
1391 return new wxCairoContext(this,dc
);
1395 wxGraphicsContext
* wxCairoRenderer::CreateContext( const wxMemoryDC
& dc
)
1401 wxGraphicsContext
* wxCairoRenderer::CreateContextFromNativeContext( void * context
)
1403 return new wxCairoContext(this,(cairo_t
*)context
);
1407 wxGraphicsContext
* wxCairoRenderer::CreateContextFromNativeWindow( void * window
)
1410 return new wxCairoContext(this,(GdkDrawable
*)window
);
1416 wxGraphicsContext
* wxCairoRenderer::CreateMeasuringContext()
1422 wxGraphicsContext
* wxCairoRenderer::CreateContext( wxWindow
* window
)
1424 return new wxCairoContext(this, window
);
1429 wxGraphicsPath
wxCairoRenderer::CreatePath()
1431 wxGraphicsPath path
;
1432 path
.SetRefData( new wxCairoPathData(this) );
1439 wxGraphicsMatrix
wxCairoRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1440 wxDouble tx
, wxDouble ty
)
1444 wxCairoMatrixData
* data
= new wxCairoMatrixData( this );
1445 data
->Set( a
,b
,c
,d
,tx
,ty
) ;
1450 wxGraphicsPen
wxCairoRenderer::CreatePen(const wxPen
& pen
)
1452 if ( !pen
.Ok() || pen
.GetStyle() == wxTRANSPARENT
)
1453 return wxNullGraphicsPen
;
1457 p
.SetRefData(new wxCairoPenData( this, pen
));
1462 wxGraphicsBrush
wxCairoRenderer::CreateBrush(const wxBrush
& brush
)
1464 if ( !brush
.Ok() || brush
.GetStyle() == wxTRANSPARENT
)
1465 return wxNullGraphicsBrush
;
1469 p
.SetRefData(new wxCairoBrushData( this, brush
));
1474 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1475 wxGraphicsBrush
wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1476 const wxColour
&c1
, const wxColour
&c2
)
1479 wxCairoBrushData
* d
= new wxCairoBrushData( this );
1480 d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, c1
, c2
);
1485 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1486 // with radius r and color cColor
1487 wxGraphicsBrush
wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1488 const wxColour
&oColor
, const wxColour
&cColor
)
1491 wxCairoBrushData
* d
= new wxCairoBrushData( this );
1492 d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,oColor
,cColor
);
1498 wxGraphicsFont
wxCairoRenderer::CreateFont( const wxFont
&font
, const wxColour
&col
)
1503 p
.SetRefData(new wxCairoFontData( this , font
, col
));
1507 return wxNullGraphicsFont
;
1510 #endif // wxUSE_GRAPHICS_CONTEXT