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