]> git.saurik.com Git - wxWidgets.git/blame - src/generic/graphicc.cpp
Handle Shift-TAB correctly in wxOSX/Carbon wxComboBox.
[wxWidgets.git] / src / generic / graphicc.cpp
CommitLineData
184fc6c8
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/graphicc.cpp
3// Purpose: cairo device context class
4// Author: Stefan Csomor
5// Modified by:
e0876d73 6// Created: 2006-10-03
184fc6c8 7// RCS-ID: $Id$
e0876d73 8// Copyright: (c) 2006 Stefan Csomor
184fc6c8
SC
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
184fc6c8 14#ifdef __BORLANDC__
7f0d0111 15 #pragma hdrstop
184fc6c8
SC
16#endif
17
9a67941f 18#if wxUSE_GRAPHICS_CONTEXT
c0e69d72 19
6c99dbd5 20#include "wx/graphics.h"
9a67941f
VZ
21
22#if wxUSE_CAIRO
23
932d0768
RD
24// keep cairo.h from defining dllimport as we're defining the symbols inside
25// the wx dll in order to load them dynamically.
26#define cairo_public
27
6c99dbd5
VZ
28#include "wx/cairo.h"
29
184fc6c8 30#ifndef WX_PRECOMP
7f0d0111
VZ
31 #include "wx/bitmap.h"
32 #include "wx/icon.h"
7f0d0111
VZ
33 #include "wx/dcclient.h"
34 #include "wx/dcmemory.h"
35 #include "wx/dcprint.h"
239e6af7 36 #include "wx/window.h"
184fc6c8
SC
37#endif
38
2f94ab40 39#include "wx/private/graphics.h"
d9485f89 40#include "wx/rawbmp.h"
50de831a 41#include "wx/vector.h"
184fc6c8 42
184fc6c8
SC
43using namespace std;
44
184fc6c8
SC
45//-----------------------------------------------------------------------------
46// device context implementation
47//
48// more and more of the dc functionality should be implemented by calling
49// the appropricate wxCairoContext, but we will have to do that step by step
50// also coordinate conversions should be moved to native matrix ops
51//-----------------------------------------------------------------------------
52
53// we always stock two context states, one at entry, to be able to preserve the
54// state we were called with, the other one after changing to HI Graphics orientation
55// (this one is used for getting back clippings etc)
56
57//-----------------------------------------------------------------------------
58// wxGraphicsPath implementation
59//-----------------------------------------------------------------------------
60
61// TODO remove this dependency (gdiplus needs the macros)
62
63#ifndef max
64#define max(a,b) (((a) > (b)) ? (a) : (b))
65#endif
66
67#ifndef min
68#define min(a,b) (((a) < (b)) ? (a) : (b))
69#endif
70
71#include <cairo.h>
c0e69d72
KO
72#ifdef __WXMSW__
73#include <cairo-win32.h>
365d11be
VZ
74// Notice that the order is important: cairo-win32.h includes windows.h which
75// pollutes the global name space with macros so include our own header which
76// #undefines them after it.
77#include "wx/msw/private.h"
c0e69d72
KO
78#endif
79
00bd8e72 80#ifdef __WXGTK__
184fc6c8 81#include <gtk/gtk.h>
84f67b11 82#include "wx/fontutil.h"
9dc44eff 83#ifndef __WXGTK3__
888dde65 84#include "wx/gtk/dc.h"
00bd8e72 85#endif
9dc44eff 86#endif
184fc6c8 87
e7f9f819 88#ifdef __WXMAC__
33ddeaba 89#include "wx/osx/private.h"
e7f9f819
SC
90#include <cairo-quartz.h>
91#include <cairo-atsui.h>
92#endif
93
0db8a70e 94class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData
184fc6c8 95{
184fc6c8 96public :
0db8a70e
RD
97 wxCairoPathData(wxGraphicsRenderer* renderer, cairo_t* path = NULL);
98 ~wxCairoPathData();
184fc6c8 99
0db8a70e 100 virtual wxGraphicsObjectRefData *Clone() const;
184fc6c8
SC
101
102 //
103 // These are the path primitives from which everything else can be constructed
104 //
105
106 // begins a new subpath at (x,y)
107 virtual void MoveToPoint( wxDouble x, wxDouble y );
108
109 // adds a straight line from the current point to (x,y)
110 virtual void AddLineToPoint( wxDouble x, wxDouble y );
111
112 // adds a cubic Bezier curve from the current point, using two control points and an end point
113 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
114
115
116 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
117 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
118
119 // gets the last point of the current path, (0,0) if not yet set
0db8a70e 120 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
184fc6c8 121
00bd8e72 122 // adds another path
0db8a70e 123 virtual void AddPath( const wxGraphicsPathData* path );
00bd8e72 124
184fc6c8
SC
125 // closes the current sub-path
126 virtual void CloseSubpath();
127
128 //
129 // These are convenience functions which - if not available natively will be assembled
130 // using the primitives from above
131 //
132
133 /*
134
49ad157e 135 // appends a rectangle as a new closed subpath
184fc6c8
SC
136 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
137 // appends an ellipsis as a new closed subpath fitting the passed rectangle
138 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
139
140 // 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)
141 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
142 */
143
cd5adaa6
RD
144 // returns the native path
145 virtual void * GetNativePath() const ;
146
147 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
0db8a70e 148 virtual void UnGetNativePath(void *p) const;
f540e5bd 149
00bd8e72 150 // transforms each point of this path by the matrix
0db8a70e 151 virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
00bd8e72
SC
152
153 // gets the bounding box enclosing all points (possibly including control points)
0db8a70e 154 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
00bd8e72 155
94a007ec 156 virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxWINDING_RULE) const;
00bd8e72 157
184fc6c8
SC
158private :
159 cairo_t* m_pathContext;
160};
161
0db8a70e 162class WXDLLIMPEXP_CORE wxCairoMatrixData : public wxGraphicsMatrixData
184fc6c8 163{
00bd8e72 164public :
0db8a70e
RD
165 wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix = NULL ) ;
166 virtual ~wxCairoMatrixData() ;
184fc6c8 167
0db8a70e 168 virtual wxGraphicsObjectRefData *Clone() const ;
184fc6c8 169
00bd8e72 170 // concatenates the matrix
0db8a70e 171 virtual void Concat( const wxGraphicsMatrixData *t );
184fc6c8 172
00bd8e72 173 // sets the matrix to the respective values
49ad157e 174 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
00bd8e72 175 wxDouble tx=0.0, wxDouble ty=0.0);
184fc6c8 176
248802d0
RD
177 // gets the component valuess of the matrix
178 virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL,
179 wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const;
49ad157e 180
00bd8e72
SC
181 // makes this the inverse matrix
182 virtual void Invert();
184fc6c8 183
00bd8e72 184 // returns true if the elements of the transformation matrix are equal ?
0db8a70e 185 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
184fc6c8 186
00bd8e72 187 // return true if this is the identity matrix
0db8a70e 188 virtual bool IsIdentity() const;
184fc6c8 189
00bd8e72
SC
190 //
191 // transformation
192 //
184fc6c8 193
00bd8e72
SC
194 // add the translation to this matrix
195 virtual void Translate( wxDouble dx , wxDouble dy );
196
197 // add the scale to this matrix
198 virtual void Scale( wxDouble xScale , wxDouble yScale );
199
200 // add the rotation to this matrix (radians)
49ad157e 201 virtual void Rotate( wxDouble angle );
00bd8e72
SC
202
203 //
204 // apply the transforms
205 //
206
207 // applies that matrix to the point
0db8a70e 208 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
00bd8e72
SC
209
210 // applies the matrix except for translations
0db8a70e 211 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
00bd8e72
SC
212
213 // returns the native representation
214 virtual void * GetNativeMatrix() const;
215private:
216 cairo_matrix_t m_matrix ;
00bd8e72
SC
217} ;
218
7447d53c
VZ
219// Common base class for pens and brushes.
220class wxCairoPenBrushBaseData : public wxGraphicsObjectRefData
221{
222public:
223 wxCairoPenBrushBaseData(wxGraphicsRenderer* renderer,
224 const wxColour& col,
225 bool isTransparent);
226 virtual ~wxCairoPenBrushBaseData();
227
228 virtual void Apply( wxGraphicsContext* context );
229
230protected:
231 // Call this to use the given bitmap as stipple. Bitmap must be non-null
232 // and valid.
233 void InitStipple(wxBitmap* bmp);
234
235 // Call this to use the given hatch style. Hatch style must be valid.
236 void InitHatch(wxHatchStyle hatchStyle);
237
238
239 double m_red;
240 double m_green;
241 double m_blue;
242 double m_alpha;
243
244 cairo_pattern_t* m_pattern;
245 class wxCairoBitmapData* m_bmpdata;
246
247private:
248 // Called once to allocate m_pattern if needed.
249 void InitHatchPattern(cairo_t* ctext);
250
251 wxHatchStyle m_hatchStyle;
252
253 wxDECLARE_NO_COPY_CLASS(wxCairoPenBrushBaseData);
254};
255
256class WXDLLIMPEXP_CORE wxCairoPenData : public wxCairoPenBrushBaseData
184fc6c8 257{
00bd8e72 258public:
87752530
SC
259 wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
260 ~wxCairoPenData();
00bd8e72
SC
261
262 void Init();
263
264 virtual void Apply( wxGraphicsContext* context );
265 virtual wxDouble GetWidth() { return m_width; }
266
267private :
268 double m_width;
49ad157e 269
00bd8e72
SC
270 cairo_line_cap_t m_cap;
271 cairo_line_join_t m_join;
272
273 int m_count;
274 const double *m_lengths;
275 double *m_userLengths;
184fc6c8 276
50de831a 277 wxDECLARE_NO_COPY_CLASS(wxCairoPenData);
00bd8e72
SC
278};
279
7447d53c 280class WXDLLIMPEXP_CORE wxCairoBrushData : public wxCairoPenBrushBaseData
184fc6c8 281{
00bd8e72 282public:
87752530
SC
283 wxCairoBrushData( wxGraphicsRenderer* renderer );
284 wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
4ee4c7b9
VZ
285
286 void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
287 wxDouble x2, wxDouble y2,
288 const wxGraphicsGradientStops& stops);
289 void CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
290 wxDouble xc, wxDouble yc, wxDouble radius,
291 const wxGraphicsGradientStops& stops);
00bd8e72
SC
292
293protected:
294 virtual void Init();
295
4ee4c7b9
VZ
296 // common part of Create{Linear,Radial}GradientBrush()
297 void AddGradientStops(const wxGraphicsGradientStops& stops);
00bd8e72
SC
298};
299
87752530 300class wxCairoFontData : public wxGraphicsObjectRefData
184fc6c8 301{
00bd8e72 302public:
87752530 303 wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
fa378d36
VZ
304 wxCairoFontData(wxGraphicsRenderer* renderer,
305 double sizeInPixels,
306 const wxString& facename,
307 int flags,
308 const wxColour& col);
87752530 309 ~wxCairoFontData();
00bd8e72 310
fa378d36 311 virtual bool Apply( wxGraphicsContext* context );
84f67b11 312#ifdef __WXGTK__
304c3065 313 const wxFont& GetFont() const { return m_wxfont; }
84f67b11 314#endif
00bd8e72 315private :
fa378d36
VZ
316 void InitColour(const wxColour& col);
317 void InitFontComponents(const wxString& facename,
318 cairo_font_slant_t slant,
319 cairo_font_weight_t weight);
320
00bd8e72 321 double m_size;
00bd8e72
SC
322 double m_red;
323 double m_green;
324 double m_blue;
325 double m_alpha;
84f67b11 326#ifdef __WXMAC__
e7f9f819 327 cairo_font_face_t *m_font;
84f67b11 328#elif defined(__WXGTK__)
304c3065 329 wxFont m_wxfont;
fa378d36
VZ
330#endif
331
332 // These members are used when the font is created from its face name and
333 // flags (and not from wxFont) and also even when creating it from wxFont
334 // on the platforms not covered above.
335 //
336 // Notice that we can't use cairo_font_face_t instead of storing those,
337 // even though it would be simpler and need less #ifdefs, because
338 // cairo_toy_font_face_create() that we'd need to create it is only
339 // available in Cairo 1.8 and we require just 1.2 currently. If we do drop
340 // support for < 1.8 versions in the future it would be definitely better
341 // to use cairo_toy_font_face_create() instead.
84f67b11
SC
342 wxCharBuffer m_fontName;
343 cairo_font_slant_t m_slant;
344 cairo_font_weight_t m_weight;
00bd8e72 345};
184fc6c8 346
8b180bde 347class wxCairoBitmapData : public wxGraphicsBitmapData
2fc9c1ea
KO
348{
349public:
350 wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp );
0a470e5e
VZ
351#if wxUSE_IMAGE
352 wxCairoBitmapData(wxGraphicsRenderer* renderer, const wxImage& image);
353#endif // wxUSE_IMAGE
2986eb86 354 wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap );
2fc9c1ea
KO
355 ~wxCairoBitmapData();
356
357 virtual cairo_surface_t* GetCairoSurface() { return m_surface; }
358 virtual cairo_pattern_t* GetCairoPattern() { return m_pattern; }
f2c757c5 359 virtual void* GetNativeBitmap() const { return m_surface; }
2fc9c1ea 360 virtual wxSize GetSize() { return wxSize(m_width, m_height); }
08b2d55f
VZ
361
362#if wxUSE_IMAGE
363 wxImage ConvertToImage() const;
364#endif // wxUSE_IMAGE
365
2fc9c1ea 366private :
5f606e65
VZ
367 // Allocate m_buffer for the bitmap of the given size in the given format.
368 //
369 // Returns the stride used for the buffer.
370 int InitBuffer(int width, int height, cairo_format_t format);
371
372 // Really create the surface using the buffer (which was supposed to be
373 // filled since InitBuffer() call).
374 void InitSurface(cairo_format_t format, int stride);
375
376
2fc9c1ea
KO
377 cairo_surface_t* m_surface;
378 cairo_pattern_t* m_pattern;
379 int m_width;
380 int m_height;
381 unsigned char* m_buffer;
382};
383
00bd8e72 384class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext
184fc6c8 385{
184fc6c8 386public:
00bd8e72 387 wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc );
888dde65 388 wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc );
c9008abe 389 wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc );
00bd8e72 390#ifdef __WXGTK__
9dc44eff 391 wxCairoContext( wxGraphicsRenderer* renderer, GdkWindow *window );
9f2b6b31
RD
392#endif
393#ifdef __WXMSW__
394 wxCairoContext( wxGraphicsRenderer* renderer, HDC context );
00bd8e72
SC
395#endif
396 wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context );
397 wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window);
79313208
VZ
398
399 // If this ctor is used, Init() must be called by the derived class later.
400 wxCairoContext( wxGraphicsRenderer* renderer );
401
184fc6c8
SC
402 virtual ~wxCairoContext();
403
e7f9f819 404 virtual bool ShouldOffset() const
49ad157e 405 {
136a1de9
SC
406 if ( !m_enableOffset )
407 return false;
408
e7f9f819
SC
409 int penwidth = 0 ;
410 if ( !m_pen.IsNull() )
411 {
412 penwidth = (int)((wxCairoPenData*)m_pen.GetRefData())->GetWidth();
413 if ( penwidth == 0 )
414 penwidth = 1;
415 }
416 return ( penwidth % 2 ) == 1;
417 }
418
184fc6c8 419 virtual void Clip( const wxRegion &region );
c0e69d72
KO
420#ifdef __WXMSW__
421 cairo_surface_t* m_mswSurface;
365d11be 422 WindowHDC m_mswWindowHDC;
c0e69d72 423#endif
539e2795
SC
424
425 // clips drawings to the rect
426 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
539e2795 427
cd5adaa6
RD
428 // resets the clipping to original extent
429 virtual void ResetClip();
430
431 virtual void * GetNativeContext();
432
bf02a7f9 433 virtual bool SetAntialiasMode(wxAntialiasMode antialias);
49ad157e 434
133cb28b
SC
435 virtual bool SetInterpolationQuality(wxInterpolationQuality interpolation);
436
bf02a7f9
SC
437 virtual bool SetCompositionMode(wxCompositionMode op);
438
439 virtual void BeginLayer(wxDouble opacity);
440
441 virtual void EndLayer();
03647350 442
0db8a70e 443 virtual void StrokePath( const wxGraphicsPath& p );
94a007ec 444 virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxWINDING_RULE );
184fc6c8 445
184fc6c8
SC
446 virtual void Translate( wxDouble dx , wxDouble dy );
447 virtual void Scale( wxDouble xScale , wxDouble yScale );
448 virtual void Rotate( wxDouble angle );
449
00bd8e72 450 // concatenates this transform with the current transform of this context
0db8a70e 451 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
00bd8e72
SC
452
453 // sets the transform of this context
0db8a70e 454 virtual void SetTransform( const wxGraphicsMatrix& matrix );
00bd8e72
SC
455
456 // gets the matrix of this context
0db8a70e 457 virtual wxGraphicsMatrix GetTransform() const;
00bd8e72 458
e77cba1a 459 virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
184fc6c8
SC
460 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
461 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
462 virtual void PushState();
463 virtual void PopState();
464
184fc6c8
SC
465 virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
466 wxDouble *descent, wxDouble *externalLeading ) const;
467 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
468
50de831a
PC
469protected:
470 virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
471
e7f9f819 472 void Init(cairo_t *context);
49ad157e 473
0a470e5e 474private:
184fc6c8 475 cairo_t* m_context;
03647350 476
bf02a7f9 477 wxVector<float> m_layerOpacities;
0b7dce54 478
c0c133e1 479 wxDECLARE_NO_COPY_CLASS(wxCairoContext);
184fc6c8
SC
480};
481
0a470e5e
VZ
482#if wxUSE_IMAGE
483// ----------------------------------------------------------------------------
484// wxCairoImageContext: context associated with a wxImage.
485// ----------------------------------------------------------------------------
486
487class wxCairoImageContext : public wxCairoContext
488{
489public:
490 wxCairoImageContext(wxGraphicsRenderer* renderer, wxImage& image) :
491 wxCairoContext(renderer),
492 m_image(image),
493 m_data(renderer, image)
494 {
495 Init(cairo_create(m_data.GetCairoSurface()));
496 }
497
498 virtual ~wxCairoImageContext()
499 {
500 m_image = m_data.ConvertToImage();
501 }
502
503private:
504 wxImage& m_image;
505 wxCairoBitmapData m_data;
506
507 wxDECLARE_NO_COPY_CLASS(wxCairoImageContext);
508};
509#endif // wxUSE_IMAGE
510
7447d53c
VZ
511// ----------------------------------------------------------------------------
512// wxCairoPenBrushBaseData implementation
513//-----------------------------------------------------------------------------
514
515wxCairoPenBrushBaseData::wxCairoPenBrushBaseData(wxGraphicsRenderer* renderer,
516 const wxColour& col,
517 bool isTransparent)
518 : wxGraphicsObjectRefData(renderer)
519{
520 m_hatchStyle = wxHATCHSTYLE_INVALID;
521 m_pattern = NULL;
522 m_bmpdata = NULL;
523
524 if ( isTransparent )
525 {
526 m_red =
527 m_green =
528 m_blue =
529 m_alpha = 0;
530 }
531 else // non-transparent
532 {
533 m_red = col.Red()/255.0;
534 m_green = col.Green()/255.0;
535 m_blue = col.Blue()/255.0;
536 m_alpha = col.Alpha()/255.0;
537 }
538}
539
540wxCairoPenBrushBaseData::~wxCairoPenBrushBaseData()
541{
542 if (m_bmpdata)
543 {
544 // Deleting the bitmap data also deletes the pattern referenced by
545 // m_pattern, so set it to NULL to avoid deleting it twice.
546 delete m_bmpdata;
547 m_pattern = NULL;
548 }
549 if (m_pattern)
550 cairo_pattern_destroy(m_pattern);
551}
552
553void wxCairoPenBrushBaseData::InitHatchPattern(cairo_t* ctext)
554{
555 cairo_surface_t* const
556 surface = cairo_surface_create_similar(
557 cairo_get_target(ctext), CAIRO_CONTENT_COLOR_ALPHA, 10, 10
558 );
559
560 cairo_t* const cr = cairo_create(surface);
561 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
562 cairo_set_line_width(cr, 1);
563 cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER);
564
565 switch ( m_hatchStyle )
566 {
567 case wxHATCHSTYLE_CROSS:
568 cairo_move_to(cr, 5, 0);
569 cairo_line_to(cr, 5, 10);
570 cairo_move_to(cr, 0, 5);
571 cairo_line_to(cr, 10, 5);
572 break;
573
574 case wxHATCHSTYLE_BDIAGONAL:
575 cairo_move_to(cr, 0, 10);
576 cairo_line_to(cr, 10, 0);
577 break;
578
579 case wxHATCHSTYLE_FDIAGONAL:
580 cairo_move_to(cr, 0, 0);
581 cairo_line_to(cr, 10, 10);
582 break;
583
584 case wxHATCHSTYLE_CROSSDIAG:
585 cairo_move_to(cr, 0, 0);
586 cairo_line_to(cr, 10, 10);
587 cairo_move_to(cr, 10, 0);
588 cairo_line_to(cr, 0, 10);
589 break;
590
591 case wxHATCHSTYLE_HORIZONTAL:
592 cairo_move_to(cr, 0, 5);
593 cairo_line_to(cr, 10, 5);
594 break;
595
596 case wxHATCHSTYLE_VERTICAL:
597 cairo_move_to(cr, 5, 0);
598 cairo_line_to(cr, 5, 10);
599 break;
600
601 default:
602 wxFAIL_MSG(wxS("Invalid hatch pattern style."));
603 }
604
605 cairo_set_source_rgba(cr, m_red, m_green, m_blue, m_alpha);
606 cairo_stroke(cr);
607
608 cairo_destroy(cr);
609
610 m_pattern = cairo_pattern_create_for_surface(surface);
611 cairo_surface_destroy(surface);
612 cairo_pattern_set_extend(m_pattern, CAIRO_EXTEND_REPEAT);
613}
614
615void wxCairoPenBrushBaseData::InitStipple(wxBitmap* bmp)
616{
617 wxCHECK_RET( bmp && bmp->IsOk(), wxS("Invalid stippled bitmap") );
618
619 m_bmpdata = new wxCairoBitmapData(GetRenderer(), *bmp);
620 m_pattern = m_bmpdata->GetCairoPattern();
621 cairo_pattern_set_extend(m_pattern, CAIRO_EXTEND_REPEAT);
622}
623
624void wxCairoPenBrushBaseData::InitHatch(wxHatchStyle hatchStyle)
625{
626 // We can't create m_pattern right now as we don't have the Cairo context
627 // needed for it, so just remember that we need to do it.
628 m_hatchStyle = hatchStyle;
629}
630
631void wxCairoPenBrushBaseData::Apply( wxGraphicsContext* context )
632{
633 cairo_t* const ctext = (cairo_t*) context->GetNativeContext();
634
635 if ( m_hatchStyle != wxHATCHSTYLE_INVALID && !m_pattern )
636 InitHatchPattern(ctext);
637
638 if ( m_pattern )
639 cairo_set_source(ctext, m_pattern);
640 else
641 cairo_set_source_rgba(ctext, m_red, m_green, m_blue, m_alpha);
642}
643
184fc6c8 644//-----------------------------------------------------------------------------
87752530 645// wxCairoPenData implementation
184fc6c8
SC
646//-----------------------------------------------------------------------------
647
87752530 648wxCairoPenData::~wxCairoPenData()
539e2795 649{
00bd8e72 650 delete[] m_userLengths;
539e2795 651}
cd5adaa6 652
87752530 653void wxCairoPenData::Init()
539e2795 654{
00bd8e72
SC
655 m_lengths = NULL;
656 m_userLengths = NULL;
657 m_width = 0;
658 m_count = 0;
539e2795
SC
659}
660
87752530 661wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
7447d53c 662 : wxCairoPenBrushBaseData(renderer, pen.GetColour(), pen.IsTransparent())
49ad157e 663{
00bd8e72 664 Init();
7447d53c 665 m_width = pen.GetWidth();
00bd8e72
SC
666 if (m_width <= 0.0)
667 m_width = 0.1;
539e2795 668
7447d53c 669 switch ( pen.GetCap() )
184fc6c8
SC
670 {
671 case wxCAP_ROUND :
00bd8e72 672 m_cap = CAIRO_LINE_CAP_ROUND;
184fc6c8
SC
673 break;
674
675 case wxCAP_PROJECTING :
00bd8e72 676 m_cap = CAIRO_LINE_CAP_SQUARE;
184fc6c8
SC
677 break;
678
679 case wxCAP_BUTT :
00bd8e72 680 m_cap = CAIRO_LINE_CAP_BUTT;
184fc6c8
SC
681 break;
682
683 default :
00bd8e72 684 m_cap = CAIRO_LINE_CAP_BUTT;
184fc6c8
SC
685 break;
686 }
184fc6c8 687
7447d53c 688 switch ( pen.GetJoin() )
184fc6c8
SC
689 {
690 case wxJOIN_BEVEL :
00bd8e72 691 m_join = CAIRO_LINE_JOIN_BEVEL;
184fc6c8
SC
692 break;
693
694 case wxJOIN_MITER :
00bd8e72 695 m_join = CAIRO_LINE_JOIN_MITER;
184fc6c8
SC
696 break;
697
698 case wxJOIN_ROUND :
00bd8e72 699 m_join = CAIRO_LINE_JOIN_ROUND;
184fc6c8
SC
700 break;
701
702 default :
00bd8e72 703 m_join = CAIRO_LINE_JOIN_MITER;
184fc6c8
SC
704 break;
705 }
184fc6c8 706
00bd8e72 707 const double dashUnit = m_width < 1.0 ? 1.0 : m_width;
184fc6c8 708 const double dotted[] =
00bd8e72
SC
709 {
710 dashUnit , dashUnit + 2.0
711 };
712 static const double short_dashed[] =
713 {
714 9.0 , 6.0
715 };
716 static const double dashed[] =
717 {
718 19.0 , 9.0
719 };
720 static const double dotted_dashed[] =
721 {
722 9.0 , 6.0 , 3.0 , 3.0
723 };
184fc6c8 724
7447d53c 725 switch ( pen.GetStyle() )
184fc6c8 726 {
fb040094 727 case wxPENSTYLE_SOLID :
184fc6c8
SC
728 break;
729
fb040094 730 case wxPENSTYLE_DOT :
00bd8e72
SC
731 m_count = WXSIZEOF(dotted);
732 m_userLengths = new double[ m_count ] ;
733 memcpy( m_userLengths, dotted, sizeof(dotted) );
734 m_lengths = m_userLengths;
184fc6c8
SC
735 break;
736
fb040094 737 case wxPENSTYLE_LONG_DASH :
84f67b11 738 m_lengths = dashed ;
00bd8e72 739 m_count = WXSIZEOF(dashed);
184fc6c8
SC
740 break;
741
fb040094 742 case wxPENSTYLE_SHORT_DASH :
84f67b11 743 m_lengths = short_dashed ;
00bd8e72 744 m_count = WXSIZEOF(short_dashed);
184fc6c8
SC
745 break;
746
fb040094 747 case wxPENSTYLE_DOT_DASH :
84f67b11 748 m_lengths = dotted_dashed ;
00bd8e72 749 m_count = WXSIZEOF(dotted_dashed);
184fc6c8
SC
750 break;
751
fb040094 752 case wxPENSTYLE_USER_DASH :
184fc6c8
SC
753 {
754 wxDash *wxdashes ;
7447d53c 755 m_count = pen.GetDashes( &wxdashes ) ;
00bd8e72 756 if ((wxdashes != NULL) && (m_count > 0))
184fc6c8 757 {
00bd8e72
SC
758 m_userLengths = new double[m_count] ;
759 for ( int i = 0 ; i < m_count ; ++i )
184fc6c8 760 {
00bd8e72 761 m_userLengths[i] = wxdashes[i] * dashUnit ;
184fc6c8 762
00bd8e72
SC
763 if ( i % 2 == 1 && m_userLengths[i] < dashUnit + 2.0 )
764 m_userLengths[i] = dashUnit + 2.0 ;
765 else if ( i % 2 == 0 && m_userLengths[i] < dashUnit )
766 m_userLengths[i] = dashUnit ;
184fc6c8
SC
767 }
768 }
00bd8e72 769 m_lengths = m_userLengths ;
184fc6c8
SC
770 }
771 break;
7447d53c 772
fb040094 773 case wxPENSTYLE_STIPPLE :
7447d53c
VZ
774 case wxPENSTYLE_STIPPLE_MASK :
775 case wxPENSTYLE_STIPPLE_MASK_OPAQUE :
776 InitStipple(pen.GetStipple());
184fc6c8 777 break;
7447d53c 778
184fc6c8 779 default :
7447d53c
VZ
780 if ( pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH
781 && pen.GetStyle() <= wxPENSTYLE_LAST_HATCH )
184fc6c8 782 {
7447d53c 783 InitHatch(static_cast<wxHatchStyle>(pen.GetStyle()));
184fc6c8
SC
784 }
785 break;
786 }
00bd8e72 787}
184fc6c8 788
87752530 789void wxCairoPenData::Apply( wxGraphicsContext* context )
00bd8e72 790{
7447d53c
VZ
791 wxCairoPenBrushBaseData::Apply(context);
792
00bd8e72
SC
793 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
794 cairo_set_line_width(ctext,m_width);
00bd8e72
SC
795 cairo_set_line_cap(ctext,m_cap);
796 cairo_set_line_join(ctext,m_join);
797 cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0);
184fc6c8
SC
798}
799
00bd8e72 800//-----------------------------------------------------------------------------
87752530 801// wxCairoBrushData implementation
00bd8e72
SC
802//-----------------------------------------------------------------------------
803
7f8bd9fc 804wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer )
7447d53c 805 : wxCairoPenBrushBaseData(renderer, wxColour(), true /* transparent */)
00bd8e72
SC
806{
807 Init();
808}
184fc6c8 809
7447d53c
VZ
810wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer,
811 const wxBrush &brush )
812 : wxCairoPenBrushBaseData(renderer, brush.GetColour(), brush.IsTransparent())
00bd8e72 813{
7f8bd9fc 814 Init();
49ad157e 815
7447d53c 816 switch ( brush.GetStyle() )
00bd8e72 817 {
7447d53c
VZ
818 case wxBRUSHSTYLE_STIPPLE:
819 case wxBRUSHSTYLE_STIPPLE_MASK:
820 case wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE:
821 InitStipple(brush.GetStipple());
822 break;
823
824 default:
825 if ( brush.IsHatch() )
826 InitHatch(static_cast<wxHatchStyle>(brush.GetStyle()));
827 break;
00bd8e72 828 }
184fc6c8
SC
829}
830
4ee4c7b9
VZ
831void wxCairoBrushData::AddGradientStops(const wxGraphicsGradientStops& stops)
832{
833 // loop over all the stops, they include the beginning and ending ones
834 const unsigned numStops = stops.GetCount();
835 for ( unsigned n = 0; n < numStops; n++ )
836 {
837 const wxGraphicsGradientStop stop = stops.Item(n);
838
839 const wxColour col = stop.GetColour();
840
841 cairo_pattern_add_color_stop_rgba
842 (
7447d53c 843 m_pattern,
4ee4c7b9
VZ
844 stop.GetPosition(),
845 col.Red()/255.0,
846 col.Green()/255.0,
847 col.Blue()/255.0,
848 col.Alpha()/255.0
849 );
850 }
851
7447d53c 852 wxASSERT_MSG(cairo_pattern_status(m_pattern) == CAIRO_STATUS_SUCCESS,
4ee4c7b9
VZ
853 wxT("Couldn't create cairo pattern"));
854}
855
856void
857wxCairoBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
858 wxDouble x2, wxDouble y2,
859 const wxGraphicsGradientStops& stops)
184fc6c8 860{
7447d53c 861 m_pattern = cairo_pattern_create_linear(x1,y1,x2,y2);
4ee4c7b9
VZ
862
863 AddGradientStops(stops);
184fc6c8
SC
864}
865
4ee4c7b9
VZ
866void
867wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
868 wxDouble xc, wxDouble yc,
869 wxDouble radius,
870 const wxGraphicsGradientStops& stops)
184fc6c8 871{
7447d53c 872 m_pattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
4ee4c7b9
VZ
873
874 AddGradientStops(stops);
184fc6c8
SC
875}
876
87752530 877void wxCairoBrushData::Init()
184fc6c8 878{
7447d53c
VZ
879 m_pattern = NULL;
880 m_bmpdata = NULL;
184fc6c8
SC
881}
882
00bd8e72 883//-----------------------------------------------------------------------------
87752530 884// wxCairoFontData implementation
00bd8e72
SC
885//-----------------------------------------------------------------------------
886
fa378d36 887void wxCairoFontData::InitColour(const wxColour& col)
184fc6c8 888{
00bd8e72 889 m_red = col.Red()/255.0;
49ad157e 890 m_green = col.Green()/255.0;
00bd8e72
SC
891 m_blue = col.Blue()/255.0;
892 m_alpha = col.Alpha()/255.0;
fa378d36
VZ
893}
894
895void
896wxCairoFontData::InitFontComponents(const wxString& facename,
897 cairo_font_slant_t slant,
898 cairo_font_weight_t weight)
899{
900 m_fontName = facename.mb_str(wxConvUTF8);
901 m_slant = slant;
902 m_weight = weight;
903}
904
905wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font,
304c3065
PC
906 const wxColour& col )
907 : wxGraphicsObjectRefData(renderer)
908#ifdef __WXGTK__
909 , m_wxfont(font)
910#endif
fa378d36
VZ
911{
912 InitColour(col);
913
00bd8e72 914 m_size = font.GetPointSize();
84f67b11
SC
915
916#ifdef __WXMAC__
aa6208d9 917 m_font = cairo_quartz_font_face_create_for_cgfont( font.OSXGetCGFont() );
84f67b11 918#elif defined(__WXGTK__)
84f67b11 919#else
fa378d36
VZ
920 InitFontComponents
921 (
922 font.GetFaceName(),
923 font.GetStyle() == wxFONTSTYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC
924 : CAIRO_FONT_SLANT_NORMAL,
925 font.GetWeight() == wxFONTWEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD
926 : CAIRO_FONT_WEIGHT_NORMAL
927 );
e7f9f819 928#endif
184fc6c8
SC
929}
930
fa378d36
VZ
931wxCairoFontData::wxCairoFontData(wxGraphicsRenderer* renderer,
932 double sizeInPixels,
933 const wxString& facename,
934 int flags,
935 const wxColour& col) :
936 wxGraphicsObjectRefData(renderer)
937{
938 InitColour(col);
939
940 // Resolution for Cairo image surfaces is 72 DPI meaning that the sizes in
941 // points and pixels are identical, so we can just pass the size in pixels
942 // directly to cairo_set_font_size().
943 m_size = sizeInPixels;
944
304c3065 945#if defined(__WXMAC__)
fa378d36
VZ
946 m_font = NULL;
947#endif
948
00953cf0
VZ
949 // There is no need to set m_underlined under wxGTK in this case, it can
950 // only be used if m_font != NULL.
fa378d36
VZ
951
952 InitFontComponents
953 (
954 facename,
955 flags & wxFONTFLAG_ITALIC ? CAIRO_FONT_SLANT_ITALIC
956 : CAIRO_FONT_SLANT_NORMAL,
957 flags & wxFONTFLAG_BOLD ? CAIRO_FONT_WEIGHT_BOLD
958 : CAIRO_FONT_WEIGHT_NORMAL
959 );
960}
961
87752530 962wxCairoFontData::~wxCairoFontData()
184fc6c8 963{
84f67b11 964#ifdef __WXMAC__
fa378d36
VZ
965 if ( m_font )
966 cairo_font_face_destroy( m_font );
84f67b11 967#endif
00bd8e72 968}
184fc6c8 969
fa378d36 970bool wxCairoFontData::Apply( wxGraphicsContext* context )
00bd8e72
SC
971{
972 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
973 cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
84f67b11 974#ifdef __WXGTK__
304c3065 975 if (m_wxfont.IsOk())
fa378d36
VZ
976 {
977 // Nothing to do, the caller uses Pango layout functions to do
978 // everything.
979 return true;
980 }
84f67b11 981#elif defined(__WXMAC__)
fa378d36
VZ
982 if ( m_font )
983 {
984 cairo_set_font_face(ctext, m_font);
985 cairo_set_font_size(ctext, m_size );
986 return true;
987 }
988#endif
989
990 // If we get here, we must be on a platform without native font support or
991 // we're using toy Cairo API even under wxGTK/wxMac.
711a4812 992 cairo_select_font_face(ctext, m_fontName, m_slant, m_weight );
84f67b11 993 cairo_set_font_size(ctext, m_size );
fa378d36
VZ
994
995 // Indicate that we don't use native fonts for the platforms which care
996 // about this (currently only wxGTK).
997 return false;
00bd8e72
SC
998}
999
1000//-----------------------------------------------------------------------------
0db8a70e 1001// wxCairoPathData implementation
00bd8e72
SC
1002//-----------------------------------------------------------------------------
1003
0db8a70e
RD
1004wxCairoPathData::wxCairoPathData( wxGraphicsRenderer* renderer, cairo_t* pathcontext)
1005 : wxGraphicsPathData(renderer)
184fc6c8 1006{
00bd8e72 1007 if (pathcontext)
184fc6c8 1008 {
00bd8e72
SC
1009 m_pathContext = pathcontext;
1010 }
1011 else
1012 {
1013 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1);
1014 m_pathContext = cairo_create(surface);
1015 cairo_surface_destroy (surface);
184fc6c8 1016 }
00bd8e72 1017}
184fc6c8 1018
0db8a70e 1019wxCairoPathData::~wxCairoPathData()
00bd8e72
SC
1020{
1021 cairo_destroy(m_pathContext);
184fc6c8
SC
1022}
1023
0db8a70e 1024wxGraphicsObjectRefData *wxCairoPathData::Clone() const
184fc6c8 1025{
00bd8e72
SC
1026 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1);
1027 cairo_t* pathcontext = cairo_create(surface);
1028 cairo_surface_destroy (surface);
1029
1030 cairo_path_t* path = cairo_copy_path(m_pathContext);
1031 cairo_append_path(pathcontext, path);
1032 cairo_path_destroy(path);
0db8a70e 1033 return new wxCairoPathData( GetRenderer() ,pathcontext);
00bd8e72
SC
1034}
1035
1036
0db8a70e 1037void* wxCairoPathData::GetNativePath() const
00bd8e72
SC
1038{
1039 return cairo_copy_path(m_pathContext) ;
1040}
1041
0db8a70e 1042void wxCairoPathData::UnGetNativePath(void *p) const
00bd8e72
SC
1043{
1044 cairo_path_destroy((cairo_path_t*)p);
1045}
1046
1047//
1048// The Primitives
1049//
1050
0db8a70e 1051void wxCairoPathData::MoveToPoint( wxDouble x , wxDouble y )
00bd8e72
SC
1052{
1053 cairo_move_to(m_pathContext,x,y);
1054}
1055
0db8a70e 1056void wxCairoPathData::AddLineToPoint( wxDouble x , wxDouble y )
00bd8e72
SC
1057{
1058 cairo_line_to(m_pathContext,x,y);
1059}
1060
0db8a70e 1061void wxCairoPathData::AddPath( const wxGraphicsPathData* path )
6b06903d 1062{
d9485f89
RD
1063 cairo_path_t* p = (cairo_path_t*)path->GetNativePath();
1064 cairo_append_path(m_pathContext, p);
1065 UnGetNativePath(p);
6b06903d
RD
1066}
1067
0db8a70e 1068void wxCairoPathData::CloseSubpath()
00bd8e72
SC
1069{
1070 cairo_close_path(m_pathContext);
1071}
1072
0db8a70e 1073void wxCairoPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
00bd8e72
SC
1074{
1075 cairo_curve_to(m_pathContext,cx1,cy1,cx2,cy2,x,y);
1076}
1077
1078// gets the last point of the current path, (0,0) if not yet set
0db8a70e 1079void wxCairoPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
00bd8e72
SC
1080{
1081 double dx,dy;
1082 cairo_get_current_point(m_pathContext,&dx,&dy);
0db8a70e
RD
1083 if (x)
1084 *x = dx;
1085 if (y)
1086 *y = dy;
00bd8e72
SC
1087}
1088
0db8a70e 1089void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
00bd8e72 1090{
49ad157e 1091 // as clockwise means positive in our system (y pointing downwards)
00bd8e72
SC
1092 // TODO make this interpretation dependent of the
1093 // real device trans
1094 if ( clockwise||(endAngle-startAngle)>=2*M_PI)
1095 cairo_arc(m_pathContext,x,y,r,startAngle,endAngle);
1096 else
1097 cairo_arc_negative(m_pathContext,x,y,r,startAngle,endAngle);
1098}
1099
1100// transforms each point of this path by the matrix
49ad157e 1101void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix )
00bd8e72
SC
1102{
1103 // as we don't have a true path object, we have to apply the inverse
1104 // matrix to the context
1105 cairo_matrix_t m = *((cairo_matrix_t*) matrix->GetNativeMatrix());
1106 cairo_matrix_invert( &m );
1107 cairo_transform(m_pathContext,&m);
49ad157e 1108}
00bd8e72
SC
1109
1110// gets the bounding box enclosing all points (possibly including control points)
0db8a70e 1111void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
00bd8e72
SC
1112{
1113 double x1,y1,x2,y2;
1114
1115 cairo_stroke_extents( m_pathContext, &x1, &y1, &x2, &y2 );
1116 if ( x2 < x1 )
184fc6c8 1117 {
00bd8e72
SC
1118 *x = x2;
1119 *w = x1-x2;
1120 }
1121 else
1122 {
1123 *x = x1;
1124 *w = x2-x1;
184fc6c8 1125 }
49ad157e 1126
00bd8e72
SC
1127 if( y2 < y1 )
1128 {
1129 *y = y2;
1130 *h = y1-y2;
1131 }
1132 else
1133 {
1134 *y = y1;
1135 *h = y2-y1;
1136 }
1137}
1138
f2b905d7 1139bool wxCairoPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
00bd8e72 1140{
f2b905d7
SC
1141 cairo_set_fill_rule(m_pathContext,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
1142 return cairo_in_fill( m_pathContext, x, y) != 0;
00bd8e72
SC
1143}
1144
1145//-----------------------------------------------------------------------------
0db8a70e 1146// wxCairoMatrixData implementation
00bd8e72
SC
1147//-----------------------------------------------------------------------------
1148
0db8a70e
RD
1149wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix )
1150 : wxGraphicsMatrixData(renderer)
00bd8e72
SC
1151{
1152 if ( matrix )
1153 m_matrix = *matrix;
1154}
1155
49ad157e 1156wxCairoMatrixData::~wxCairoMatrixData()
00bd8e72
SC
1157{
1158 // nothing to do
1159}
1160
49ad157e 1161wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const
00bd8e72 1162{
0db8a70e 1163 return new wxCairoMatrixData(GetRenderer(),&m_matrix);
00bd8e72
SC
1164}
1165
1166// concatenates the matrix
49ad157e 1167void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t )
00bd8e72 1168{
49ad157e 1169 cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix());
00bd8e72
SC
1170}
1171
00bd8e72 1172// sets the matrix to the respective values
49ad157e
VZ
1173void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1174 wxDouble tx, wxDouble ty)
00bd8e72
SC
1175{
1176 cairo_matrix_init( &m_matrix, a, b, c, d, tx, ty);
1177}
1178
248802d0
RD
1179// gets the component valuess of the matrix
1180void wxCairoMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c,
1181 wxDouble* d, wxDouble* tx, wxDouble* ty) const
1182{
1183 if (a) *a = m_matrix.xx;
1184 if (b) *b = m_matrix.yx;
1185 if (c) *c = m_matrix.xy;
1186 if (d) *d = m_matrix.yy;
1187 if (tx) *tx= m_matrix.x0;
1188 if (ty) *ty= m_matrix.y0;
1189}
1190
00bd8e72 1191// makes this the inverse matrix
49ad157e 1192void wxCairoMatrixData::Invert()
00bd8e72
SC
1193{
1194 cairo_matrix_invert( &m_matrix );
1195}
1196
1197// returns true if the elements of the transformation matrix are equal ?
49ad157e 1198bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
00bd8e72
SC
1199{
1200 const cairo_matrix_t* tm = (cairo_matrix_t*) t->GetNativeMatrix();
49ad157e
VZ
1201 return (
1202 m_matrix.xx == tm->xx &&
1203 m_matrix.yx == tm->yx &&
1204 m_matrix.xy == tm->xy &&
1205 m_matrix.yy == tm->yy &&
1206 m_matrix.x0 == tm->x0 &&
00bd8e72
SC
1207 m_matrix.y0 == tm->y0 ) ;
1208}
1209
1210// return true if this is the identity matrix
0db8a70e 1211bool wxCairoMatrixData::IsIdentity() const
00bd8e72
SC
1212{
1213 return ( m_matrix.xx == 1 && m_matrix.yy == 1 &&
1214 m_matrix.yx == 0 && m_matrix.xy == 0 && m_matrix.x0 == 0 && m_matrix.y0 == 0);
1215}
1216
1217//
1218// transformation
1219//
1220
1221// add the translation to this matrix
0db8a70e 1222void wxCairoMatrixData::Translate( wxDouble dx , wxDouble dy )
00bd8e72
SC
1223{
1224 cairo_matrix_translate( &m_matrix, dx, dy) ;
1225}
1226
1227// add the scale to this matrix
0db8a70e 1228void wxCairoMatrixData::Scale( wxDouble xScale , wxDouble yScale )
00bd8e72
SC
1229{
1230 cairo_matrix_scale( &m_matrix, xScale, yScale) ;
1231}
1232
1233// add the rotation to this matrix (radians)
49ad157e 1234void wxCairoMatrixData::Rotate( wxDouble angle )
00bd8e72
SC
1235{
1236 cairo_matrix_rotate( &m_matrix, angle) ;
49ad157e 1237}
00bd8e72
SC
1238
1239//
1240// apply the transforms
1241//
1242
1243// applies that matrix to the point
0db8a70e 1244void wxCairoMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
00bd8e72
SC
1245{
1246 double lx = *x, ly = *y ;
1247 cairo_matrix_transform_point( &m_matrix, &lx, &ly);
1248 *x = lx;
1249 *y = ly;
1250}
1251
1252// applies the matrix except for translations
0db8a70e 1253void wxCairoMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
00bd8e72
SC
1254{
1255 double lx = *dx, ly = *dy ;
1256 cairo_matrix_transform_distance( &m_matrix, &lx, &ly);
1257 *dx = lx;
1258 *dy = ly;
1259}
1260
1261// returns the native representation
0db8a70e 1262void * wxCairoMatrixData::GetNativeMatrix() const
00bd8e72
SC
1263{
1264 return (void*) &m_matrix;
1265}
1266
5f606e65 1267// ----------------------------------------------------------------------------
2fc9c1ea 1268// wxCairoBitmap implementation
5f606e65
VZ
1269// ----------------------------------------------------------------------------
1270
1271int wxCairoBitmapData::InitBuffer(int width, int height, cairo_format_t format)
1272{
1273 wxUnusedVar(format); // Only really unused with Cairo < 1.6.
1274
1275 // Determine the stride: use cairo_format_stride_for_width() if available
1276 // but fall back to 4*width for the earlier versions as this is what that
1277 // function always returns, even in latest Cairo, anyhow.
1278 int stride;
1279#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
1280 if ( cairo_version() >= CAIRO_VERSION_ENCODE(1, 6, 0) )
1281 {
1282 stride = cairo_format_stride_for_width(format, width);
1283
1284 // All our code would totally break if stride were not a multiple of 4
1285 // so ensure this is the case.
1286 if ( stride % 4 )
1287 {
1288 wxFAIL_MSG("Unexpected Cairo image surface stride.");
1289
1290 stride += 4 - stride % 4;
1291 }
1292 }
1293 else
1294#endif
1295 stride = 4*width;
1296
1297 m_width = width;
1298 m_height = height;
1299 m_buffer = new unsigned char[height*stride];
1300
1301 return stride;
1302}
1303
1304void wxCairoBitmapData::InitSurface(cairo_format_t format, int stride)
1305{
1306 m_surface = cairo_image_surface_create_for_data(
1307 m_buffer, format, m_width, m_height, stride);
1308 m_pattern = cairo_pattern_create_for_surface(m_surface);
1309}
2fc9c1ea 1310
2986eb86 1311wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap ) :
8b180bde 1312 wxGraphicsBitmapData( renderer )
2986eb86
SC
1313{
1314 m_surface = bitmap;
1315 m_pattern = cairo_pattern_create_for_surface(m_surface);
1316}
1317
8b180bde 1318wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsBitmapData( renderer )
2fc9c1ea
KO
1319{
1320 wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
1321
711a4812 1322#ifdef wxHAS_RAW_BITMAP
2fc9c1ea
KO
1323 // Create a surface object and copy the bitmap pixel data to it. if the
1324 // image has alpha (or a mask represented as alpha) then we'll use a
1325 // different format and iterator than if it doesn't...
6e6f074b 1326 cairo_format_t bufferFormat = bmp.GetDepth() == 32
9dc44eff 1327#if defined(__WXGTK__) && !defined(__WXGTK3__)
5f606e65 1328 || bmp.GetMask()
932d0768 1329#endif
5f606e65
VZ
1330 ? CAIRO_FORMAT_ARGB32
1331 : CAIRO_FORMAT_RGB24;
1332
1333 int stride = InitBuffer(bmp.GetWidth(), bmp.GetHeight(), bufferFormat);
1334
5f606e65
VZ
1335 wxBitmap bmpSource = bmp; // we need a non-const instance
1336 wxUint32* data = (wxUint32*)m_buffer;
1337
1338 if ( bufferFormat == CAIRO_FORMAT_ARGB32 )
1339 {
1340 // use the bitmap's alpha
95c0502b
VZ
1341 wxAlphaPixelData
1342 pixData(bmpSource, wxPoint(0, 0), wxSize(m_width, m_height));
2fc9c1ea
KO
1343 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1344
1345 wxAlphaPixelData::Iterator p(pixData);
95c0502b 1346 for (int y=0; y<m_height; y++)
2fc9c1ea
KO
1347 {
1348 wxAlphaPixelData::Iterator rowStart = p;
5f606e65 1349 wxUint32* const rowStartDst = data;
95c0502b 1350 for (int x=0; x<m_width; x++)
2fc9c1ea
KO
1351 {
1352 // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
1353 // with alpha in the upper 8 bits, then red, then green, then
1354 // blue. The 32-bit quantities are stored native-endian.
1355 // Pre-multiplied alpha is used.
1356 unsigned char alpha = p.Alpha();
1357 if (alpha == 0)
1358 *data = 0;
1359 else
1360 *data = ( alpha << 24
1361 | (p.Red() * alpha/255) << 16
1362 | (p.Green() * alpha/255) << 8
1363 | (p.Blue() * alpha/255) );
1364 ++data;
1365 ++p;
1366 }
5f606e65
VZ
1367
1368 data = rowStartDst + stride / 4;
2fc9c1ea
KO
1369 p = rowStart;
1370 p.OffsetY(pixData, 1);
1371 }
1372 }
1373 else // no alpha
1374 {
95c0502b
VZ
1375 wxNativePixelData
1376 pixData(bmpSource, wxPoint(0, 0), wxSize(m_width, m_height));
2fc9c1ea
KO
1377 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1378
1379 wxNativePixelData::Iterator p(pixData);
95c0502b 1380 for (int y=0; y<m_height; y++)
2fc9c1ea
KO
1381 {
1382 wxNativePixelData::Iterator rowStart = p;
5f606e65 1383 wxUint32* const rowStartDst = data;
95c0502b 1384 for (int x=0; x<m_width; x++)
2fc9c1ea
KO
1385 {
1386 // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
1387 // the upper 8 bits unused. Red, Green, and Blue are stored in
1388 // the remaining 24 bits in that order. The 32-bit quantities
1389 // are stored native-endian.
1390 *data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
1391 ++data;
1392 ++p;
1393 }
5f606e65
VZ
1394
1395 data = rowStartDst + stride / 4;
2fc9c1ea
KO
1396 p = rowStart;
1397 p.OffsetY(pixData, 1);
1398 }
1399 }
9dc44eff 1400#if defined(__WXMSW__) || defined(__WXGTK3__)
75ded4d1
RD
1401 // if there is a mask, set the alpha bytes in the target buffer to
1402 // fully transparent or fully opaque
1403 if (bmpSource.GetMask())
1404 {
1405 wxBitmap bmpMask = bmpSource.GetMaskBitmap();
1406 bufferFormat = CAIRO_FORMAT_ARGB32;
1407 data = (wxUint32*)m_buffer;
95c0502b
VZ
1408 wxNativePixelData
1409 pixData(bmpMask, wxPoint(0, 0), wxSize(m_width, m_height));
1410 wxCHECK_RET( pixData, wxT("Failed to gain raw access to mask data."));
75ded4d1
RD
1411
1412 wxNativePixelData::Iterator p(pixData);
95c0502b 1413 for (int y=0; y<m_height; y++)
75ded4d1
RD
1414 {
1415 wxNativePixelData::Iterator rowStart = p;
5f606e65 1416 wxUint32* const rowStartDst = data;
95c0502b 1417 for (int x=0; x<m_width; x++)
75ded4d1
RD
1418 {
1419 if (p.Red()+p.Green()+p.Blue() == 0)
1420 *data = 0;
1421 else
1422 *data = (wxALPHA_OPAQUE << 24) | (*data & 0x00FFFFFF);
1423 ++data;
1424 ++p;
1425 }
5f606e65
VZ
1426
1427 data = rowStartDst + stride / 4;
75ded4d1
RD
1428 p = rowStart;
1429 p.OffsetY(pixData, 1);
1430 }
1431 }
1432#endif
1433
5f606e65 1434 InitSurface(bufferFormat, stride);
711a4812 1435#endif // wxHAS_RAW_BITMAP
2fc9c1ea
KO
1436}
1437
08b2d55f
VZ
1438#if wxUSE_IMAGE
1439
1440// Helper functions for dealing with alpha pre-multiplication.
1441namespace
1442{
1443
1444inline unsigned char Premultiply(unsigned char alpha, unsigned char data)
1445{
1446 return alpha ? (data * alpha)/0xff : data;
1447}
1448
1449inline unsigned char Unpremultiply(unsigned char alpha, unsigned char data)
1450{
1451 return alpha ? (data * 0xff)/alpha : data;
1452}
1453
1454} // anonymous namespace
1455
1456wxCairoBitmapData::wxCairoBitmapData(wxGraphicsRenderer* renderer,
1457 const wxImage& image)
8b180bde 1458 : wxGraphicsBitmapData(renderer)
08b2d55f
VZ
1459{
1460 const cairo_format_t bufferFormat = image.HasAlpha()
1461 ? CAIRO_FORMAT_ARGB32
1462 : CAIRO_FORMAT_RGB24;
1463
0a470e5e 1464 int stride = InitBuffer(image.GetWidth(), image.GetHeight(), bufferFormat);
08b2d55f
VZ
1465
1466 // Copy wxImage data into the buffer. Notice that we work with wxUint32
1467 // values and not bytes becase Cairo always works with buffers in native
1468 // endianness.
1469 wxUint32* dst = reinterpret_cast<wxUint32*>(m_buffer);
1470 const unsigned char* src = image.GetData();
1471
1472 if ( bufferFormat == CAIRO_FORMAT_ARGB32 )
1473 {
1474 const unsigned char* alpha = image.GetAlpha();
1475
1476 for ( int y = 0; y < m_height; y++ )
1477 {
0a470e5e
VZ
1478 wxUint32* const rowStartDst = dst;
1479
08b2d55f
VZ
1480 for ( int x = 0; x < m_width; x++ )
1481 {
1482 const unsigned char a = *alpha++;
1483
1484 *dst++ = a << 24 |
1485 Premultiply(a, src[0]) << 16 |
1486 Premultiply(a, src[1]) << 8 |
1487 Premultiply(a, src[2]);
1488 src += 3;
1489 }
0a470e5e
VZ
1490
1491 dst = rowStartDst + stride / 4;
08b2d55f
VZ
1492 }
1493 }
1494 else // RGB
1495 {
1496 for ( int y = 0; y < m_height; y++ )
1497 {
0a470e5e
VZ
1498 wxUint32* const rowStartDst = dst;
1499
08b2d55f
VZ
1500 for ( int x = 0; x < m_width; x++ )
1501 {
1502 *dst++ = src[0] << 16 |
1503 src[1] << 8 |
1504 src[2];
1505 src += 3;
1506 }
0a470e5e
VZ
1507
1508 dst = rowStartDst + stride / 4;
08b2d55f
VZ
1509 }
1510 }
1511
0a470e5e 1512 InitSurface(bufferFormat, stride);
08b2d55f
VZ
1513}
1514
1515wxImage wxCairoBitmapData::ConvertToImage() const
1516{
1517 wxImage image(m_width, m_height, false /* don't clear */);
1518
1519 // Get the surface type and format.
1520 wxCHECK_MSG( cairo_surface_get_type(m_surface) == CAIRO_SURFACE_TYPE_IMAGE,
1521 wxNullImage,
1522 wxS("Can't convert non-image surface to image.") );
1523
1524 switch ( cairo_image_surface_get_format(m_surface) )
1525 {
1526 case CAIRO_FORMAT_ARGB32:
1527 image.SetAlpha();
1528 break;
1529
1530 case CAIRO_FORMAT_RGB24:
1531 // Nothing to do, we don't use alpha by default.
1532 break;
1533
1534 case CAIRO_FORMAT_A8:
1535 case CAIRO_FORMAT_A1:
1536 wxFAIL_MSG(wxS("Unsupported Cairo image surface type."));
1537 return wxNullImage;
1538
1539 default:
1540 wxFAIL_MSG(wxS("Unknown Cairo image surface type."));
1541 return wxNullImage;
1542 }
1543
1544 // Prepare for copying data.
1545 const wxUint32* src = (wxUint32*)cairo_image_surface_get_data(m_surface);
1546 wxCHECK_MSG( src, wxNullImage, wxS("Failed to get Cairo surface data.") );
1547
1548 int stride = cairo_image_surface_get_stride(m_surface);
1549 wxCHECK_MSG( stride > 0, wxNullImage,
1550 wxS("Failed to get Cairo surface stride.") );
1551
1552 // As we work with wxUint32 pointers and not char ones, we need to adjust
1553 // the stride accordingly. This should be lossless as the stride must be a
1554 // multiple of pixel size.
1555 wxASSERT_MSG( !(stride % sizeof(wxUint32)), wxS("Unexpected stride.") );
1556 stride /= sizeof(wxUint32);
1557
1558 unsigned char* dst = image.GetData();
1559 unsigned char *alpha = image.GetAlpha();
1560 if ( alpha )
1561 {
1562 // We need to also copy alpha and undo the pre-multiplication as Cairo
1563 // stores pre-multiplied values in this format while wxImage does not.
1564 for ( int y = 0; y < m_height; y++ )
1565 {
1566 const wxUint32* const rowStart = src;
1567 for ( int x = 0; x < m_width; x++ )
1568 {
1569 const wxUint32 argb = *src++;
1570
1571 *alpha++ = (argb & 0xff000000) >> 24;
1572
1573 // Copy the RGB data undoing the pre-multiplication.
1574 *dst++ = Unpremultiply(*alpha, (argb & 0x00ff0000) >> 16);
1575 *dst++ = Unpremultiply(*alpha, (argb & 0x0000ff00) >> 8);
1576 *dst++ = Unpremultiply(*alpha, (argb & 0x000000ff));
1577 }
1578
1579 src = rowStart + stride;
1580 }
1581 }
1582 else // RGB
1583 {
1584 // Things are pretty simple in this case, just copy RGB bytes.
1585 for ( int y = 0; y < m_height; y++ )
1586 {
1587 const wxUint32* const rowStart = src;
1588 for ( int x = 0; x < m_width; x++ )
1589 {
1590 const wxUint32 argb = *src++;
1591
1592 *dst++ = (argb & 0x00ff0000) >> 16;
1593 *dst++ = (argb & 0x0000ff00) >> 8;
1594 *dst++ = (argb & 0x000000ff);
1595 }
1596
1597 src = rowStart + stride;
1598 }
1599 }
1600
1601 return image;
1602}
1603
1604#endif // wxUSE_IMAGE
1605
2fc9c1ea
KO
1606wxCairoBitmapData::~wxCairoBitmapData()
1607{
66f917a7
KO
1608 if (m_pattern)
1609 cairo_pattern_destroy(m_pattern);
4ee4c7b9 1610
66f917a7
KO
1611 if (m_surface)
1612 cairo_surface_destroy(m_surface);
4ee4c7b9 1613
2fc9c1ea
KO
1614 delete [] m_buffer;
1615}
1616
00bd8e72
SC
1617//-----------------------------------------------------------------------------
1618// wxCairoContext implementation
1619//-----------------------------------------------------------------------------
1620
e7f9f819
SC
1621class wxCairoOffsetHelper
1622{
1623public :
1624 wxCairoOffsetHelper( cairo_t* ctx , bool offset )
1625 {
1626 m_ctx = ctx;
1627 m_offset = offset;
1628 if ( m_offset )
1629 cairo_translate( m_ctx, 0.5, 0.5 );
1630 }
1631 ~wxCairoOffsetHelper( )
1632 {
1633 if ( m_offset )
1634 cairo_translate( m_ctx, -0.5, -0.5 );
1635 }
1636public :
1637 cairo_t* m_ctx;
1638 bool m_offset;
1639} ;
1640
c9008abe
RR
1641wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc )
1642: wxGraphicsContext(renderer)
1643{
932d0768
RD
1644#ifdef __WXMSW__
1645 // wxMSW contexts always use MM_ANISOTROPIC, which messes up
1646 // text rendering when printing using Cairo. Switch it to MM_TEXT
1647 // map mode to avoid this problem.
1648 HDC hdc = (HDC)dc.GetHDC();
1649 ::SetMapMode(hdc, MM_TEXT);
1650 m_mswSurface = cairo_win32_printing_surface_create(hdc);
1651 Init( cairo_create(m_mswSurface) );
1652#endif
1653
c9008abe
RR
1654#ifdef __WXGTK20__
1655 const wxDCImpl *impl = dc.GetImpl();
1656 Init( (cairo_t*) impl->GetCairoContext() );
932d0768 1657#endif
b129eaa3
VZ
1658 wxSize sz = dc.GetSize();
1659 m_width = sz.x;
1660 m_height = sz.y;
1661
c9008abe 1662 wxPoint org = dc.GetDeviceOrigin();
eaeb9985 1663 cairo_translate( m_context, org.x, org.y );
49ad157e 1664
c9008abe
RR
1665 double sx,sy;
1666 dc.GetUserScale( &sx, &sy );
932d0768
RD
1667
1668// TODO: Determine if these fixes are needed on other platforms too.
1669// On MSW, without this the printer context will not respect wxDC SetMapMode calls.
1670// For example, using dc.SetMapMode(wxMM_POINTS) can let us share printer and screen
1671// drawing code
1672#ifdef __WXMSW__
1673 double lsx,lsy;
1674 dc.GetLogicalScale( &lsx, &lsy );
1675 sx *= lsx;
1676 sy *= lsy;
1677#endif
eaeb9985 1678 cairo_scale( m_context, sx, sy );
c9008abe 1679
eaeb9985
RR
1680 org = dc.GetLogicalOrigin();
1681 cairo_translate( m_context, -org.x, -org.y );
c9008abe
RR
1682}
1683
00bd8e72
SC
1684wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc )
1685: wxGraphicsContext(renderer)
1686{
b129eaa3
VZ
1687 int width, height;
1688 dc.GetSize( &width, &height );
1689 m_width = width;
1690 m_height = height;
1691
136a1de9
SC
1692 m_enableOffset = true;
1693
932d0768
RD
1694#ifdef __WXMSW__
1695 m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC());
1696 Init( cairo_create(m_mswSurface) );
1697#endif
1698
9dc44eff
PC
1699#ifdef __WXGTK3__
1700 cairo_t* cr = static_cast<cairo_t*>(dc.GetImpl()->GetCairoContext());
1701 if (cr)
1702 Init(cr);
1703#elif defined __WXGTK20__
888dde65 1704 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
64a226f7 1705 Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
49ad157e
VZ
1706
1707#if 0
c9008abe 1708 wxGraphicsMatrix matrix = CreateMatrix();
49ad157e 1709
c9008abe
RR
1710 wxPoint org = dc.GetDeviceOrigin();
1711 matrix.Translate( org.x, org.y );
49ad157e 1712
c9008abe
RR
1713 org = dc.GetLogicalOrigin();
1714 matrix.Translate( -org.x, -org.y );
1715
1716 double sx,sy;
1717 dc.GetUserScale( &sx, &sy );
1718 matrix.Scale( sx, sy );
1719
1720 ConcatTransform( matrix );
1721#endif
e7f9f819 1722#endif
c9008abe 1723
888dde65 1724#ifdef __WXMAC__
888dde65
RR
1725 CGContextRef cgcontext = (CGContextRef)dc.GetWindow()->MacGetCGContextRef();
1726 cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(cgcontext, width, height);
1727 Init( cairo_create( surface ) );
1728 cairo_surface_destroy( surface );
1729#endif
1730}
1731
1732wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc )
1733: wxGraphicsContext(renderer)
1734{
b129eaa3
VZ
1735 int width, height;
1736 dc.GetSize( &width, &height );
1737 m_width = width;
1738 m_height = height;
1739
136a1de9 1740 m_enableOffset = true;
932d0768
RD
1741
1742#ifdef __WXMSW__
caf1a3aa
RD
1743
1744 HDC hdc = (HDC)dc.GetHDC();
1745
1746 HBITMAP bitmap = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
1747
1748 BITMAP info;
1749 bool hasBitmap = false;
1750
1751 // cairo_win32_surface_create creates a 24-bit bitmap,
1752 // so if we have alpha, we need to create a 32-bit surface instead.
1753 if (!GetObject(bitmap, sizeof(info), &info) || info.bmBitsPixel < 32)
1754 m_mswSurface = cairo_win32_surface_create(hdc);
1755 else {
1756 hasBitmap = true;
1757 m_mswSurface = cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
1758 CAIRO_FORMAT_ARGB32,
1759 info.bmWidth,
1760 info.bmHeight,
1761 info.bmWidthBytes);
1762 }
1763
932d0768 1764 Init( cairo_create(m_mswSurface) );
caf1a3aa
RD
1765 // If we've created a image surface, we need to flip the Y axis so that
1766 // all drawing will appear right side up.
1767 if (hasBitmap) {
1768 cairo_matrix_t matrix;
1769 cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, height);
1770 cairo_set_matrix(m_context, &matrix);
1771 }
932d0768 1772#endif
136a1de9 1773
9dc44eff
PC
1774#ifdef __WXGTK3__
1775 cairo_t* cr = static_cast<cairo_t*>(dc.GetImpl()->GetCairoContext());
1776 if (cr)
1777 Init(cr);
1778#elif defined __WXGTK20__
888dde65
RR
1779 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
1780 Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
49ad157e
VZ
1781
1782#if 0
c9008abe 1783 wxGraphicsMatrix matrix = CreateMatrix();
49ad157e 1784
c9008abe
RR
1785 wxPoint org = dc.GetDeviceOrigin();
1786 matrix.Translate( org.x, org.y );
49ad157e 1787
c9008abe
RR
1788 org = dc.GetLogicalOrigin();
1789 matrix.Translate( -org.x, -org.y );
1790
1791 double sx,sy;
1792 dc.GetUserScale( &sx, &sy );
1793 matrix.Scale( sx, sy );
1794
1795 ConcatTransform( matrix );
64a226f7 1796#endif
c9008abe
RR
1797#endif
1798
e7f9f819 1799#ifdef __WXMAC__
e7f9f819
SC
1800 CGContextRef cgcontext = (CGContextRef)dc.GetWindow()->MacGetCGContextRef();
1801 cairo_surface_t* surface = cairo_quartz_surface_create_for_cg_context(cgcontext, width, height);
1802 Init( cairo_create( surface ) );
1803 cairo_surface_destroy( surface );
00bd8e72 1804#endif
00bd8e72
SC
1805}
1806
c9008abe 1807#ifdef __WXGTK20__
9dc44eff 1808wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkWindow *window )
00bd8e72
SC
1809: wxGraphicsContext(renderer)
1810{
9dc44eff 1811 Init( gdk_cairo_create( window ) );
b129eaa3 1812
9dc44eff
PC
1813#ifdef __WXGTK3__
1814 m_width = gdk_window_get_width(window);
1815 m_height = gdk_window_get_height(window);
1816#else
b129eaa3 1817 int width, height;
9dc44eff 1818 gdk_drawable_get_size(window, &width, &height);
b129eaa3
VZ
1819 m_width = width;
1820 m_height = height;
9dc44eff 1821#endif
00bd8e72
SC
1822}
1823#endif
1824
c0e69d72
KO
1825#ifdef __WXMSW__
1826wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, HDC handle )
1827: wxGraphicsContext(renderer)
1828{
1829 m_mswSurface = cairo_win32_surface_create(handle);
b129eaa3
VZ
1830 Init( cairo_create(m_mswSurface) );
1831 m_width =
1832 m_height = 0;
c0e69d72
KO
1833}
1834#endif
1835
1836
00bd8e72
SC
1837wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context )
1838: wxGraphicsContext(renderer)
1839{
e7f9f819 1840 Init( context );
b129eaa3
VZ
1841 m_width =
1842 m_height = 0;
184fc6c8
SC
1843}
1844
00bd8e72 1845wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window)
365d11be
VZ
1846 : wxGraphicsContext(renderer)
1847#ifdef __WXMSW__
1848 , m_mswWindowHDC(GetHwndOf(window))
1849#endif
184fc6c8 1850{
136a1de9 1851 m_enableOffset = true;
00bd8e72
SC
1852#ifdef __WXGTK__
1853 // something along these lines (copied from dcclient)
1854
00bd8e72
SC
1855 // Some controls don't have m_wxwindow - like wxStaticBox, but the user
1856 // code should still be able to create wxClientDCs for them, so we will
1857 // use the parent window here then.
82a234fb 1858 if (window->m_wxwindow == NULL)
184fc6c8 1859 {
00bd8e72 1860 window = window->GetParent();
184fc6c8 1861 }
00bd8e72 1862
82a234fb 1863 wxASSERT_MSG( window->m_wxwindow, wxT("wxCairoContext needs a widget") );
00bd8e72 1864
82a234fb 1865 Init(gdk_cairo_create(window->GTKGetDrawingWindow()));
b129eaa3
VZ
1866
1867 wxSize sz = window->GetSize();
1868 m_width = sz.x;
1869 m_height = sz.y;
00bd8e72 1870#endif
9f2b6b31
RD
1871
1872#ifdef __WXMSW__
365d11be 1873 m_mswSurface = cairo_win32_surface_create((HDC)m_mswWindowHDC);
9f2b6b31
RD
1874 Init(cairo_create(m_mswSurface));
1875#endif
1876
00bd8e72
SC
1877}
1878
79313208
VZ
1879wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer) :
1880 wxGraphicsContext(renderer)
1881{
1882 m_context = NULL;
1883}
1884
00bd8e72
SC
1885wxCairoContext::~wxCairoContext()
1886{
00bd8e72
SC
1887 if ( m_context )
1888 {
1889 PopState();
1890 PopState();
1891 cairo_destroy(m_context);
1892 }
c0e69d72
KO
1893#ifdef __WXMSW__
1894 if ( m_mswSurface )
1895 cairo_surface_destroy(m_mswSurface);
1896#endif
00bd8e72
SC
1897}
1898
e7f9f819
SC
1899void wxCairoContext::Init(cairo_t *context)
1900{
1901 m_context = context ;
1902 PushState();
1903 PushState();
1904}
1905
00bd8e72 1906
d9485f89 1907void wxCairoContext::Clip( const wxRegion& region )
00bd8e72 1908{
d9485f89
RD
1909 // Create a path with all the rectangles in the region
1910 wxGraphicsPath path = GetRenderer()->CreatePath();
1911 wxRegionIterator ri(region);
1912 while (ri)
1913 {
1914 path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH());
82a234fb 1915 ++ri;
d9485f89 1916 }
49ad157e 1917
d9485f89
RD
1918 // Put it in the context
1919 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
1920 cairo_append_path(m_context, cp);
1921
1922 // clip to that path
1923 cairo_clip(m_context);
49ad157e 1924 path.UnGetNativePath(cp);
00bd8e72
SC
1925}
1926
1927void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1928{
d9485f89
RD
1929 // Create a path with this rectangle
1930 wxGraphicsPath path = GetRenderer()->CreatePath();
1931 path.AddRectangle(x,y,w,h);
1932
1933 // Put it in the context
1934 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
1935 cairo_append_path(m_context, cp);
1936
1937 // clip to that path
71696da0 1938 cairo_clip(m_context);
49ad157e 1939 path.UnGetNativePath(cp);
00bd8e72
SC
1940}
1941
1942void wxCairoContext::ResetClip()
1943{
d9485f89 1944 cairo_reset_clip(m_context);
00bd8e72
SC
1945}
1946
1947
0db8a70e 1948void wxCairoContext::StrokePath( const wxGraphicsPath& path )
00bd8e72 1949{
87752530 1950 if ( !m_pen.IsNull() )
49ad157e
VZ
1951 {
1952 wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
0db8a70e 1953 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
00bd8e72 1954 cairo_append_path(m_context,cp);
87752530 1955 ((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
00bd8e72 1956 cairo_stroke(m_context);
0db8a70e 1957 path.UnGetNativePath(cp);
00bd8e72
SC
1958 }
1959}
1960
94a007ec 1961void wxCairoContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
00bd8e72 1962{
87752530 1963 if ( !m_brush.IsNull() )
00bd8e72 1964 {
e7f9f819 1965 wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
0db8a70e 1966 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
00bd8e72 1967 cairo_append_path(m_context,cp);
87752530 1968 ((wxCairoBrushData*)m_brush.GetRefData())->Apply(this);
00bd8e72
SC
1969 cairo_set_fill_rule(m_context,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
1970 cairo_fill(m_context);
0db8a70e 1971 path.UnGetNativePath(cp);
00bd8e72
SC
1972 }
1973}
1974
1975void wxCairoContext::Rotate( wxDouble angle )
1976{
1977 cairo_rotate(m_context,angle);
1978}
1979
1980void wxCairoContext::Translate( wxDouble dx , wxDouble dy )
1981{
1982 cairo_translate(m_context,dx,dy);
1983}
1984
1985void wxCairoContext::Scale( wxDouble xScale , wxDouble yScale )
1986{
1987 cairo_scale(m_context,xScale,yScale);
1988}
1989
1990// concatenates this transform with the current transform of this context
0db8a70e 1991void wxCairoContext::ConcatTransform( const wxGraphicsMatrix& matrix )
00bd8e72 1992{
0db8a70e 1993 cairo_transform(m_context,(const cairo_matrix_t *) matrix.GetNativeMatrix());
00bd8e72
SC
1994}
1995
1996// sets the transform of this context
0db8a70e 1997void wxCairoContext::SetTransform( const wxGraphicsMatrix& matrix )
00bd8e72 1998{
0db8a70e 1999 cairo_set_matrix(m_context,(const cairo_matrix_t*) matrix.GetNativeMatrix());
00bd8e72
SC
2000}
2001
2002// gets the matrix of this context
0db8a70e 2003wxGraphicsMatrix wxCairoContext::GetTransform() const
00bd8e72 2004{
0db8a70e
RD
2005 wxGraphicsMatrix matrix = CreateMatrix();
2006 cairo_get_matrix(m_context,(cairo_matrix_t*) matrix.GetNativeMatrix());
2007 return matrix;
00bd8e72
SC
2008}
2009
2010
2011
2012void wxCairoContext::PushState()
2013{
2014 cairo_save(m_context);
2015}
2016
2017void wxCairoContext::PopState()
2018{
2019 cairo_restore(m_context);
2020}
184fc6c8
SC
2021
2022void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2023{
2fc9c1ea 2024 wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
3c10f6db 2025 DrawBitmap(bitmap, x, y, w, h);
d9485f89 2026
2fc9c1ea 2027}
49ad157e 2028
2fc9c1ea
KO
2029void wxCairoContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2030{
d9485f89 2031 PushState();
49ad157e 2032
d9485f89
RD
2033 // In case we're scaling the image by using a width and height different
2034 // than the bitmap's size create a pattern transformation on the surface and
2035 // draw the transformed pattern.
2fc9c1ea
KO
2036 wxCairoBitmapData* data = static_cast<wxCairoBitmapData*>(bmp.GetRefData());
2037 cairo_pattern_t* pattern = data->GetCairoPattern();
2038 wxSize size = data->GetSize();
2039
2040 wxDouble scaleX = w / size.GetWidth();
2041 wxDouble scaleY = h / size.GetHeight();
d9485f89
RD
2042
2043 // prepare to draw the image
2044 cairo_translate(m_context, x, y);
ce6b1014 2045 cairo_scale(m_context, scaleX, scaleY);
d9485f89
RD
2046 cairo_set_source(m_context, pattern);
2047 // use the original size here since the context is scaled already...
2fc9c1ea 2048 cairo_rectangle(m_context, 0, 0, size.GetWidth(), size.GetHeight());
d9485f89
RD
2049 // fill the rectangle using the pattern
2050 cairo_fill(m_context);
2051
d9485f89 2052 PopState();
184fc6c8
SC
2053}
2054
2055void wxCairoContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2056{
d9485f89
RD
2057 // An icon is a bitmap on wxGTK, so do this the easy way. When we want to
2058 // start using the Cairo backend on other platforms then we may need to
2059 // fiddle with this...
2060 DrawBitmap(icon, x, y, w, h);
184fc6c8
SC
2061}
2062
2063
0b7dce54 2064void wxCairoContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
184fc6c8 2065{
0b7dce54
VZ
2066 wxCHECK_RET( !m_font.IsNull(),
2067 wxT("wxCairoContext::DrawText - no valid font set") );
1011fbeb
SC
2068
2069 if ( str.empty())
d9485f89 2070 return;
84f67b11 2071
10c508ef 2072 const wxCharBuffer data = str.utf8_str();
e7f9f819
SC
2073 if ( !data )
2074 return;
0b7dce54 2075
fa378d36
VZ
2076 if ( ((wxCairoFontData*)m_font.GetRefData())->Apply(this) )
2077 {
0b7dce54 2078#ifdef __WXGTK__
fa378d36 2079 PangoLayout *layout = pango_cairo_create_layout (m_context);
304c3065
PC
2080 const wxFont& font = static_cast<wxCairoFontData*>(m_font.GetRefData())->GetFont();
2081 pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description);
2082 pango_layout_set_text(layout, data, data.length());
2083 font.GTKSetPangoAttrs(layout);
0d19936d 2084
fa378d36
VZ
2085 cairo_move_to(m_context, x, y);
2086 pango_cairo_show_layout (m_context, layout);
2087
2088 g_object_unref (layout);
2089
2090 // Don't use Cairo text API, we already did everything.
2091 return;
2092#endif
2093 }
e7f9f819 2094
d9485f89
RD
2095 // Cairo's x,y for drawing text is at the baseline, so we need to adjust
2096 // the position we move to by the ascent.
2097 cairo_font_extents_t fe;
2098 cairo_font_extents(m_context, &fe);
2099 cairo_move_to(m_context, x, y+fe.ascent);
49ad157e 2100
0b7dce54 2101 cairo_show_text(m_context, data);
184fc6c8
SC
2102}
2103
2104void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
2105 wxDouble *descent, wxDouble *externalLeading ) const
2106{
1011fbeb
SC
2107 wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetTextExtent - no valid font set") );
2108
e7f9f819
SC
2109 if ( width )
2110 *width = 0;
2111 if ( height )
2112 *height = 0;
2113 if ( descent )
2114 *descent = 0;
2115 if ( externalLeading )
2116 *externalLeading = 0;
2117
1011fbeb 2118 if ( str.empty())
d9485f89
RD
2119 return;
2120
fa378d36
VZ
2121 if ( ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this) )
2122 {
e7f9f819 2123#ifdef __WXGTK__
fa378d36 2124 int w, h;
49ad157e 2125
fa378d36 2126 PangoLayout *layout = pango_cairo_create_layout (m_context);
304c3065
PC
2127 const wxFont& font = static_cast<wxCairoFontData*>(m_font.GetRefData())->GetFont();
2128 pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description);
fa378d36
VZ
2129 const wxCharBuffer data = str.utf8_str();
2130 if ( !data )
2131 {
2132 return;
2133 }
304c3065 2134 pango_layout_set_text(layout, data, data.length());
fa378d36
VZ
2135 pango_layout_get_pixel_size (layout, &w, &h);
2136 if ( width )
2137 *width = w;
2138 if ( height )
2139 *height = h;
2140 if (descent)
2141 {
2142 PangoLayoutIter *iter = pango_layout_get_iter(layout);
2143 int baseline = pango_layout_iter_get_baseline(iter);
2144 pango_layout_iter_free(iter);
2145 *descent = h - PANGO_PIXELS(baseline);
2146 }
2147 g_object_unref (layout);
e7f9f819 2148 return;
fa378d36 2149#endif
e7f9f819 2150 }
d9485f89
RD
2151
2152 if (width)
2153 {
2154 const wxWX2MBbuf buf(str.mb_str(wxConvUTF8));
2155 cairo_text_extents_t te;
2156 cairo_text_extents(m_context, buf, &te);
2157 *width = te.width;
2158 }
2159
2160 if (height || descent || externalLeading)
2161 {
2162 cairo_font_extents_t fe;
2163 cairo_font_extents(m_context, &fe);
49ad157e 2164
3e700936 2165 // some backends have negative descents
49ad157e 2166
3e700936
SC
2167 if ( fe.descent < 0 )
2168 fe.descent = -fe.descent;
49ad157e 2169
3e700936
SC
2170 if ( fe.height < (fe.ascent + fe.descent ) )
2171 {
2172 // some backends are broken re height ... (eg currently ATSUI)
2173 fe.height = fe.ascent + fe.descent;
2174 }
49ad157e 2175
d9485f89
RD
2176 if (height)
2177 *height = fe.height;
2178 if ( descent )
2179 *descent = fe.descent;
2180 if ( externalLeading )
2181 *externalLeading = wxMax(0, fe.height - (fe.ascent + fe.descent));
2182 }
184fc6c8
SC
2183}
2184
2185void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
2186{
2187 widths.Empty();
1011fbeb 2188 wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetPartialTextExtents - no valid font set") );
4c6fdc35 2189#ifdef __WXGTK__
6186cb74
PC
2190 const wxCharBuffer data = text.utf8_str();
2191 int w = 0;
2192 if (data.length())
2193 {
2194 PangoLayout* layout = pango_cairo_create_layout(m_context);
2195 const wxFont& font = static_cast<wxCairoFontData*>(m_font.GetRefData())->GetFont();
2196 pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description);
2197 pango_layout_set_text(layout, data, data.length());
2198 PangoLayoutIter* iter = pango_layout_get_iter(layout);
2199 PangoRectangle rect;
2200 do {
2201 pango_layout_iter_get_cluster_extents(iter, NULL, &rect);
2202 w += rect.width;
2203 widths.Add(PANGO_PIXELS(w));
2204 } while (pango_layout_iter_next_cluster(iter));
2205 pango_layout_iter_free(iter);
2206 g_object_unref(layout);
2207 }
2208 size_t i = widths.GetCount();
2209 const size_t len = text.length();
2210 while (i++ < len)
2211 widths.Add(PANGO_PIXELS(w));
2212#else
00bd8e72 2213 // TODO
6186cb74 2214#endif
184fc6c8
SC
2215}
2216
49ad157e 2217void * wxCairoContext::GetNativeContext()
184fc6c8 2218{
00bd8e72
SC
2219 return m_context;
2220}
184fc6c8 2221
bf02a7f9 2222bool wxCairoContext::SetAntialiasMode(wxAntialiasMode antialias)
49ad157e 2223{
bf02a7f9 2224 if (m_antialias == antialias)
49ad157e
VZ
2225 return true;
2226
bf02a7f9 2227 m_antialias = antialias;
03647350 2228
bf02a7f9
SC
2229 cairo_antialias_t antialiasMode;
2230 switch (antialias)
2231 {
2232 case wxANTIALIAS_DEFAULT:
2233 antialiasMode = CAIRO_ANTIALIAS_DEFAULT;
2234 break;
2235 case wxANTIALIAS_NONE:
2236 antialiasMode = CAIRO_ANTIALIAS_NONE;
2237 break;
2238 default:
2239 return false;
2240 }
2241 cairo_set_antialias(m_context, antialiasMode);
2242 return true;
2243}
49ad157e 2244
133cb28b
SC
2245bool wxCairoContext::SetInterpolationQuality(wxInterpolationQuality WXUNUSED(interpolation))
2246{
2247 // placeholder
2248 return false;
2249}
2250
bf02a7f9
SC
2251bool wxCairoContext::SetCompositionMode(wxCompositionMode op)
2252{
2253 if ( m_composition == op )
2254 return true;
03647350 2255
bf02a7f9
SC
2256 m_composition = op;
2257 cairo_operator_t cop;
2258 switch (op)
49ad157e 2259 {
50de831a 2260 case wxCOMPOSITION_CLEAR:
bf02a7f9 2261 cop = CAIRO_OPERATOR_CLEAR;
49ad157e 2262 break;
bf02a7f9
SC
2263 case wxCOMPOSITION_SOURCE:
2264 cop = CAIRO_OPERATOR_SOURCE;
49ad157e 2265 break;
bf02a7f9
SC
2266 case wxCOMPOSITION_OVER:
2267 cop = CAIRO_OPERATOR_OVER;
49ad157e 2268 break;
bf02a7f9
SC
2269 case wxCOMPOSITION_IN:
2270 cop = CAIRO_OPERATOR_IN;
2271 break;
2272 case wxCOMPOSITION_OUT:
2273 cop = CAIRO_OPERATOR_OUT;
2274 break;
2275 case wxCOMPOSITION_ATOP:
2276 cop = CAIRO_OPERATOR_ATOP;
2277 break;
2278 case wxCOMPOSITION_DEST:
2279 cop = CAIRO_OPERATOR_DEST;
2280 break;
2281 case wxCOMPOSITION_DEST_OVER:
2282 cop = CAIRO_OPERATOR_DEST_OVER;
2283 break;
2284 case wxCOMPOSITION_DEST_IN:
2285 cop = CAIRO_OPERATOR_DEST_IN;
2286 break;
2287 case wxCOMPOSITION_DEST_OUT:
2288 cop = CAIRO_OPERATOR_DEST_OUT;
2289 break;
2290 case wxCOMPOSITION_DEST_ATOP:
2291 cop = CAIRO_OPERATOR_DEST_ATOP;
2292 break;
2293 case wxCOMPOSITION_XOR:
2294 cop = CAIRO_OPERATOR_XOR;
2295 break;
2296 case wxCOMPOSITION_ADD:
2297 cop = CAIRO_OPERATOR_ADD;
49ad157e 2298 break;
49ad157e
VZ
2299 default:
2300 return false;
2301 }
bf02a7f9 2302 cairo_set_operator(m_context, cop);
49ad157e
VZ
2303 return true;
2304}
2305
bf02a7f9
SC
2306void wxCairoContext::BeginLayer(wxDouble opacity)
2307{
2308 m_layerOpacities.push_back(opacity);
2309 cairo_push_group(m_context);
2310}
49ad157e 2311
bf02a7f9
SC
2312void wxCairoContext::EndLayer()
2313{
2314 float opacity = m_layerOpacities.back();
2315 m_layerOpacities.pop_back();
2316 cairo_pop_group_to_source(m_context);
2317 cairo_paint_with_alpha(m_context,opacity);
2318}
03647350 2319
00bd8e72
SC
2320//-----------------------------------------------------------------------------
2321// wxCairoRenderer declaration
2322//-----------------------------------------------------------------------------
2323
2324class WXDLLIMPEXP_CORE wxCairoRenderer : public wxGraphicsRenderer
2325{
2326public :
2327 wxCairoRenderer() {}
2328
2329 virtual ~wxCairoRenderer() {}
2330
2331 // Context
2332
2333 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
773ccc31 2334 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
0b822969 2335 virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc);
773ccc31 2336
00bd8e72
SC
2337 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
2338
2339 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
0a470e5e
VZ
2340#if wxUSE_IMAGE
2341 virtual wxGraphicsContext * CreateContextFromImage(wxImage& image);
2342#endif // wxUSE_IMAGE
00bd8e72
SC
2343
2344 virtual wxGraphicsContext * CreateContext( wxWindow* window );
2345
091ef146 2346 virtual wxGraphicsContext * CreateMeasuringContext();
9f2b6b31
RD
2347#ifdef __WXMSW__
2348#if wxUSE_ENH_METAFILE
2349 virtual wxGraphicsContext * CreateContext( const wxEnhMetaFileDC& dc);
2350#endif
2351#endif
00bd8e72
SC
2352 // Path
2353
0db8a70e 2354 virtual wxGraphicsPath CreatePath();
00bd8e72
SC
2355
2356 // Matrix
2357
49ad157e 2358 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
00bd8e72
SC
2359 wxDouble tx=0.0, wxDouble ty=0.0);
2360
2361
87752530 2362 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
00bd8e72 2363
87752530 2364 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
00bd8e72 2365
4ee4c7b9
VZ
2366 virtual wxGraphicsBrush
2367 CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
2368 wxDouble x2, wxDouble y2,
2369 const wxGraphicsGradientStops& stops);
00bd8e72 2370
4ee4c7b9
VZ
2371 virtual wxGraphicsBrush
2372 CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
2373 wxDouble xc, wxDouble yc,
2374 wxDouble radius,
2375 const wxGraphicsGradientStops& stops);
00bd8e72
SC
2376
2377 // sets the font
87752530 2378 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
fa378d36
VZ
2379 virtual wxGraphicsFont CreateFont(double sizeInPixels,
2380 const wxString& facename,
2381 int flags = wxFONTFLAG_DEFAULT,
2382 const wxColour& col = *wxBLACK);
00bd8e72 2383
d974a494 2384 // create a native bitmap representation
2fc9c1ea 2385 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
0a470e5e
VZ
2386#if wxUSE_IMAGE
2387 virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image);
6e6f074b 2388 virtual wxImage CreateImageFromBitmap(const wxGraphicsBitmap& bmp);
0a470e5e 2389#endif // wxUSE_IMAGE
49ad157e 2390
2986eb86
SC
2391 // create a graphics bitmap from a native bitmap
2392 virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
2393
d974a494 2394 // create a subimage from a native image representation
2fc9c1ea 2395 virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
d974a494 2396
932d0768
RD
2397protected :
2398 bool EnsureIsLoaded();
2399 void Load();
2400 void Unload();
2401 friend class wxCairoModule;
00bd8e72 2402private :
932d0768 2403 int m_loaded;
00bd8e72
SC
2404 DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer)
2405} ;
2406
2407//-----------------------------------------------------------------------------
2408// wxCairoRenderer implementation
2409//-----------------------------------------------------------------------------
2410
2411IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer,wxGraphicsRenderer)
2412
2413static wxCairoRenderer gs_cairoGraphicsRenderer;
3e700936
SC
2414// temporary hack to allow creating a cairo context on any platform
2415extern wxGraphicsRenderer* gCairoRenderer;
2416wxGraphicsRenderer* gCairoRenderer = &gs_cairoGraphicsRenderer;
00bd8e72 2417
932d0768
RD
2418bool wxCairoRenderer::EnsureIsLoaded()
2419{
2420#ifndef __WXGTK__
2421 Load();
2422 return wxCairoInit();
2423#else
2424 return true;
2425#endif
2426}
2427
2428void wxCairoRenderer::Load()
2429{
2430 wxCairoInit();
2431}
2432
2433void wxCairoRenderer::Unload()
2434{
2435 wxCairoCleanUp();
2436}
2437
2438// call EnsureIsLoaded() and return returnOnFail value if it fails
2439#define ENSURE_LOADED_OR_RETURN(returnOnFail) \
2440 if ( !EnsureIsLoaded() ) \
2441 return (returnOnFail)
2442
00bd8e72 2443wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc)
539e2795 2444{
932d0768 2445 ENSURE_LOADED_OR_RETURN(NULL);
00bd8e72
SC
2446 return new wxCairoContext(this,dc);
2447}
2448
773ccc31
SC
2449wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc)
2450{
932d0768 2451 ENSURE_LOADED_OR_RETURN(NULL);
888dde65 2452 return new wxCairoContext(this,dc);
773ccc31 2453}
773ccc31 2454
0b822969
RR
2455wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc)
2456{
932d0768 2457 ENSURE_LOADED_OR_RETURN(NULL);
0f31a78f 2458 return new wxCairoContext(this, dc);
0b822969
RR
2459}
2460
9f2b6b31
RD
2461#ifdef __WXMSW__
2462#if wxUSE_ENH_METAFILE
932d0768 2463wxGraphicsContext * wxCairoRenderer::CreateContext( const wxEnhMetaFileDC& WXUNUSED(dc) )
9f2b6b31 2464{
932d0768 2465 ENSURE_LOADED_OR_RETURN(NULL);
9f2b6b31
RD
2466 return NULL;
2467}
2468#endif
2469#endif
2470
00bd8e72
SC
2471wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context )
2472{
932d0768 2473 ENSURE_LOADED_OR_RETURN(NULL);
a8f9fe13 2474#ifdef __WXMSW__
c0e69d72 2475 return new wxCairoContext(this,(HDC)context);
711a4812 2476#else
00bd8e72 2477 return new wxCairoContext(this,(cairo_t*)context);
c0e69d72 2478#endif
00bd8e72
SC
2479}
2480
2481
2482wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window )
2483{
932d0768 2484 ENSURE_LOADED_OR_RETURN(NULL);
00bd8e72 2485#ifdef __WXGTK__
9dc44eff 2486 return new wxCairoContext(this, static_cast<GdkWindow*>(window));
00bd8e72 2487#else
932d0768 2488 wxUnusedVar(window);
00bd8e72
SC
2489 return NULL;
2490#endif
2491}
2492
0a470e5e
VZ
2493#if wxUSE_IMAGE
2494wxGraphicsContext * wxCairoRenderer::CreateContextFromImage(wxImage& image)
2495{
2496 return new wxCairoImageContext(this, image);
2497}
2498#endif // wxUSE_IMAGE
2499
091ef146
SC
2500wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext()
2501{
932d0768 2502 ENSURE_LOADED_OR_RETURN(NULL);
5e8d27fe
KO
2503#ifdef __WXGTK__
2504 return CreateContextFromNativeWindow(gdk_get_default_root_window());
ecdfd095 2505#else
091ef146
SC
2506 return NULL;
2507 // TODO
ecdfd095 2508#endif
091ef146
SC
2509}
2510
00bd8e72
SC
2511wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window )
2512{
932d0768 2513 ENSURE_LOADED_OR_RETURN(NULL);
00bd8e72
SC
2514 return new wxCairoContext(this, window );
2515}
2516
2517// Path
2518
0db8a70e 2519wxGraphicsPath wxCairoRenderer::CreatePath()
00bd8e72 2520{
932d0768 2521 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath);
0db8a70e
RD
2522 wxGraphicsPath path;
2523 path.SetRefData( new wxCairoPathData(this) );
2524 return path;
539e2795
SC
2525}
2526
00bd8e72
SC
2527
2528// Matrix
2529
49ad157e 2530wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
0db8a70e 2531 wxDouble tx, wxDouble ty)
00bd8e72 2532
184fc6c8 2533{
932d0768 2534 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix);
0db8a70e
RD
2535 wxGraphicsMatrix m;
2536 wxCairoMatrixData* data = new wxCairoMatrixData( this );
2537 data->Set( a,b,c,d,tx,ty ) ;
2538 m.SetRefData(data);
00bd8e72 2539 return m;
7ba86d93
RD
2540}
2541
49ad157e 2542wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen)
539e2795 2543{
932d0768 2544 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen);
a1b806b9 2545 if ( !pen.IsOk() || pen.GetStyle() == wxPENSTYLE_TRANSPARENT )
87752530 2546 return wxNullGraphicsPen;
00bd8e72 2547 else
87752530
SC
2548 {
2549 wxGraphicsPen p;
2550 p.SetRefData(new wxCairoPenData( this, pen ));
2551 return p;
2552 }
539e2795
SC
2553}
2554
49ad157e 2555wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush )
539e2795 2556{
932d0768 2557 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
a1b806b9 2558 if ( !brush.IsOk() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT )
87752530 2559 return wxNullGraphicsBrush;
00bd8e72 2560 else
87752530
SC
2561 {
2562 wxGraphicsBrush p;
2563 p.SetRefData(new wxCairoBrushData( this, brush ));
2564 return p;
2565 }
00bd8e72
SC
2566}
2567
4ee4c7b9
VZ
2568wxGraphicsBrush
2569wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
2570 wxDouble x2, wxDouble y2,
2571 const wxGraphicsGradientStops& stops)
00bd8e72 2572{
932d0768 2573 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
87752530
SC
2574 wxGraphicsBrush p;
2575 wxCairoBrushData* d = new wxCairoBrushData( this );
4ee4c7b9 2576 d->CreateLinearGradientBrush(x1, y1, x2, y2, stops);
87752530
SC
2577 p.SetRefData(d);
2578 return p;
00bd8e72
SC
2579}
2580
4ee4c7b9
VZ
2581wxGraphicsBrush
2582wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
2583 wxDouble xc, wxDouble yc, wxDouble r,
2584 const wxGraphicsGradientStops& stops)
00bd8e72 2585{
932d0768 2586 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
87752530
SC
2587 wxGraphicsBrush p;
2588 wxCairoBrushData* d = new wxCairoBrushData( this );
4ee4c7b9 2589 d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops);
87752530
SC
2590 p.SetRefData(d);
2591 return p;
00bd8e72
SC
2592}
2593
49ad157e 2594wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col )
00bd8e72 2595{
932d0768 2596 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
a1b806b9 2597 if ( font.IsOk() )
49ad157e 2598 {
87752530
SC
2599 wxGraphicsFont p;
2600 p.SetRefData(new wxCairoFontData( this , font, col ));
2601 return p;
2602 }
00bd8e72 2603 else
87752530 2604 return wxNullGraphicsFont;
539e2795
SC
2605}
2606
fa378d36
VZ
2607wxGraphicsFont
2608wxCairoRenderer::CreateFont(double sizeInPixels,
2609 const wxString& facename,
2610 int flags,
2611 const wxColour& col)
2612{
2613 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
2614
2615 wxGraphicsFont font;
2616 font.SetRefData(new wxCairoFontData(this, sizeInPixels, facename, flags, col));
2617 return font;
2618}
2619
f5008769 2620wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp )
2fc9c1ea 2621{
932d0768 2622 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
a1b806b9 2623 if ( bmp.IsOk() )
2fc9c1ea
KO
2624 {
2625 wxGraphicsBitmap p;
2626 p.SetRefData(new wxCairoBitmapData( this , bmp ));
2627 return p;
2628 }
2629 else
2630 return wxNullGraphicsBitmap;
2631}
2632
0a470e5e
VZ
2633#if wxUSE_IMAGE
2634
2635wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromImage(const wxImage& image)
2636{
2637 wxGraphicsBitmap bmp;
2638
2639 ENSURE_LOADED_OR_RETURN(bmp);
2640
2641 if ( image.IsOk() )
2642 {
2643 bmp.SetRefData(new wxCairoBitmapData(this, image));
2644 }
2645
2646 return bmp;
2647}
2648
6e6f074b
RD
2649wxImage wxCairoRenderer::CreateImageFromBitmap(const wxGraphicsBitmap& bmp)
2650{
2651 ENSURE_LOADED_OR_RETURN(wxNullImage);
2652
2653 const wxCairoBitmapData* const
2654 data = static_cast<wxCairoBitmapData*>(bmp.GetGraphicsData());
2655
2656 return data ? data->ConvertToImage() : wxNullImage;
2657}
2658
0a470e5e
VZ
2659#endif // wxUSE_IMAGE
2660
6e6f074b 2661
2986eb86
SC
2662wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
2663{
932d0768 2664 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
2986eb86
SC
2665 if ( bitmap != NULL )
2666 {
2667 wxGraphicsBitmap p;
2668 p.SetRefData(new wxCairoBitmapData( this , (cairo_surface_t*) bitmap ));
2669 return p;
2670 }
2671 else
2672 return wxNullGraphicsBitmap;
2673}
2674
84e0e526
VZ
2675wxGraphicsBitmap
2676wxCairoRenderer::CreateSubBitmap(const wxGraphicsBitmap& WXUNUSED(bitmap),
2677 wxDouble WXUNUSED(x),
2678 wxDouble WXUNUSED(y),
2679 wxDouble WXUNUSED(w),
2680 wxDouble WXUNUSED(h))
2fc9c1ea 2681{
932d0768 2682 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
2fc9c1ea
KO
2683 wxFAIL_MSG("wxCairoRenderer::CreateSubBitmap is not implemented.");
2684 return wxNullGraphicsBitmap;
2685}
2686
c0e69d72
KO
2687wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()
2688{
c0e69d72 2689 return &gs_cairoGraphicsRenderer;
ef40c54c
VZ
2690}
2691
2692#else // !wxUSE_CAIRO
2693
2694wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()
2695{
c0e69d72 2696 return NULL;
c0e69d72 2697}
9a67941f 2698
ef40c54c
VZ
2699#endif // wxUSE_CAIRO/!wxUSE_CAIRO
2700
2701// MSW and OS X have their own native default renderers, but the other ports
2702// use Cairo by default
2703#if !(defined(__WXMSW__) || defined(__WXOSX__))
2704wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
2705{
2706 return GetCairoRenderer();
2707}
2708#endif // !(__WXMSW__ || __WXOSX__)
2709
9a67941f 2710#endif // wxUSE_GRAPHICS_CONTEXT