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