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