cairo implementation
[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: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/dc.h"
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/image.h"
25 #include "wx/window.h"
26 #include "wx/dc.h"
27 #include "wx/utils.h"
28 #include "wx/dialog.h"
29 #include "wx/app.h"
30 #include "wx/bitmap.h"
31 #include "wx/dcmemory.h"
32 #include "wx/log.h"
33 #include "wx/icon.h"
34 #include "wx/dcprint.h"
35 #include "wx/module.h"
36 #endif
37
38 #include "wx/graphics.h"
39
40 #include <vector>
41
42 using namespace std;
43
44 //-----------------------------------------------------------------------------
45 // constants
46 //-----------------------------------------------------------------------------
47
48 const double RAD2DEG = 180.0 / M_PI;
49
50 //-----------------------------------------------------------------------------
51 // Local functions
52 //-----------------------------------------------------------------------------
53
54 static inline double dmin(double a, double b)
55 {
56 return a < b ? a : b;
57 }
58 static inline double dmax(double a, double b)
59 {
60 return a > b ? a : b;
61 }
62
63 static inline double DegToRad(double deg)
64 {
65 return (deg * M_PI) / 180.0;
66 }
67 static inline double RadToDeg(double deg)
68 {
69 return (deg * 180.0) / M_PI;
70 }
71
72 //-----------------------------------------------------------------------------
73 // device context implementation
74 //
75 // more and more of the dc functionality should be implemented by calling
76 // the appropricate wxCairoContext, but we will have to do that step by step
77 // also coordinate conversions should be moved to native matrix ops
78 //-----------------------------------------------------------------------------
79
80 // we always stock two context states, one at entry, to be able to preserve the
81 // state we were called with, the other one after changing to HI Graphics orientation
82 // (this one is used for getting back clippings etc)
83
84 //-----------------------------------------------------------------------------
85 // wxGraphicsPath implementation
86 //-----------------------------------------------------------------------------
87
88 // TODO remove this dependency (gdiplus needs the macros)
89
90 #ifndef max
91 #define max(a,b) (((a) > (b)) ? (a) : (b))
92 #endif
93
94 #ifndef min
95 #define min(a,b) (((a) < (b)) ? (a) : (b))
96 #endif
97
98 #include <cairo.h>
99 #include <gtk/gtk.h>
100
101 class WXDLLEXPORT wxCairoPath : public wxGraphicsPath
102 {
103 DECLARE_NO_COPY_CLASS(wxCairoPath)
104 public :
105 wxCairoPath();
106 ~wxCairoPath();
107
108
109 //
110 // These are the path primitives from which everything else can be constructed
111 //
112
113 // begins a new subpath at (x,y)
114 virtual void MoveToPoint( wxDouble x, wxDouble y );
115
116 // adds a straight line from the current point to (x,y)
117 virtual void AddLineToPoint( wxDouble x, wxDouble y );
118
119 // adds a cubic Bezier curve from the current point, using two control points and an end point
120 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
121
122
123 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
124 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
125
126 // gets the last point of the current path, (0,0) if not yet set
127 virtual void GetCurrentPoint( wxDouble& x, wxDouble&y) ;
128
129 // closes the current sub-path
130 virtual void CloseSubpath();
131
132 //
133 // These are convenience functions which - if not available natively will be assembled
134 // using the primitives from above
135 //
136
137 /*
138
139 // appends a rectangle as a new closed subpath
140 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
141 // appends an ellipsis as a new closed subpath fitting the passed rectangle
142 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
143
144 // 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)
145 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
146 */
147
148 cairo_path_t* GetPath() const;
149 private :
150 cairo_t* m_pathContext;
151 };
152
153 wxCairoPath::wxCairoPath()
154 {
155 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1);
156 m_pathContext = cairo_create(surface);
157 cairo_surface_destroy (surface);
158 }
159
160 wxCairoPath::~wxCairoPath()
161 {
162 cairo_destroy(m_pathContext);
163 }
164
165 cairo_path_t* wxCairoPath::GetPath() const
166 {
167 return cairo_copy_path(m_pathContext) ;
168 }
169
170 //
171 // The Primitives
172 //
173
174 void wxCairoPath::MoveToPoint( wxDouble x , wxDouble y )
175 {
176 cairo_move_to(m_pathContext,x,y);
177 }
178
179 void wxCairoPath::AddLineToPoint( wxDouble x , wxDouble y )
180 {
181 cairo_line_to(m_pathContext,x,y);
182 }
183
184 void wxCairoPath::CloseSubpath()
185 {
186 cairo_close_path(m_pathContext);
187 }
188
189 void wxCairoPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
190 {
191 cairo_curve_to(m_pathContext,cx1,cy1,cx2,cy2,x,y);
192 }
193
194 // gets the last point of the current path, (0,0) if not yet set
195 void wxCairoPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
196 {
197 double dx,dy;
198 cairo_get_current_point(m_pathContext,&dx,&dy);
199 x = dx;
200 y = dy;
201 }
202
203 void wxCairoPath::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
204 {
205 // as clockwise means positive in our system (y pointing downwards)
206 // TODO make this interpretation dependent of the
207 // real device trans
208 if ( clockwise||(endAngle-startAngle)>=2*M_PI)
209 cairo_arc(m_pathContext,x,y,r,startAngle,endAngle);
210 else
211 cairo_arc_negative(m_pathContext,x,y,r,startAngle,endAngle);
212 }
213
214 /*
215 void wxCairoPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
216 {
217 m_path->AddRectangle(RectF(x,y,w,h));
218 }
219 */
220 //
221 //
222 //
223 /*
224 // closes the current subpath
225 void wxCairoPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
226 {
227 // CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);
228 }
229
230 */
231
232 class WXDLLEXPORT wxCairoContext : public wxGraphicsContext
233 {
234 DECLARE_NO_COPY_CLASS(wxCairoContext)
235
236 public:
237 wxCairoContext( const wxWindowDC& dc );
238 wxCairoContext();
239 virtual ~wxCairoContext();
240
241 virtual void Clip( const wxRegion &region );
242 virtual void StrokePath( const wxGraphicsPath *p );
243 virtual void FillPath( const wxGraphicsPath *p , int fillStyle = wxWINDING_RULE );
244
245 virtual wxGraphicsPath* CreatePath();
246 virtual void SetPen( const wxPen &pen );
247 virtual void SetBrush( const wxBrush &brush );
248 virtual void SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2) ;
249 virtual void SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
250 const wxColour &oColor, const wxColour &cColor);
251
252 virtual void Translate( wxDouble dx , wxDouble dy );
253 virtual void Scale( wxDouble xScale , wxDouble yScale );
254 virtual void Rotate( wxDouble angle );
255
256 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
257 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
258 virtual void PushState();
259 virtual void PopState();
260
261 virtual void SetFont( const wxFont &font );
262 virtual void SetTextColor( const wxColour &col );
263 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y);
264 virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
265 wxDouble *descent, wxDouble *externalLeading ) const;
266 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
267
268 private:
269 cairo_t* m_context;
270 bool m_penTransparent;
271 bool m_brushTransparent;
272
273 wxPen m_pen;
274 wxBrush m_brush;
275 cairo_pattern_t* m_brushPattern;
276 wxColour m_textColour;
277 };
278
279
280
281
282 //-----------------------------------------------------------------------------
283 // wxCairoContext implementation
284 //-----------------------------------------------------------------------------
285
286 wxCairoContext::wxCairoContext( const wxWindowDC& dc )
287 {
288 m_context = gdk_cairo_create( dc.m_window ) ;
289 PushState();
290 PushState();
291 m_penTransparent = true;
292 m_brushTransparent = true;
293 m_brushPattern = NULL ;
294 }
295
296 wxCairoContext::~wxCairoContext()
297 {
298 if ( m_context )
299 {
300 PopState();
301 PopState();
302 cairo_destroy(m_context);
303 if ( m_brushPattern )
304 cairo_pattern_destroy(m_brushPattern);
305 }
306 }
307
308
309 void wxCairoContext::Clip( const wxRegion &region )
310 {
311 // ClipCGContextToRegion ( m_context, &bounds , (RgnHandle) dc->m_macCurrentClipRgn );
312 }
313
314 void wxCairoContext::StrokePath( const wxGraphicsPath *p )
315 {
316 if ( m_penTransparent )
317 return;
318
319 const wxCairoPath* path = dynamic_cast< const wxCairoPath*>( p );
320 cairo_path_t* cp = path->GetPath() ;
321 cairo_append_path(m_context,cp);
322
323 // setup pen
324
325 // TODO: * m_dc->m_scaleX
326 double penWidth = m_pen.GetWidth();
327 if (penWidth <= 0.0)
328 penWidth = 0.1;
329
330 cairo_set_line_width(m_context,penWidth);
331 cairo_set_source_rgba(m_context,m_pen.GetColour().Red()/255.0,
332 m_pen.GetColour().Green()/255.0, m_pen.GetColour().Blue()/255.0,m_pen.GetColour().Alpha()/255.0);
333
334 cairo_line_cap_t cap;
335 switch ( m_pen.GetCap() )
336 {
337 case wxCAP_ROUND :
338 cap = CAIRO_LINE_CAP_ROUND;
339 break;
340
341 case wxCAP_PROJECTING :
342 cap = CAIRO_LINE_CAP_SQUARE;
343 break;
344
345 case wxCAP_BUTT :
346 cap = CAIRO_LINE_CAP_BUTT;
347 break;
348
349 default :
350 cap = CAIRO_LINE_CAP_BUTT;
351 break;
352 }
353 cairo_set_line_cap(m_context,cap);
354
355 cairo_line_join_t join;
356 switch ( m_pen.GetJoin() )
357 {
358 case wxJOIN_BEVEL :
359 join = CAIRO_LINE_JOIN_BEVEL;
360 break;
361
362 case wxJOIN_MITER :
363 join = CAIRO_LINE_JOIN_MITER;
364 break;
365
366 case wxJOIN_ROUND :
367 join = CAIRO_LINE_JOIN_ROUND;
368 break;
369
370 default :
371 join = CAIRO_LINE_JOIN_MITER;
372 break;
373 }
374 cairo_set_line_join(m_context,join);
375
376 int num_dashes = 0;
377 const double * dashes = NULL;
378 double offset = 0.0;
379
380 const double dashUnit = penWidth < 1.0 ? 1.0 : penWidth;
381
382 double *userLengths = NULL;
383 const double dotted[] =
384 {
385 dashUnit , dashUnit + 2.0
386 };
387 const double short_dashed[] =
388 {
389 9.0 , 6.0
390 };
391 const double dashed[] =
392 {
393 19.0 , 9.0
394 };
395 const double dotted_dashed[] =
396 {
397 9.0 , 6.0 , 3.0 , 3.0
398 };
399
400 switch ( m_pen.GetStyle() )
401 {
402 case wxSOLID :
403 break;
404
405 case wxDOT :
406 dashes = dotted ;
407 num_dashes = WXSIZEOF(dotted)
408 ;
409 break;
410
411 case wxLONG_DASH :
412 dashes = dotted ;
413 num_dashes = WXSIZEOF(dashed);
414 break;
415
416 case wxSHORT_DASH :
417 dashes = dotted ;
418 num_dashes = WXSIZEOF(short_dashed);
419 break;
420
421 case wxDOT_DASH :
422 dashes = dotted ;
423 num_dashes = WXSIZEOF(dotted_dashed);
424 break;
425
426 case wxUSER_DASH :
427 {
428 wxDash *wxdashes ;
429 num_dashes = m_pen.GetDashes( &wxdashes ) ;
430 if ((wxdashes != NULL) && (num_dashes > 0))
431 {
432 userLengths = new double[num_dashes] ;
433 for ( int i = 0 ; i < num_dashes ; ++i )
434 {
435 userLengths[i] = wxdashes[i] * dashUnit ;
436
437 if ( i % 2 == 1 && userLengths[i] < dashUnit + 2.0 )
438 userLengths[i] = dashUnit + 2.0 ;
439 else if ( i % 2 == 0 && userLengths[i] < dashUnit )
440 userLengths[i] = dashUnit ;
441 }
442 }
443 dashes = userLengths ;
444 }
445 break;
446 case wxSTIPPLE :
447 {
448 /*
449 wxBitmap* bmp = pen.GetStipple();
450 if ( bmp && bmp->Ok() )
451 {
452 wxDELETE( m_penImage );
453 wxDELETE( m_penBrush );
454 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
455 m_penBrush = new TextureBrush(m_penImage);
456 m_pen->SetBrush( m_penBrush );
457 }
458 */
459 }
460 break;
461 default :
462 if ( m_pen.GetStyle() >= wxFIRST_HATCH && m_pen.GetStyle() <= wxLAST_HATCH )
463 {
464 /*
465 wxDELETE( m_penBrush );
466 HatchStyle style = HatchStyleHorizontal;
467 switch( pen.GetStyle() )
468 {
469 case wxBDIAGONAL_HATCH :
470 style = HatchStyleBackwardDiagonal;
471 break ;
472 case wxCROSSDIAG_HATCH :
473 style = HatchStyleDiagonalCross;
474 break ;
475 case wxFDIAGONAL_HATCH :
476 style = HatchStyleForwardDiagonal;
477 break ;
478 case wxCROSS_HATCH :
479 style = HatchStyleCross;
480 break ;
481 case wxHORIZONTAL_HATCH :
482 style = HatchStyleHorizontal;
483 break ;
484 case wxVERTICAL_HATCH :
485 style = HatchStyleVertical;
486 break ;
487
488 }
489 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
490 pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent );
491 m_pen->SetBrush( m_penBrush )
492 */
493 }
494 break;
495 }
496
497 cairo_set_dash(m_context,(double*)dashes,num_dashes,offset);
498 if ( userLengths )
499 delete[] userLengths;
500 cairo_stroke(m_context);
501 cairo_path_destroy(cp);
502 }
503
504 void wxCairoContext::FillPath( const wxGraphicsPath *p , int fillStyle )
505 {
506 if ( !m_brushTransparent )
507 {
508 const wxCairoPath* path = dynamic_cast< const wxCairoPath*>( p );
509 cairo_path_t* cp = path->GetPath() ;
510 cairo_append_path(m_context,cp);
511
512 if ( m_brushPattern )
513 {
514 cairo_set_source(m_context,m_brushPattern);
515 }
516 else
517 {
518 cairo_set_source_rgba(m_context,m_brush.GetColour().Red()/255.0,
519 m_brush.GetColour().Green()/255.0,
520 m_brush.GetColour().Blue()/255.0,
521 m_brush.GetColour().Alpha()/255.0);
522 }
523
524 cairo_set_fill_rule(m_context,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
525 cairo_fill(m_context);
526 cairo_path_destroy(cp);
527 }
528 }
529
530 wxGraphicsPath* wxCairoContext::CreatePath()
531 {
532 return new wxCairoPath();
533 }
534
535 void wxCairoContext::Rotate( wxDouble angle )
536 {
537 cairo_rotate(m_context,angle);
538 }
539
540 void wxCairoContext::Translate( wxDouble dx , wxDouble dy )
541 {
542 cairo_translate(m_context,dx,dy);
543 }
544
545 void wxCairoContext::Scale( wxDouble xScale , wxDouble yScale )
546 {
547 cairo_scale(m_context,xScale,yScale);
548 /*
549 PointF penWidth( m_pen->GetWidth(), 0);
550 Matrix matrix ;
551 if ( !m_penTransparent )
552 {
553 m_context->GetTransform(&matrix);
554 matrix.TransformVectors(&penWidth);
555 }
556 m_context->ScaleTransform(xScale,yScale);
557 if ( !m_penTransparent )
558 {
559 m_context->GetTransform(&matrix);
560 matrix.Invert();
561 matrix.TransformVectors(&penWidth) ;
562 m_pen->SetWidth( sqrt( penWidth.X*penWidth.X + penWidth.Y*penWidth.Y));
563 }
564 */
565 }
566
567 void wxCairoContext::PushState()
568 {
569 cairo_save(m_context);
570 }
571
572 void wxCairoContext::PopState()
573 {
574 cairo_restore(m_context);
575 }
576
577 void wxCairoContext::SetTextColor( const wxColour &col )
578 {
579 m_textColour = col;
580 }
581
582 void wxCairoContext::SetPen( const wxPen &pen )
583 {
584 m_pen = pen ;
585 m_penTransparent = pen.GetStyle() == wxTRANSPARENT;
586 if ( m_penTransparent )
587 return;
588
589 /*
590
591 case wxSTIPPLE :
592 {
593 wxBitmap* bmp = pen.GetStipple();
594 if ( bmp && bmp->Ok() )
595 {
596 wxDELETE( m_penImage );
597 wxDELETE( m_penBrush );
598 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
599 m_penBrush = new TextureBrush(m_penImage);
600 m_pen->SetBrush( m_penBrush );
601 }
602
603 }
604 break;
605 default :
606 if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH )
607 {
608 wxDELETE( m_penBrush );
609 HatchStyle style = HatchStyleHorizontal;
610 switch( pen.GetStyle() )
611 {
612 case wxBDIAGONAL_HATCH :
613 style = HatchStyleBackwardDiagonal;
614 break ;
615 case wxCROSSDIAG_HATCH :
616 style = HatchStyleDiagonalCross;
617 break ;
618 case wxFDIAGONAL_HATCH :
619 style = HatchStyleForwardDiagonal;
620 break ;
621 case wxCROSS_HATCH :
622 style = HatchStyleCross;
623 break ;
624 case wxHORIZONTAL_HATCH :
625 style = HatchStyleHorizontal;
626 break ;
627 case wxVERTICAL_HATCH :
628 style = HatchStyleVertical;
629 break ;
630
631 }
632 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
633 pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent );
634 m_pen->SetBrush( m_penBrush );
635 }
636 break;
637 }
638 if ( dashStyle != DashStyleSolid )
639 m_pen->SetDashStyle(dashStyle);
640 */
641 }
642
643 void wxCairoContext::SetBrush( const wxBrush &brush )
644 {
645 m_brush = brush;
646 if (m_brushPattern)
647 {
648 cairo_pattern_destroy(m_brushPattern);
649 m_brushPattern = NULL;
650 }
651 m_brushTransparent = brush.GetStyle() == wxTRANSPARENT;
652
653 if ( m_brushTransparent )
654 return;
655 /*
656 wxDELETE(m_brush);
657
658 if ( brush.GetStyle() == wxSOLID)
659 {
660 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
661 brush.GetColour().Green() , brush.GetColour().Blue() ) );
662 }
663 else if ( brush.IsHatch() )
664 {
665 HatchStyle style = HatchStyleHorizontal;
666 switch( brush.GetStyle() )
667 {
668 case wxBDIAGONAL_HATCH :
669 style = HatchStyleBackwardDiagonal;
670 break ;
671 case wxCROSSDIAG_HATCH :
672 style = HatchStyleDiagonalCross;
673 break ;
674 case wxFDIAGONAL_HATCH :
675 style = HatchStyleForwardDiagonal;
676 break ;
677 case wxCROSS_HATCH :
678 style = HatchStyleCross;
679 break ;
680 case wxHORIZONTAL_HATCH :
681 style = HatchStyleHorizontal;
682 break ;
683 case wxVERTICAL_HATCH :
684 style = HatchStyleVertical;
685 break ;
686
687 }
688 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
689 brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent );
690 }
691 else
692 {
693 wxBitmap* bmp = brush.GetStipple();
694 if ( bmp && bmp->Ok() )
695 {
696 wxDELETE( m_brushImage );
697 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
698 m_brush = new TextureBrush(m_brushImage);
699 }
700 }
701 */
702 }
703
704 void wxCairoContext::SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
705 {
706 if ( m_brushPattern )
707 {
708 cairo_pattern_destroy(m_brushPattern);
709 m_brushPattern=NULL;
710 }
711
712 m_brushTransparent = false;
713 m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2);
714 cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,c1.Red()/255.0,
715 c1.Green()/255.0, c1.Blue()/255.0,c1.Alpha()/255.0);
716 cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,c2.Red()/255.0,
717 c2.Green()/255.0, c2.Blue()/255.0,c2.Alpha()/255.0);
718 wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern"));
719 }
720
721 void wxCairoContext::SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
722 const wxColour &oColor, const wxColour &cColor)
723 {
724 if ( m_brushPattern )
725 {
726 cairo_pattern_destroy(m_brushPattern);
727 m_brushPattern=NULL;
728 }
729
730 m_brushTransparent = false;
731 m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
732 cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,oColor.Red()/255.0,
733 oColor.Green()/255.0, oColor.Blue()/255.0,oColor.Alpha()/255.0);
734 cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,cColor.Red()/255.0,
735 cColor.Green()/255.0, cColor.Blue()/255.0,cColor.Alpha()/255.0);
736 wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern"));
737 }
738
739 void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
740 {
741 /*
742 Bitmap* image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
743 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
744 delete image ;
745 */
746 }
747
748 void wxCairoContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
749 {
750 /*
751 Bitmap* image = Bitmap::FromHICON((HICON)icon.GetHICON());
752 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
753 delete image ;
754 */
755 }
756
757
758 void wxCairoContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
759 {
760 if ( str.IsEmpty())
761 return ;
762 cairo_move_to(m_context,x,y);
763 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
764
765 cairo_set_source_rgba(m_context,m_textColour.Red()/255.0,
766 m_textColour.Green()/255.0, m_textColour.Blue()/255.0,m_textColour.Alpha()/255.0);
767 cairo_show_text(m_context,buf);
768
769 // TODO m_backgroundMode == wxSOLID
770 }
771
772 void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
773 wxDouble *descent, wxDouble *externalLeading ) const
774 {
775 /*
776 wxWCharBuffer s = str.wc_str( *wxConvUI );
777 FontFamily ffamily ;
778
779 m_font->GetFamily(&ffamily) ;
780
781 REAL factorY = m_context->GetDpiY() / 72.0 ;
782
783 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
784 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
785 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
786 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
787 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
788 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
789
790 if ( height )
791 *height = rHeight * factorY + 0.5 ;
792 if ( descent )
793 *descent = rDescent * factorY + 0.5 ;
794 if ( externalLeading )
795 *externalLeading = (rHeight - rAscent - rDescent) * factorY + 0.5 ;
796 // measuring empty strings is not guaranteed, so do it by hand
797 if ( str.IsEmpty())
798 {
799 if ( width )
800 *width = 0 ;
801 }
802 else
803 {
804 // MeasureString does return a rectangle that is way too large, so it is
805 // not usable here
806 RectF layoutRect(0,0, 100000.0f, 100000.0f);
807 StringFormat strFormat;
808 CharacterRange strRange(0,wcslen(s));
809 strFormat.SetMeasurableCharacterRanges(1,&strRange);
810 Region region ;
811 m_context->MeasureCharacterRanges(s, -1 , m_font,layoutRect, &strFormat,1,&region) ;
812 RectF bbox ;
813 region.GetBounds(&bbox,m_context);
814 if ( width )
815 *width = bbox.GetRight()-bbox.GetLeft()+0.5;
816 }
817 */
818 }
819
820 void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
821 {
822 widths.Empty();
823 widths.Add(0, text.length());
824
825 if (text.empty())
826 return;
827 /*
828 wxWCharBuffer ws = text.wc_str( *wxConvUI );
829 size_t len = wcslen( ws ) ;
830 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
831
832 RectF layoutRect(0,0, 100000.0f, 100000.0f);
833 StringFormat strFormat;
834
835 CharacterRange* ranges = new CharacterRange[len] ;
836 Region* regions = new Region[len];
837 for( int i = 0 ; i < len ; ++i)
838 {
839 ranges[i].First = i ;
840 ranges[i].Length = 1 ;
841 }
842 strFormat.SetMeasurableCharacterRanges(len,ranges);
843 m_context->MeasureCharacterRanges(ws, -1 , m_font,layoutRect, &strFormat,1,regions) ;
844
845 RectF bbox ;
846 for ( int i = 0 ; i < len ; ++i)
847 {
848 regions[i].GetBounds(&bbox,m_context);
849 widths[i] = bbox.GetRight()-bbox.GetLeft();
850 }
851 */
852 }
853
854 void wxCairoContext::SetFont( const wxFont &font )
855 {
856 cairo_select_font_face(m_context,font.GetFaceName().mb_str(wxConvUTF8),
857 font.GetStyle() == wxFONTSTYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC:CAIRO_FONT_SLANT_NORMAL,
858 font.GetWeight() == wxFONTWEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD:CAIRO_FONT_WEIGHT_NORMAL);
859
860 cairo_set_font_size(m_context,font.GetPointSize());
861 // TODO UNDERLINE
862 // TODO FIX SIZE
863 }
864
865 wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc )
866 {
867 return new wxCairoContext(dc);
868 }