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