]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/graphicc.cpp
NUL terminate the string in UngetWriteBuf(len) (bug 1594189)
[wxWidgets.git] / src / generic / graphicc.cpp
... / ...
CommitLineData
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
45using namespace std;
46
47//-----------------------------------------------------------------------------
48// constants
49//-----------------------------------------------------------------------------
50
51const double RAD2DEG = 180.0 / M_PI;
52
53//-----------------------------------------------------------------------------
54// Local functions
55//-----------------------------------------------------------------------------
56
57static inline double dmin(double a, double b)
58{
59 return a < b ? a : b;
60}
61static inline double dmax(double a, double b)
62{
63 return a > b ? a : b;
64}
65
66static inline double DegToRad(double deg)
67{
68 return (deg * M_PI) / 180.0;
69}
70static 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
106class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData
107{
108public :
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
170private :
171 cairo_t* m_pathContext;
172};
173
174class WXDLLIMPEXP_CORE wxCairoMatrixData : public wxGraphicsMatrixData
175{
176public :
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;
223private:
224 cairo_matrix_t m_matrix ;
225} ;
226
227class WXDLLIMPEXP_CORE wxCairoPenData : public wxGraphicsObjectRefData
228{
229public:
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
238private :
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
256class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData
257{
258public:
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
269protected:
270 virtual void Init();
271
272private :
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
281class wxCairoFontData : public wxGraphicsObjectRefData
282{
283public:
284 wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
285 ~wxCairoFontData();
286
287 virtual void Apply( wxGraphicsContext* context );
288private :
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
299class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext
300{
301 DECLARE_NO_COPY_CLASS(wxCairoContext)
302
303public:
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
349private:
350 cairo_t* m_context;
351};
352
353//-----------------------------------------------------------------------------
354// wxCairoPenData implementation
355//-----------------------------------------------------------------------------
356
357wxCairoPenData::~wxCairoPenData()
358{
359 delete[] m_userLengths;
360}
361
362void wxCairoPenData::Init()
363{
364 m_lengths = NULL;
365 m_userLengths = NULL;
366 m_width = 0;
367 m_count = 0;
368}
369
370wxCairoPenData::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
539void 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
553wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer )
554 : wxGraphicsObjectRefData( renderer )
555{
556 Init();
557}
558
559wxCairoBrushData::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
615wxCairoBrushData::~wxCairoBrushData ()
616{
617 if (m_brushPattern)
618 cairo_pattern_destroy(m_brushPattern);
619}
620
621void 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
634void 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
645void 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
656void wxCairoBrushData::Init()
657{
658 m_brushPattern = NULL;
659}
660
661//-----------------------------------------------------------------------------
662// wxCairoFontData implementation
663//-----------------------------------------------------------------------------
664
665wxCairoFontData::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
679wxCairoFontData::~wxCairoFontData()
680{
681}
682
683void 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
697wxCairoPathData::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
712wxCairoPathData::~wxCairoPathData()
713{
714 cairo_destroy(m_pathContext);
715}
716
717wxGraphicsObjectRefData *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
730void* wxCairoPathData::GetNativePath() const
731{
732 return cairo_copy_path(m_pathContext) ;
733}
734
735void wxCairoPathData::UnGetNativePath(void *p) const
736{
737 cairo_path_destroy((cairo_path_t*)p);
738}
739
740//
741// The Primitives
742//
743
744void wxCairoPathData::MoveToPoint( wxDouble x , wxDouble y )
745{
746 cairo_move_to(m_pathContext,x,y);
747}
748
749void wxCairoPathData::AddLineToPoint( wxDouble x , wxDouble y )
750{
751 cairo_line_to(m_pathContext,x,y);
752}
753
754void wxCairoPathData::AddPath( const wxGraphicsPathData* path )
755{
756 // TODO
757}
758
759void wxCairoPathData::CloseSubpath()
760{
761 cairo_close_path(m_pathContext);
762}
763
764void 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
770void 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
780void 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
792void 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)
802void 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
830bool 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
839wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix )
840 : wxGraphicsMatrixData(renderer)
841{
842 if ( matrix )
843 m_matrix = *matrix;
844}
845
846wxCairoMatrixData::~wxCairoMatrixData()
847{
848 // nothing to do
849}
850
851wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const
852{
853 return new wxCairoMatrixData(GetRenderer(),&m_matrix);
854}
855
856// concatenates the matrix
857void 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
863void 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
870void wxCairoMatrixData::Invert()
871{
872 cairo_matrix_invert( &m_matrix );
873}
874
875// returns true if the elements of the transformation matrix are equal ?
876bool 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
889bool 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
900void wxCairoMatrixData::Translate( wxDouble dx , wxDouble dy )
901{
902 cairo_matrix_translate( &m_matrix, dx, dy) ;
903}
904
905// add the scale to this matrix
906void 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)
912void 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
922void 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
931void 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
940void * wxCairoMatrixData::GetNativeMatrix() const
941{
942 return (void*) &m_matrix;
943}
944
945//-----------------------------------------------------------------------------
946// wxCairoContext implementation
947//-----------------------------------------------------------------------------
948
949wxCairoContext::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__
960wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable )
961: wxGraphicsContext(renderer)
962{
963 m_context = gdk_cairo_create( drawable ) ;
964 PushState();
965 PushState();
966}
967#endif
968
969wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context )
970: wxGraphicsContext(renderer)
971{
972 m_context = context ;
973 PushState();
974 PushState();
975}
976
977wxCairoContext::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
1004wxCairoContext::~wxCairoContext()
1005{
1006 if ( m_context )
1007 {
1008 PopState();
1009 PopState();
1010 cairo_destroy(m_context);
1011 }
1012}
1013
1014
1015void wxCairoContext::Clip( const wxRegion & WXUNUSED(region) )
1016{
1017// TODO
1018}
1019
1020void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1021{
1022// TODO
1023}
1024
1025void wxCairoContext::ResetClip()
1026{
1027// TODO
1028}
1029
1030
1031void 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
1043void 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
1056void wxCairoContext::Rotate( wxDouble angle )
1057{
1058 cairo_rotate(m_context,angle);
1059}
1060
1061void wxCairoContext::Translate( wxDouble dx , wxDouble dy )
1062{
1063 cairo_translate(m_context,dx,dy);
1064}
1065
1066void 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
1072void 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
1078void 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
1084wxGraphicsMatrix 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
1093void wxCairoContext::PushState()
1094{
1095 cairo_save(m_context);
1096}
1097
1098void wxCairoContext::PopState()
1099{
1100 cairo_restore(m_context);
1101}
1102
1103void 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
1112void 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
1122void 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
1132void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1133 wxDouble *descent, wxDouble *externalLeading ) const
1134{
1135 // TODO
1136}
1137
1138void 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
1149void * wxCairoContext::GetNativeContext()
1150{
1151 return m_context;
1152}
1153
1154//-----------------------------------------------------------------------------
1155// wxCairoRenderer declaration
1156//-----------------------------------------------------------------------------
1157
1158class WXDLLIMPEXP_CORE wxCairoRenderer : public wxGraphicsRenderer
1159{
1160public :
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
1207private :
1208 DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer)
1209} ;
1210
1211//-----------------------------------------------------------------------------
1212// wxCairoRenderer implementation
1213//-----------------------------------------------------------------------------
1214
1215IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer,wxGraphicsRenderer)
1216
1217static wxCairoRenderer gs_cairoGraphicsRenderer;
1218
1219#ifdef __WXGTK__
1220wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1221{
1222 return &gs_cairoGraphicsRenderer;
1223}
1224#endif
1225
1226wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc)
1227{
1228 return new wxCairoContext(this,dc);
1229}
1230
1231#ifdef __WXMSW__
1232wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc)
1233{
1234 return NULL;
1235}
1236#endif
1237
1238wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context )
1239{
1240 return new wxCairoContext(this,(cairo_t*)context);
1241}
1242
1243
1244wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window )
1245{
1246#ifdef __WXGTK__
1247 return new wxCairoContext(this,(GdkDrawable*)window);
1248#else
1249 return NULL;
1250#endif
1251}
1252
1253wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext()
1254{
1255 return NULL;
1256 // TODO
1257}
1258
1259wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window )
1260{
1261 return new wxCairoContext(this, window );
1262}
1263
1264// Path
1265
1266wxGraphicsPath wxCairoRenderer::CreatePath()
1267{
1268 wxGraphicsPath path;
1269 path.SetRefData( new wxCairoPathData(this) );
1270 return path;
1271}
1272
1273
1274// Matrix
1275
1276wxGraphicsMatrix 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
1287wxGraphicsPen 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
1299wxGraphicsBrush 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
1312wxGraphicsBrush 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
1324wxGraphicsBrush 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
1335wxGraphicsFont 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