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