]> git.saurik.com Git - wxWidgets.git/blame - src/generic/graphicc.cpp
don't forward Enter presses to the default button if any of the ancestor windows...
[wxWidgets.git] / src / generic / graphicc.cpp
CommitLineData
184fc6c8
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/graphicc.cpp
3// Purpose: cairo device context class
4// Author: Stefan Csomor
5// Modified by:
e0876d73 6// Created: 2006-10-03
184fc6c8 7// RCS-ID: $Id$
e0876d73 8// Copyright: (c) 2006 Stefan Csomor
184fc6c8
SC
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#include "wx/dc.h"
15
184fc6c8
SC
16#ifdef __BORLANDC__
17#pragma hdrstop
18#endif
19
20#ifndef WX_PRECOMP
21#include "wx/image.h"
22#include "wx/window.h"
23#include "wx/dc.h"
24#include "wx/utils.h"
25#include "wx/dialog.h"
26#include "wx/app.h"
27#include "wx/bitmap.h"
28#include "wx/dcmemory.h"
29#include "wx/log.h"
30#include "wx/icon.h"
31#include "wx/dcprint.h"
32#include "wx/module.h"
33#endif
34
ed1b38a8 35#ifdef __WXGTK__
08f53168 36#include <gtk/gtk.h>
ed1b38a8
RD
37#endif
38
184fc6c8 39#include "wx/graphics.h"
d9485f89 40#include "wx/rawbmp.h"
184fc6c8 41
7ba86d93
RD
42#if wxUSE_GRAPHICS_CONTEXT
43
184fc6c8
SC
44#include <vector>
45
46using namespace std;
47
48//-----------------------------------------------------------------------------
49// constants
50//-----------------------------------------------------------------------------
51
52const double RAD2DEG = 180.0 / M_PI;
53
54//-----------------------------------------------------------------------------
55// Local functions
56//-----------------------------------------------------------------------------
57
58static inline double dmin(double a, double b)
59{
60 return a < b ? a : b;
61}
62static inline double dmax(double a, double b)
63{
64 return a > b ? a : b;
65}
66
67static inline double DegToRad(double deg)
68{
69 return (deg * M_PI) / 180.0;
70}
71static inline double RadToDeg(double deg)
72{
73 return (deg * 180.0) / M_PI;
74}
75
76//-----------------------------------------------------------------------------
77// device context implementation
78//
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//-----------------------------------------------------------------------------
83
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)
87
88//-----------------------------------------------------------------------------
89// wxGraphicsPath implementation
90//-----------------------------------------------------------------------------
91
92// TODO remove this dependency (gdiplus needs the macros)
93
94#ifndef max
95#define max(a,b) (((a) > (b)) ? (a) : (b))
96#endif
97
98#ifndef min
99#define min(a,b) (((a) < (b)) ? (a) : (b))
100#endif
101
102#include <cairo.h>
00bd8e72 103#ifdef __WXGTK__
e7f9f819 104#include "wx/gtk/win_gtk.h"
184fc6c8 105#include <gtk/gtk.h>
00bd8e72 106#endif
184fc6c8 107
e7f9f819
SC
108#ifdef __WXMSW__
109#include <cairo-win32.h>
110#endif
111
112#ifdef __WXMAC__
113#include "wx/mac/private.h"
114#include <cairo-quartz.h>
115#include <cairo-atsui.h>
116#endif
117
0db8a70e 118class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData
184fc6c8 119{
184fc6c8 120public :
0db8a70e
RD
121 wxCairoPathData(wxGraphicsRenderer* renderer, cairo_t* path = NULL);
122 ~wxCairoPathData();
184fc6c8 123
0db8a70e 124 virtual wxGraphicsObjectRefData *Clone() const;
184fc6c8
SC
125
126 //
127 // These are the path primitives from which everything else can be constructed
128 //
129
130 // begins a new subpath at (x,y)
131 virtual void MoveToPoint( wxDouble x, wxDouble y );
132
133 // adds a straight line from the current point to (x,y)
134 virtual void AddLineToPoint( wxDouble x, wxDouble y );
135
136 // adds a cubic Bezier curve from the current point, using two control points and an end point
137 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
138
139
140 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
141 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
142
143 // gets the last point of the current path, (0,0) if not yet set
0db8a70e 144 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
184fc6c8 145
00bd8e72 146 // adds another path
0db8a70e 147 virtual void AddPath( const wxGraphicsPathData* path );
00bd8e72 148
184fc6c8
SC
149 // closes the current sub-path
150 virtual void CloseSubpath();
151
152 //
153 // These are convenience functions which - if not available natively will be assembled
154 // using the primitives from above
155 //
156
157 /*
158
159 // appends a rectangle as a new closed subpath
160 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
161 // appends an ellipsis as a new closed subpath fitting the passed rectangle
162 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
163
164 // 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)
165 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
166 */
167
cd5adaa6
RD
168 // returns the native path
169 virtual void * GetNativePath() const ;
170
171 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
0db8a70e 172 virtual void UnGetNativePath(void *p) const;
f540e5bd 173
00bd8e72 174 // transforms each point of this path by the matrix
0db8a70e 175 virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
00bd8e72
SC
176
177 // gets the bounding box enclosing all points (possibly including control points)
0db8a70e 178 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
00bd8e72 179
0db8a70e 180 virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxWINDING_RULE) const;
00bd8e72 181
184fc6c8
SC
182private :
183 cairo_t* m_pathContext;
184};
185
0db8a70e 186class WXDLLIMPEXP_CORE wxCairoMatrixData : public wxGraphicsMatrixData
184fc6c8 187{
00bd8e72 188public :
0db8a70e
RD
189 wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix = NULL ) ;
190 virtual ~wxCairoMatrixData() ;
184fc6c8 191
0db8a70e 192 virtual wxGraphicsObjectRefData *Clone() const ;
184fc6c8 193
00bd8e72 194 // concatenates the matrix
0db8a70e 195 virtual void Concat( const wxGraphicsMatrixData *t );
184fc6c8 196
00bd8e72
SC
197 // sets the matrix to the respective values
198 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
199 wxDouble tx=0.0, wxDouble ty=0.0);
184fc6c8 200
248802d0
RD
201 // gets the component valuess of the matrix
202 virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL,
203 wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const;
204
00bd8e72
SC
205 // makes this the inverse matrix
206 virtual void Invert();
184fc6c8 207
00bd8e72 208 // returns true if the elements of the transformation matrix are equal ?
0db8a70e 209 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
184fc6c8 210
00bd8e72 211 // return true if this is the identity matrix
0db8a70e 212 virtual bool IsIdentity() const;
184fc6c8 213
00bd8e72
SC
214 //
215 // transformation
216 //
184fc6c8 217
00bd8e72
SC
218 // add the translation to this matrix
219 virtual void Translate( wxDouble dx , wxDouble dy );
220
221 // add the scale to this matrix
222 virtual void Scale( wxDouble xScale , wxDouble yScale );
223
224 // add the rotation to this matrix (radians)
225 virtual void Rotate( wxDouble angle );
226
227 //
228 // apply the transforms
229 //
230
231 // applies that matrix to the point
0db8a70e 232 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
00bd8e72
SC
233
234 // applies the matrix except for translations
0db8a70e 235 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
00bd8e72
SC
236
237 // returns the native representation
238 virtual void * GetNativeMatrix() const;
239private:
240 cairo_matrix_t m_matrix ;
00bd8e72
SC
241} ;
242
87752530 243class WXDLLIMPEXP_CORE wxCairoPenData : public wxGraphicsObjectRefData
184fc6c8 244{
00bd8e72 245public:
87752530
SC
246 wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
247 ~wxCairoPenData();
00bd8e72
SC
248
249 void Init();
250
251 virtual void Apply( wxGraphicsContext* context );
252 virtual wxDouble GetWidth() { return m_width; }
253
254private :
255 double m_width;
256
257 double m_red;
258 double m_green;
259 double m_blue;
260 double m_alpha;
261
262 cairo_line_cap_t m_cap;
263 cairo_line_join_t m_join;
264
265 int m_count;
266 const double *m_lengths;
267 double *m_userLengths;
184fc6c8 268
00bd8e72 269 wxPen m_pen;
00bd8e72
SC
270};
271
87752530 272class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData
184fc6c8 273{
00bd8e72 274public:
87752530
SC
275 wxCairoBrushData( wxGraphicsRenderer* renderer );
276 wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
277 ~wxCairoBrushData ();
00bd8e72
SC
278
279 virtual void Apply( wxGraphicsContext* context );
280 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
281 const wxColour&c1, const wxColour&c2 );
282 void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
283 const wxColour &oColor, const wxColour &cColor );
284
285protected:
286 virtual void Init();
287
288private :
289 double m_red;
290 double m_green;
291 double m_blue;
292 double m_alpha;
293
294 cairo_pattern_t* m_brushPattern;
00bd8e72
SC
295};
296
87752530 297class wxCairoFontData : public wxGraphicsObjectRefData
184fc6c8 298{
00bd8e72 299public:
87752530
SC
300 wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
301 ~wxCairoFontData();
00bd8e72
SC
302
303 virtual void Apply( wxGraphicsContext* context );
304private :
305 wxCharBuffer m_fontName;
306 double m_size;
307 cairo_font_slant_t m_slant;
308 cairo_font_weight_t m_weight;
309 double m_red;
310 double m_green;
311 double m_blue;
312 double m_alpha;
e7f9f819
SC
313 cairo_font_face_t *m_font;
314 wxFont m_wxFont;
00bd8e72 315};
184fc6c8 316
00bd8e72 317class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext
184fc6c8
SC
318{
319 DECLARE_NO_COPY_CLASS(wxCairoContext)
320
321public:
00bd8e72
SC
322 wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc );
323#ifdef __WXGTK__
324 wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable );
325#endif
326 wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context );
327 wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window);
184fc6c8
SC
328 wxCairoContext();
329 virtual ~wxCairoContext();
330
e7f9f819
SC
331 virtual bool ShouldOffset() const
332 {
333 int penwidth = 0 ;
334 if ( !m_pen.IsNull() )
335 {
336 penwidth = (int)((wxCairoPenData*)m_pen.GetRefData())->GetWidth();
337 if ( penwidth == 0 )
338 penwidth = 1;
339 }
340 return ( penwidth % 2 ) == 1;
341 }
342
184fc6c8 343 virtual void Clip( const wxRegion &region );
539e2795
SC
344
345 // clips drawings to the rect
346 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
539e2795 347
cd5adaa6
RD
348 // resets the clipping to original extent
349 virtual void ResetClip();
350
351 virtual void * GetNativeContext();
352
0db8a70e
RD
353 virtual void StrokePath( const wxGraphicsPath& p );
354 virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxWINDING_RULE );
184fc6c8 355
184fc6c8
SC
356 virtual void Translate( wxDouble dx , wxDouble dy );
357 virtual void Scale( wxDouble xScale , wxDouble yScale );
358 virtual void Rotate( wxDouble angle );
359
00bd8e72 360 // concatenates this transform with the current transform of this context
0db8a70e 361 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
00bd8e72
SC
362
363 // sets the transform of this context
0db8a70e 364 virtual void SetTransform( const wxGraphicsMatrix& matrix );
00bd8e72
SC
365
366 // gets the matrix of this context
0db8a70e 367 virtual wxGraphicsMatrix GetTransform() const;
00bd8e72 368
184fc6c8
SC
369 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
370 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
371 virtual void PushState();
372 virtual void PopState();
373
184fc6c8
SC
374 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y);
375 virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
376 wxDouble *descent, wxDouble *externalLeading ) const;
377 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
378
379private:
e7f9f819
SC
380 void Init(cairo_t *context);
381
184fc6c8 382 cairo_t* m_context;
184fc6c8
SC
383};
384
184fc6c8 385//-----------------------------------------------------------------------------
87752530 386// wxCairoPenData implementation
184fc6c8
SC
387//-----------------------------------------------------------------------------
388
87752530 389wxCairoPenData::~wxCairoPenData()
539e2795 390{
00bd8e72 391 delete[] m_userLengths;
539e2795 392}
cd5adaa6 393
87752530 394void wxCairoPenData::Init()
539e2795 395{
00bd8e72
SC
396 m_lengths = NULL;
397 m_userLengths = NULL;
398 m_width = 0;
399 m_count = 0;
539e2795
SC
400}
401
87752530
SC
402wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
403: wxGraphicsObjectRefData(renderer)
00bd8e72
SC
404{
405 Init();
7f8bd9fc
RD
406 m_pen = pen;
407 m_width = m_pen.GetWidth();
00bd8e72
SC
408 if (m_width <= 0.0)
409 m_width = 0.1;
539e2795 410
00bd8e72
SC
411 m_red = m_pen.GetColour().Red()/255.0;
412 m_green = m_pen.GetColour().Green()/255.0;
413 m_blue = m_pen.GetColour().Blue()/255.0;
414 m_alpha = m_pen.GetColour().Alpha()/255.0;
184fc6c8 415
184fc6c8
SC
416 switch ( m_pen.GetCap() )
417 {
418 case wxCAP_ROUND :
00bd8e72 419 m_cap = CAIRO_LINE_CAP_ROUND;
184fc6c8
SC
420 break;
421
422 case wxCAP_PROJECTING :
00bd8e72 423 m_cap = CAIRO_LINE_CAP_SQUARE;
184fc6c8
SC
424 break;
425
426 case wxCAP_BUTT :
00bd8e72 427 m_cap = CAIRO_LINE_CAP_BUTT;
184fc6c8
SC
428 break;
429
430 default :
00bd8e72 431 m_cap = CAIRO_LINE_CAP_BUTT;
184fc6c8
SC
432 break;
433 }
184fc6c8 434
184fc6c8
SC
435 switch ( m_pen.GetJoin() )
436 {
437 case wxJOIN_BEVEL :
00bd8e72 438 m_join = CAIRO_LINE_JOIN_BEVEL;
184fc6c8
SC
439 break;
440
441 case wxJOIN_MITER :
00bd8e72 442 m_join = CAIRO_LINE_JOIN_MITER;
184fc6c8
SC
443 break;
444
445 case wxJOIN_ROUND :
00bd8e72 446 m_join = CAIRO_LINE_JOIN_ROUND;
184fc6c8
SC
447 break;
448
449 default :
00bd8e72 450 m_join = CAIRO_LINE_JOIN_MITER;
184fc6c8
SC
451 break;
452 }
184fc6c8 453
00bd8e72 454 const double dashUnit = m_width < 1.0 ? 1.0 : m_width;
184fc6c8 455 const double dotted[] =
00bd8e72
SC
456 {
457 dashUnit , dashUnit + 2.0
458 };
459 static const double short_dashed[] =
460 {
461 9.0 , 6.0
462 };
463 static const double dashed[] =
464 {
465 19.0 , 9.0
466 };
467 static const double dotted_dashed[] =
468 {
469 9.0 , 6.0 , 3.0 , 3.0
470 };
184fc6c8
SC
471
472 switch ( m_pen.GetStyle() )
473 {
474 case wxSOLID :
475 break;
476
477 case wxDOT :
00bd8e72
SC
478 m_count = WXSIZEOF(dotted);
479 m_userLengths = new double[ m_count ] ;
480 memcpy( m_userLengths, dotted, sizeof(dotted) );
481 m_lengths = m_userLengths;
184fc6c8
SC
482 break;
483
484 case wxLONG_DASH :
00bd8e72
SC
485 m_lengths = dotted ;
486 m_count = WXSIZEOF(dashed);
184fc6c8
SC
487 break;
488
489 case wxSHORT_DASH :
00bd8e72
SC
490 m_lengths = dotted ;
491 m_count = WXSIZEOF(short_dashed);
184fc6c8
SC
492 break;
493
494 case wxDOT_DASH :
00bd8e72
SC
495 m_lengths = dotted ;
496 m_count = WXSIZEOF(dotted_dashed);
184fc6c8
SC
497 break;
498
499 case wxUSER_DASH :
500 {
501 wxDash *wxdashes ;
00bd8e72
SC
502 m_count = m_pen.GetDashes( &wxdashes ) ;
503 if ((wxdashes != NULL) && (m_count > 0))
184fc6c8 504 {
00bd8e72
SC
505 m_userLengths = new double[m_count] ;
506 for ( int i = 0 ; i < m_count ; ++i )
184fc6c8 507 {
00bd8e72 508 m_userLengths[i] = wxdashes[i] * dashUnit ;
184fc6c8 509
00bd8e72
SC
510 if ( i % 2 == 1 && m_userLengths[i] < dashUnit + 2.0 )
511 m_userLengths[i] = dashUnit + 2.0 ;
512 else if ( i % 2 == 0 && m_userLengths[i] < dashUnit )
513 m_userLengths[i] = dashUnit ;
184fc6c8
SC
514 }
515 }
00bd8e72 516 m_lengths = m_userLengths ;
184fc6c8
SC
517 }
518 break;
519 case wxSTIPPLE :
520 {
521 /*
00bd8e72
SC
522 wxBitmap* bmp = pen.GetStipple();
523 if ( bmp && bmp->Ok() )
524 {
525 wxDELETE( m_penImage );
526 wxDELETE( m_penBrush );
527 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
528 m_penBrush = new TextureBrush(m_penImage);
529 m_pen->SetBrush( m_penBrush );
530 }
184fc6c8
SC
531 */
532 }
533 break;
534 default :
535 if ( m_pen.GetStyle() >= wxFIRST_HATCH && m_pen.GetStyle() <= wxLAST_HATCH )
536 {
537 /*
00bd8e72
SC
538 wxDELETE( m_penBrush );
539 HatchStyle style = HatchStyleHorizontal;
540 switch( pen.GetStyle() )
541 {
542 case wxBDIAGONAL_HATCH :
543 style = HatchStyleBackwardDiagonal;
544 break ;
545 case wxCROSSDIAG_HATCH :
546 style = HatchStyleDiagonalCross;
547 break ;
548 case wxFDIAGONAL_HATCH :
549 style = HatchStyleForwardDiagonal;
550 break ;
551 case wxCROSS_HATCH :
552 style = HatchStyleCross;
553 break ;
554 case wxHORIZONTAL_HATCH :
555 style = HatchStyleHorizontal;
556 break ;
557 case wxVERTICAL_HATCH :
558 style = HatchStyleVertical;
559 break ;
560
561 }
562 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
563 pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent );
564 m_pen->SetBrush( m_penBrush )
184fc6c8
SC
565 */
566 }
567 break;
568 }
00bd8e72 569}
184fc6c8 570
87752530 571void wxCairoPenData::Apply( wxGraphicsContext* context )
00bd8e72
SC
572{
573 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
574 cairo_set_line_width(ctext,m_width);
575 cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
576 cairo_set_line_cap(ctext,m_cap);
577 cairo_set_line_join(ctext,m_join);
578 cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0);
184fc6c8
SC
579}
580
00bd8e72 581//-----------------------------------------------------------------------------
87752530 582// wxCairoBrushData implementation
00bd8e72
SC
583//-----------------------------------------------------------------------------
584
7f8bd9fc
RD
585wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer )
586 : wxGraphicsObjectRefData( renderer )
00bd8e72
SC
587{
588 Init();
589}
184fc6c8 590
87752530 591wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush )
7f8bd9fc 592 : wxGraphicsObjectRefData(renderer)
00bd8e72 593{
7f8bd9fc
RD
594 Init();
595
00bd8e72
SC
596 m_red = brush.GetColour().Red()/255.0;
597 m_green = brush.GetColour().Green()/255.0;
598 m_blue = brush.GetColour().Blue()/255.0;
599 m_alpha = brush.GetColour().Alpha()/255.0;
600 /*
601 if ( brush.GetStyle() == wxSOLID)
602 {
603 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
604 brush.GetColour().Green() , brush.GetColour().Blue() ) );
605 }
606 else if ( brush.IsHatch() )
607 {
608 HatchStyle style = HatchStyleHorizontal;
609 switch( brush.GetStyle() )
610 {
611 case wxBDIAGONAL_HATCH :
612 style = HatchStyleBackwardDiagonal;
613 break ;
614 case wxCROSSDIAG_HATCH :
615 style = HatchStyleDiagonalCross;
616 break ;
617 case wxFDIAGONAL_HATCH :
618 style = HatchStyleForwardDiagonal;
619 break ;
620 case wxCROSS_HATCH :
621 style = HatchStyleCross;
622 break ;
623 case wxHORIZONTAL_HATCH :
624 style = HatchStyleHorizontal;
625 break ;
626 case wxVERTICAL_HATCH :
627 style = HatchStyleVertical;
628 break ;
629
630 }
631 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
632 brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent );
633 }
634 else
635 {
636 wxBitmap* bmp = brush.GetStipple();
637 if ( bmp && bmp->Ok() )
638 {
639 wxDELETE( m_brushImage );
640 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
641 m_brush = new TextureBrush(m_brushImage);
642 }
184fc6c8 643 }
00bd8e72 644 */
184fc6c8
SC
645}
646
87752530 647wxCairoBrushData::~wxCairoBrushData ()
184fc6c8 648{
00bd8e72
SC
649 if (m_brushPattern)
650 cairo_pattern_destroy(m_brushPattern);
184fc6c8
SC
651}
652
87752530 653void wxCairoBrushData::Apply( wxGraphicsContext* context )
184fc6c8 654{
00bd8e72
SC
655 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
656 if ( m_brushPattern )
657 {
658 cairo_set_source(ctext,m_brushPattern);
659 }
660 else
661 {
662 cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
663 }
184fc6c8
SC
664}
665
87752530 666void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
00bd8e72 667 const wxColour&c1, const wxColour&c2 )
184fc6c8 668{
00bd8e72
SC
669 m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2);
670 cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,c1.Red()/255.0,
671 c1.Green()/255.0, c1.Blue()/255.0,c1.Alpha()/255.0);
672 cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,c2.Red()/255.0,
673 c2.Green()/255.0, c2.Blue()/255.0,c2.Alpha()/255.0);
674 wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern"));
184fc6c8
SC
675}
676
87752530 677void wxCairoBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
00bd8e72 678 const wxColour &oColor, const wxColour &cColor )
184fc6c8 679{
00bd8e72
SC
680 m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
681 cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,oColor.Red()/255.0,
682 oColor.Green()/255.0, oColor.Blue()/255.0,oColor.Alpha()/255.0);
683 cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,cColor.Red()/255.0,
684 cColor.Green()/255.0, cColor.Blue()/255.0,cColor.Alpha()/255.0);
685 wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern"));
184fc6c8
SC
686}
687
87752530 688void wxCairoBrushData::Init()
184fc6c8 689{
00bd8e72 690 m_brushPattern = NULL;
184fc6c8
SC
691}
692
00bd8e72 693//-----------------------------------------------------------------------------
87752530 694// wxCairoFontData implementation
00bd8e72
SC
695//-----------------------------------------------------------------------------
696
87752530
SC
697wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font,
698 const wxColour& col ) : wxGraphicsObjectRefData(renderer)
184fc6c8 699{
00bd8e72
SC
700 m_red = col.Red()/255.0;
701 m_green = col.Green()/255.0;
702 m_blue = col.Blue()/255.0;
703 m_alpha = col.Alpha()/255.0;
704
705 m_size = font.GetPointSize();
706 m_fontName = font.GetFaceName().mb_str(wxConvUTF8);
707 m_slant = font.GetStyle() == wxFONTSTYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC:CAIRO_FONT_SLANT_NORMAL;
708 m_weight = font.GetWeight() == wxFONTWEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD:CAIRO_FONT_WEIGHT_NORMAL;
e7f9f819
SC
709#ifdef __WXMAC__
710 m_font = cairo_atsui_font_face_create_for_atsu_font_id( font.MacGetATSUFontID() );
711#endif
712#ifdef __WXMSW__
713#endif
714#ifdef __WXGTK__
715 // Pango implementation uses the native descriptor
716 m_font = NULL;
717 m_wxFont = font;
718#endif
184fc6c8
SC
719}
720
87752530 721wxCairoFontData::~wxCairoFontData()
184fc6c8 722{
e7f9f819 723 cairo_font_face_destroy( m_font );
00bd8e72 724}
184fc6c8 725
87752530 726void wxCairoFontData::Apply( wxGraphicsContext* context )
00bd8e72 727{
e7f9f819
SC
728#ifdef __WXGTK__
729 // Pango handled differently
730#else
00bd8e72
SC
731 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
732 cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
e7f9f819 733 cairo_set_font_face(ctext, m_font );
00bd8e72
SC
734 // TODO UNDERLINE
735 // TODO FIX SIZE
e7f9f819 736#endif
00bd8e72
SC
737}
738
739//-----------------------------------------------------------------------------
0db8a70e 740// wxCairoPathData implementation
00bd8e72
SC
741//-----------------------------------------------------------------------------
742
0db8a70e
RD
743wxCairoPathData::wxCairoPathData( wxGraphicsRenderer* renderer, cairo_t* pathcontext)
744 : wxGraphicsPathData(renderer)
184fc6c8 745{
00bd8e72 746 if (pathcontext)
184fc6c8 747 {
00bd8e72
SC
748 m_pathContext = pathcontext;
749 }
750 else
751 {
752 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1);
753 m_pathContext = cairo_create(surface);
754 cairo_surface_destroy (surface);
184fc6c8 755 }
00bd8e72 756}
184fc6c8 757
0db8a70e 758wxCairoPathData::~wxCairoPathData()
00bd8e72
SC
759{
760 cairo_destroy(m_pathContext);
184fc6c8
SC
761}
762
0db8a70e 763wxGraphicsObjectRefData *wxCairoPathData::Clone() const
184fc6c8 764{
00bd8e72
SC
765 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1);
766 cairo_t* pathcontext = cairo_create(surface);
767 cairo_surface_destroy (surface);
768
769 cairo_path_t* path = cairo_copy_path(m_pathContext);
770 cairo_append_path(pathcontext, path);
771 cairo_path_destroy(path);
0db8a70e 772 return new wxCairoPathData( GetRenderer() ,pathcontext);
00bd8e72
SC
773}
774
775
0db8a70e 776void* wxCairoPathData::GetNativePath() const
00bd8e72
SC
777{
778 return cairo_copy_path(m_pathContext) ;
779}
780
0db8a70e 781void wxCairoPathData::UnGetNativePath(void *p) const
00bd8e72
SC
782{
783 cairo_path_destroy((cairo_path_t*)p);
784}
785
786//
787// The Primitives
788//
789
0db8a70e 790void wxCairoPathData::MoveToPoint( wxDouble x , wxDouble y )
00bd8e72
SC
791{
792 cairo_move_to(m_pathContext,x,y);
793}
794
0db8a70e 795void wxCairoPathData::AddLineToPoint( wxDouble x , wxDouble y )
00bd8e72
SC
796{
797 cairo_line_to(m_pathContext,x,y);
798}
799
0db8a70e 800void wxCairoPathData::AddPath( const wxGraphicsPathData* path )
6b06903d 801{
d9485f89
RD
802 cairo_path_t* p = (cairo_path_t*)path->GetNativePath();
803 cairo_append_path(m_pathContext, p);
804 UnGetNativePath(p);
6b06903d
RD
805}
806
0db8a70e 807void wxCairoPathData::CloseSubpath()
00bd8e72
SC
808{
809 cairo_close_path(m_pathContext);
810}
811
0db8a70e 812void wxCairoPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
00bd8e72
SC
813{
814 cairo_curve_to(m_pathContext,cx1,cy1,cx2,cy2,x,y);
815}
816
817// gets the last point of the current path, (0,0) if not yet set
0db8a70e 818void wxCairoPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
00bd8e72
SC
819{
820 double dx,dy;
821 cairo_get_current_point(m_pathContext,&dx,&dy);
0db8a70e
RD
822 if (x)
823 *x = dx;
824 if (y)
825 *y = dy;
00bd8e72
SC
826}
827
0db8a70e 828void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
00bd8e72
SC
829{
830 // as clockwise means positive in our system (y pointing downwards)
831 // TODO make this interpretation dependent of the
832 // real device trans
833 if ( clockwise||(endAngle-startAngle)>=2*M_PI)
834 cairo_arc(m_pathContext,x,y,r,startAngle,endAngle);
835 else
836 cairo_arc_negative(m_pathContext,x,y,r,startAngle,endAngle);
837}
838
839// transforms each point of this path by the matrix
0db8a70e 840void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix )
00bd8e72
SC
841{
842 // as we don't have a true path object, we have to apply the inverse
843 // matrix to the context
844 cairo_matrix_t m = *((cairo_matrix_t*) matrix->GetNativeMatrix());
845 cairo_matrix_invert( &m );
846 cairo_transform(m_pathContext,&m);
847}
848
849// gets the bounding box enclosing all points (possibly including control points)
0db8a70e 850void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
00bd8e72
SC
851{
852 double x1,y1,x2,y2;
853
854 cairo_stroke_extents( m_pathContext, &x1, &y1, &x2, &y2 );
855 if ( x2 < x1 )
184fc6c8 856 {
00bd8e72
SC
857 *x = x2;
858 *w = x1-x2;
859 }
860 else
861 {
862 *x = x1;
863 *w = x2-x1;
184fc6c8
SC
864 }
865
00bd8e72
SC
866 if( y2 < y1 )
867 {
868 *y = y2;
869 *h = y1-y2;
870 }
871 else
872 {
873 *y = y1;
874 *h = y2-y1;
875 }
876}
877
0db8a70e 878bool wxCairoPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const
00bd8e72 879{
0db8a70e 880 return cairo_in_stroke( m_pathContext, x, y) != 0;
00bd8e72
SC
881}
882
883//-----------------------------------------------------------------------------
0db8a70e 884// wxCairoMatrixData implementation
00bd8e72
SC
885//-----------------------------------------------------------------------------
886
0db8a70e
RD
887wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix )
888 : wxGraphicsMatrixData(renderer)
00bd8e72
SC
889{
890 if ( matrix )
891 m_matrix = *matrix;
892}
893
0db8a70e 894wxCairoMatrixData::~wxCairoMatrixData()
00bd8e72
SC
895{
896 // nothing to do
897}
898
0db8a70e 899wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const
00bd8e72 900{
0db8a70e 901 return new wxCairoMatrixData(GetRenderer(),&m_matrix);
00bd8e72
SC
902}
903
904// concatenates the matrix
0db8a70e 905void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t )
00bd8e72
SC
906{
907 cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix());
908}
909
00bd8e72 910// sets the matrix to the respective values
0db8a70e 911void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
00bd8e72
SC
912 wxDouble tx, wxDouble ty)
913{
914 cairo_matrix_init( &m_matrix, a, b, c, d, tx, ty);
915}
916
248802d0
RD
917// gets the component valuess of the matrix
918void wxCairoMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c,
919 wxDouble* d, wxDouble* tx, wxDouble* ty) const
920{
921 if (a) *a = m_matrix.xx;
922 if (b) *b = m_matrix.yx;
923 if (c) *c = m_matrix.xy;
924 if (d) *d = m_matrix.yy;
925 if (tx) *tx= m_matrix.x0;
926 if (ty) *ty= m_matrix.y0;
927}
928
00bd8e72 929// makes this the inverse matrix
0db8a70e 930void wxCairoMatrixData::Invert()
00bd8e72
SC
931{
932 cairo_matrix_invert( &m_matrix );
933}
934
935// returns true if the elements of the transformation matrix are equal ?
0db8a70e 936bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
00bd8e72
SC
937{
938 const cairo_matrix_t* tm = (cairo_matrix_t*) t->GetNativeMatrix();
939 return (
940 m_matrix.xx == tm->xx &&
941 m_matrix.yx == tm->yx &&
942 m_matrix.xy == tm->xy &&
943 m_matrix.yy == tm->yy &&
944 m_matrix.x0 == tm->x0 &&
945 m_matrix.y0 == tm->y0 ) ;
946}
947
948// return true if this is the identity matrix
0db8a70e 949bool wxCairoMatrixData::IsIdentity() const
00bd8e72
SC
950{
951 return ( m_matrix.xx == 1 && m_matrix.yy == 1 &&
952 m_matrix.yx == 0 && m_matrix.xy == 0 && m_matrix.x0 == 0 && m_matrix.y0 == 0);
953}
954
955//
956// transformation
957//
958
959// add the translation to this matrix
0db8a70e 960void wxCairoMatrixData::Translate( wxDouble dx , wxDouble dy )
00bd8e72
SC
961{
962 cairo_matrix_translate( &m_matrix, dx, dy) ;
963}
964
965// add the scale to this matrix
0db8a70e 966void wxCairoMatrixData::Scale( wxDouble xScale , wxDouble yScale )
00bd8e72
SC
967{
968 cairo_matrix_scale( &m_matrix, xScale, yScale) ;
969}
970
971// add the rotation to this matrix (radians)
0db8a70e 972void wxCairoMatrixData::Rotate( wxDouble angle )
00bd8e72
SC
973{
974 cairo_matrix_rotate( &m_matrix, angle) ;
975}
976
977//
978// apply the transforms
979//
980
981// applies that matrix to the point
0db8a70e 982void wxCairoMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
00bd8e72
SC
983{
984 double lx = *x, ly = *y ;
985 cairo_matrix_transform_point( &m_matrix, &lx, &ly);
986 *x = lx;
987 *y = ly;
988}
989
990// applies the matrix except for translations
0db8a70e 991void wxCairoMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
00bd8e72
SC
992{
993 double lx = *dx, ly = *dy ;
994 cairo_matrix_transform_distance( &m_matrix, &lx, &ly);
995 *dx = lx;
996 *dy = ly;
997}
998
999// returns the native representation
0db8a70e 1000void * wxCairoMatrixData::GetNativeMatrix() const
00bd8e72
SC
1001{
1002 return (void*) &m_matrix;
1003}
1004
1005//-----------------------------------------------------------------------------
1006// wxCairoContext implementation
1007//-----------------------------------------------------------------------------
1008
e7f9f819
SC
1009class wxCairoOffsetHelper
1010{
1011public :
1012 wxCairoOffsetHelper( cairo_t* ctx , bool offset )
1013 {
1014 m_ctx = ctx;
1015 m_offset = offset;
1016 if ( m_offset )
1017 cairo_translate( m_ctx, 0.5, 0.5 );
1018 }
1019 ~wxCairoOffsetHelper( )
1020 {
1021 if ( m_offset )
1022 cairo_translate( m_ctx, -0.5, -0.5 );
1023 }
1024public :
1025 cairo_t* m_ctx;
1026 bool m_offset;
1027} ;
1028
00bd8e72
SC
1029wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc )
1030: wxGraphicsContext(renderer)
1031{
1032#ifdef __WXGTK__
e7f9f819
SC
1033 Init( gdk_cairo_create( dc.m_window ) );
1034#endif
1035#ifdef __WXMAC__
1036 int width, height;
1037 dc.GetSize( &width, &height );
1038 CGContextRef cgcontext = (CGContextRef)dc.GetWindow()->MacGetCGContextRef();
1039 cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(cgcontext, width, height);
1040 Init( cairo_create( surface ) );
1041 cairo_surface_destroy( surface );
00bd8e72 1042#endif
00bd8e72
SC
1043}
1044
1045#ifdef __WXGTK__
1046wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable )
1047: wxGraphicsContext(renderer)
1048{
e7f9f819 1049 Init( gdk_cairo_create( drawable ) );
00bd8e72
SC
1050}
1051#endif
1052
1053wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context )
1054: wxGraphicsContext(renderer)
1055{
e7f9f819 1056 Init( context );
184fc6c8
SC
1057}
1058
00bd8e72
SC
1059wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window)
1060: wxGraphicsContext(renderer)
184fc6c8 1061{
00bd8e72
SC
1062#ifdef __WXGTK__
1063 // something along these lines (copied from dcclient)
1064
1065 GtkWidget *widget = window->m_wxwindow;
1066
1067 // Some controls don't have m_wxwindow - like wxStaticBox, but the user
1068 // code should still be able to create wxClientDCs for them, so we will
1069 // use the parent window here then.
1070 if ( !widget )
184fc6c8 1071 {
00bd8e72
SC
1072 window = window->GetParent();
1073 widget = window->m_wxwindow;
184fc6c8 1074 }
00bd8e72
SC
1075
1076 wxASSERT_MSG( widget, wxT("wxCairoContext needs a widget") );
1077
1078 GtkPizza *pizza = GTK_PIZZA( widget );
1079 GdkDrawable* drawable = pizza->bin_window;
e7f9f819 1080 Init( gdk_cairo_create( drawable ) ) ;
00bd8e72 1081#endif
00bd8e72
SC
1082}
1083
1084wxCairoContext::~wxCairoContext()
1085{
00bd8e72
SC
1086 if ( m_context )
1087 {
1088 PopState();
1089 PopState();
1090 cairo_destroy(m_context);
1091 }
1092}
1093
e7f9f819
SC
1094void wxCairoContext::Init(cairo_t *context)
1095{
1096 m_context = context ;
1097 PushState();
1098 PushState();
1099}
1100
00bd8e72 1101
d9485f89 1102void wxCairoContext::Clip( const wxRegion& region )
00bd8e72 1103{
d9485f89
RD
1104 // Create a path with all the rectangles in the region
1105 wxGraphicsPath path = GetRenderer()->CreatePath();
1106 wxRegionIterator ri(region);
1107 while (ri)
1108 {
1109 path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH());
1110 ri++;
1111 }
1112
1113 // Put it in the context
1114 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
1115 cairo_append_path(m_context, cp);
1116
1117 // clip to that path
1118 cairo_clip(m_context);
1119 path.UnGetNativePath(cp);
00bd8e72
SC
1120}
1121
1122void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1123{
d9485f89
RD
1124 // Create a path with this rectangle
1125 wxGraphicsPath path = GetRenderer()->CreatePath();
1126 path.AddRectangle(x,y,w,h);
1127
1128 // Put it in the context
1129 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
1130 cairo_append_path(m_context, cp);
1131
1132 // clip to that path
e7f9f819 1133// cairo_clip(m_context);
d9485f89 1134 path.UnGetNativePath(cp);
00bd8e72
SC
1135}
1136
1137void wxCairoContext::ResetClip()
1138{
d9485f89 1139 cairo_reset_clip(m_context);
00bd8e72
SC
1140}
1141
1142
0db8a70e 1143void wxCairoContext::StrokePath( const wxGraphicsPath& path )
00bd8e72 1144{
87752530 1145 if ( !m_pen.IsNull() )
00bd8e72 1146 {
e7f9f819 1147 wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
0db8a70e 1148 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
00bd8e72 1149 cairo_append_path(m_context,cp);
87752530 1150 ((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
00bd8e72 1151 cairo_stroke(m_context);
0db8a70e 1152 path.UnGetNativePath(cp);
00bd8e72
SC
1153 }
1154}
1155
0db8a70e 1156void wxCairoContext::FillPath( const wxGraphicsPath& path , int fillStyle )
00bd8e72 1157{
87752530 1158 if ( !m_brush.IsNull() )
00bd8e72 1159 {
e7f9f819 1160 wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
0db8a70e 1161 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
00bd8e72 1162 cairo_append_path(m_context,cp);
87752530 1163 ((wxCairoBrushData*)m_brush.GetRefData())->Apply(this);
00bd8e72
SC
1164 cairo_set_fill_rule(m_context,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
1165 cairo_fill(m_context);
0db8a70e 1166 path.UnGetNativePath(cp);
00bd8e72
SC
1167 }
1168}
1169
1170void wxCairoContext::Rotate( wxDouble angle )
1171{
1172 cairo_rotate(m_context,angle);
1173}
1174
1175void wxCairoContext::Translate( wxDouble dx , wxDouble dy )
1176{
1177 cairo_translate(m_context,dx,dy);
1178}
1179
1180void wxCairoContext::Scale( wxDouble xScale , wxDouble yScale )
1181{
1182 cairo_scale(m_context,xScale,yScale);
1183}
1184
1185// concatenates this transform with the current transform of this context
0db8a70e 1186void wxCairoContext::ConcatTransform( const wxGraphicsMatrix& matrix )
00bd8e72 1187{
0db8a70e 1188 cairo_transform(m_context,(const cairo_matrix_t *) matrix.GetNativeMatrix());
00bd8e72
SC
1189}
1190
1191// sets the transform of this context
0db8a70e 1192void wxCairoContext::SetTransform( const wxGraphicsMatrix& matrix )
00bd8e72 1193{
0db8a70e 1194 cairo_set_matrix(m_context,(const cairo_matrix_t*) matrix.GetNativeMatrix());
00bd8e72
SC
1195}
1196
1197// gets the matrix of this context
0db8a70e 1198wxGraphicsMatrix wxCairoContext::GetTransform() const
00bd8e72 1199{
0db8a70e
RD
1200 wxGraphicsMatrix matrix = CreateMatrix();
1201 cairo_get_matrix(m_context,(cairo_matrix_t*) matrix.GetNativeMatrix());
1202 return matrix;
00bd8e72
SC
1203}
1204
1205
1206
1207void wxCairoContext::PushState()
1208{
1209 cairo_save(m_context);
1210}
1211
1212void wxCairoContext::PopState()
1213{
1214 cairo_restore(m_context);
1215}
184fc6c8
SC
1216
1217void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1218{
d9485f89
RD
1219 wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
1220
1221 cairo_surface_t* surface;
1222 int bw = bmp.GetWidth();
1223 int bh = bmp.GetHeight();
1224 wxBitmap bmpSource = bmp; // we need a non-const instance
1225 unsigned char* buffer = new unsigned char[bw*bh*4];
1226 wxUint32* data = (wxUint32*)buffer;
1227
1228 // Create a surface object and copy the bitmap pixel data to it. if the
1229 // image has alpha (or a mask represented as alpha) then we'll use a
1230 // different format and iterator than if it doesn't...
1231 if (bmpSource.HasAlpha() || bmpSource.GetMask())
1232 {
1233 surface = cairo_image_surface_create_for_data(
1234 buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4);
1235 wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
1236 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1237
1238 wxAlphaPixelData::Iterator p(pixData);
1239 for (int y=0; y<bh; y++)
1240 {
1241 wxAlphaPixelData::Iterator rowStart = p;
1242 for (int x=0; x<bw; x++)
1243 {
1244 // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
1245 // with alpha in the upper 8 bits, then red, then green, then
1246 // blue. The 32-bit quantities are stored native-endian.
1247 // Pre-multiplied alpha is used.
1248 unsigned char alpha = p.Alpha();
1249 if (alpha == 0)
1250 *data = 0;
1251 else
1252 *data = ( alpha << 24
1253 | (p.Red() * alpha/255) << 16
1254 | (p.Green() * alpha/255) << 8
1255 | (p.Blue() * alpha/255) );
1256 ++data;
1257 ++p;
1258 }
1259 p = rowStart;
1260 p.OffsetY(pixData, 1);
1261 }
1262 }
1263 else // no alpha
1264 {
1265 surface = cairo_image_surface_create_for_data(
1266 buffer, CAIRO_FORMAT_RGB24, bw, bh, bw*4);
1267 wxNativePixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
1268 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1269
1270 wxNativePixelData::Iterator p(pixData);
1271 for (int y=0; y<bh; y++)
1272 {
1273 wxNativePixelData::Iterator rowStart = p;
1274 for (int x=0; x<bw; x++)
1275 {
1276 // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
1277 // the upper 8 bits unused. Red, Green, and Blue are stored in
1278 // the remaining 24 bits in that order. The 32-bit quantities
1279 // are stored native-endian.
1280 *data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
1281 ++data;
1282 ++p;
1283 }
1284 p = rowStart;
1285 p.OffsetY(pixData, 1);
1286 }
1287 }
1288
1289
1290 PushState();
1291
1292 // In case we're scaling the image by using a width and height different
1293 // than the bitmap's size create a pattern transformation on the surface and
1294 // draw the transformed pattern.
1295 cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
1296 wxDouble scaleX = w / bw;
1297 wxDouble scaleY = h / bh;
1298 cairo_scale(m_context, scaleX, scaleY);
1299
1300 // prepare to draw the image
1301 cairo_translate(m_context, x, y);
1302 cairo_set_source(m_context, pattern);
1303 // use the original size here since the context is scaled already...
1304 cairo_rectangle(m_context, 0, 0, bw, bh);
1305 // fill the rectangle using the pattern
1306 cairo_fill(m_context);
1307
1308 // clean up
1309 cairo_pattern_destroy(pattern);
1310 cairo_surface_destroy(surface);
1311 delete [] buffer;
1312 PopState();
184fc6c8
SC
1313}
1314
1315void wxCairoContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1316{
d9485f89
RD
1317 // An icon is a bitmap on wxGTK, so do this the easy way. When we want to
1318 // start using the Cairo backend on other platforms then we may need to
1319 // fiddle with this...
1320 DrawBitmap(icon, x, y, w, h);
184fc6c8
SC
1321}
1322
1323
1324void wxCairoContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
1325{
d9485f89
RD
1326 if ( m_font.IsNull() || str.empty())
1327 return;
1328
e7f9f819
SC
1329#ifdef __WXGTK__
1330 const wxCharBuffer data = wxGTK_CONV( str );
1331 if ( !data )
1332 return;
1333 size_t datalen = strlen(data);
1334
1335 PangoLayout *layout = pango_cairo_create_layout (m_context);
1336 pango_layout_set_font_description( m_layout, m_wxFont->GetNativeFontInfo()->description);
1337 pango_layout_set_text (layout, data, datalen);
1338 cairo_move_to(m_context, x, y);
1339 pango_cairo_show_layout (m_context, layout);
1340
1341 g_object_unref (layout);
1342#else
87752530 1343 ((wxCairoFontData*)m_font.GetRefData())->Apply(this);
d9485f89
RD
1344 // Cairo's x,y for drawing text is at the baseline, so we need to adjust
1345 // the position we move to by the ascent.
1346 cairo_font_extents_t fe;
1347 cairo_font_extents(m_context, &fe);
1348 cairo_move_to(m_context, x, y+fe.ascent);
1349
1350 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
184fc6c8 1351 cairo_show_text(m_context,buf);
e7f9f819 1352#endif
184fc6c8
SC
1353}
1354
1355void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1356 wxDouble *descent, wxDouble *externalLeading ) const
1357{
e7f9f819
SC
1358 if ( width )
1359 *width = 0;
1360 if ( height )
1361 *height = 0;
1362 if ( descent )
1363 *descent = 0;
1364 if ( externalLeading )
1365 *externalLeading = 0;
1366
d9485f89
RD
1367 if ( m_font.IsNull() || str.empty())
1368 return;
1369
e7f9f819
SC
1370#ifdef __WXGTK__
1371 int w, h;
1372
1373 PangoLayout *layout = pango_cairo_create_layout (m_context);
1374 pango_layout_set_font_description( layout, m_wxFont->GetNativeFontInfo()->description);
1375 const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(str, m_wxFont);
1376 if ( !dataUTF8 )
1377 {
1378 return;
1379 }
1380 pango_layout_set_text( layout, dataUTF8, strlen(dataUTF8) );
1381 pango_layout_get_pixel_size (layout, &w, &h);
1382 if ( width )
1383 *width = w;
1384 if ( height )
1385 *height = h;
1386 if (descent)
1387 {
1388 PangoLayoutIter *iter = pango_layout_get_iter(layout);
1389 int baseline = pango_layout_iter_get_baseline(iter);
1390 pango_layout_iter_free(iter);
1391 *descent = h - PANGO_PIXELS(baseline);
1392 }
1393 g_object_unref (layout);
1394#else
d9485f89
RD
1395 ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this);
1396
1397 if (width)
1398 {
1399 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
1400 cairo_text_extents_t te;
1401 cairo_text_extents(m_context, buf, &te);
1402 *width = te.width;
1403 }
1404
1405 if (height || descent || externalLeading)
1406 {
1407 cairo_font_extents_t fe;
1408 cairo_font_extents(m_context, &fe);
1409
1410 if (height)
1411 *height = fe.height;
1412 if ( descent )
1413 *descent = fe.descent;
1414 if ( externalLeading )
1415 *externalLeading = wxMax(0, fe.height - (fe.ascent + fe.descent));
1416 }
e7f9f819 1417#endif
184fc6c8
SC
1418}
1419
1420void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
1421{
1422 widths.Empty();
1423 widths.Add(0, text.length());
1424
1425 if (text.empty())
1426 return;
00bd8e72
SC
1427
1428 // TODO
184fc6c8
SC
1429}
1430
00bd8e72 1431void * wxCairoContext::GetNativeContext()
184fc6c8 1432{
00bd8e72
SC
1433 return m_context;
1434}
184fc6c8 1435
00bd8e72
SC
1436//-----------------------------------------------------------------------------
1437// wxCairoRenderer declaration
1438//-----------------------------------------------------------------------------
1439
1440class WXDLLIMPEXP_CORE wxCairoRenderer : public wxGraphicsRenderer
1441{
1442public :
1443 wxCairoRenderer() {}
1444
1445 virtual ~wxCairoRenderer() {}
1446
1447 // Context
1448
1449 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1450
773ccc31
SC
1451#ifdef __WXMSW__
1452 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
1453#endif
1454
00bd8e72
SC
1455 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1456
1457 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1458
1459 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1460
091ef146
SC
1461 virtual wxGraphicsContext * CreateMeasuringContext();
1462
00bd8e72
SC
1463 // Path
1464
0db8a70e 1465 virtual wxGraphicsPath CreatePath();
00bd8e72
SC
1466
1467 // Matrix
1468
0db8a70e 1469 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
00bd8e72
SC
1470 wxDouble tx=0.0, wxDouble ty=0.0);
1471
1472
87752530 1473 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
00bd8e72 1474
87752530 1475 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
00bd8e72
SC
1476
1477 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
87752530 1478 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
00bd8e72
SC
1479 const wxColour&c1, const wxColour&c2) ;
1480
1481 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1482 // with radius r and color cColor
87752530 1483 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
00bd8e72
SC
1484 const wxColour &oColor, const wxColour &cColor) ;
1485
1486 // sets the font
87752530 1487 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
00bd8e72
SC
1488
1489private :
1490 DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer)
1491} ;
1492
1493//-----------------------------------------------------------------------------
1494// wxCairoRenderer implementation
1495//-----------------------------------------------------------------------------
1496
1497IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer,wxGraphicsRenderer)
1498
1499static wxCairoRenderer gs_cairoGraphicsRenderer;
1500
1501#ifdef __WXGTK__
1502wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1503{
1504 return &gs_cairoGraphicsRenderer;
184fc6c8 1505}
00bd8e72 1506#endif
184fc6c8 1507
00bd8e72 1508wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc)
539e2795 1509{
00bd8e72
SC
1510 return new wxCairoContext(this,dc);
1511}
1512
773ccc31
SC
1513#ifdef __WXMSW__
1514wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc)
1515{
1516 return NULL;
1517}
1518#endif
1519
00bd8e72
SC
1520wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context )
1521{
1522 return new wxCairoContext(this,(cairo_t*)context);
1523}
1524
1525
1526wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window )
1527{
1528#ifdef __WXGTK__
ed1b38a8 1529 return new wxCairoContext(this,(GdkDrawable*)window);
00bd8e72
SC
1530#else
1531 return NULL;
1532#endif
1533}
1534
091ef146
SC
1535wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext()
1536{
1537 return NULL;
1538 // TODO
1539}
1540
00bd8e72
SC
1541wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window )
1542{
1543 return new wxCairoContext(this, window );
1544}
1545
1546// Path
1547
0db8a70e 1548wxGraphicsPath wxCairoRenderer::CreatePath()
00bd8e72 1549{
0db8a70e
RD
1550 wxGraphicsPath path;
1551 path.SetRefData( new wxCairoPathData(this) );
1552 return path;
539e2795
SC
1553}
1554
00bd8e72
SC
1555
1556// Matrix
1557
0db8a70e
RD
1558wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1559 wxDouble tx, wxDouble ty)
00bd8e72 1560
184fc6c8 1561{
0db8a70e
RD
1562 wxGraphicsMatrix m;
1563 wxCairoMatrixData* data = new wxCairoMatrixData( this );
1564 data->Set( a,b,c,d,tx,ty ) ;
1565 m.SetRefData(data);
00bd8e72 1566 return m;
7ba86d93
RD
1567}
1568
87752530 1569wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen)
539e2795 1570{
00bd8e72 1571 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
87752530 1572 return wxNullGraphicsPen;
00bd8e72 1573 else
87752530
SC
1574 {
1575 wxGraphicsPen p;
1576 p.SetRefData(new wxCairoPenData( this, pen ));
1577 return p;
1578 }
539e2795
SC
1579}
1580
87752530 1581wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush )
539e2795 1582{
00bd8e72 1583 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
87752530 1584 return wxNullGraphicsBrush;
00bd8e72 1585 else
87752530
SC
1586 {
1587 wxGraphicsBrush p;
1588 p.SetRefData(new wxCairoBrushData( this, brush ));
1589 return p;
1590 }
00bd8e72
SC
1591}
1592
1593// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
87752530 1594wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
00bd8e72
SC
1595 const wxColour&c1, const wxColour&c2)
1596{
87752530
SC
1597 wxGraphicsBrush p;
1598 wxCairoBrushData* d = new wxCairoBrushData( this );
1599 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1600 p.SetRefData(d);
1601 return p;
00bd8e72
SC
1602}
1603
1604// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1605// with radius r and color cColor
87752530 1606wxGraphicsBrush wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
00bd8e72
SC
1607 const wxColour &oColor, const wxColour &cColor)
1608{
87752530
SC
1609 wxGraphicsBrush p;
1610 wxCairoBrushData* d = new wxCairoBrushData( this );
1611 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1612 p.SetRefData(d);
1613 return p;
00bd8e72
SC
1614}
1615
1616// sets the font
87752530 1617wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col )
00bd8e72
SC
1618{
1619 if ( font.Ok() )
87752530
SC
1620 {
1621 wxGraphicsFont p;
1622 p.SetRefData(new wxCairoFontData( this , font, col ));
1623 return p;
1624 }
00bd8e72 1625 else
87752530 1626 return wxNullGraphicsFont;
539e2795
SC
1627}
1628
7ba86d93 1629#endif // wxUSE_GRAPHICS_CONTEXT