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