]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/graphicc.cpp
new file added
[wxWidgets.git] / src / generic / graphicc.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/graphicc.cpp
3// Purpose: cairo device context class
4// Author: Stefan Csomor
5// Modified by:
6// Created: 2006-10-03
7// RCS-ID: $Id$
8// Copyright: (c) 2006 Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
18#if wxUSE_GRAPHICS_CONTEXT
19
20#include "wx/graphics.h"
21
22#if wxUSE_CAIRO
23
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
28#include "wx/cairo.h"
29
30#ifndef WX_PRECOMP
31 #include "wx/bitmap.h"
32 #include "wx/icon.h"
33 #include "wx/dcclient.h"
34 #include "wx/dcmemory.h"
35 #include "wx/dcprint.h"
36 #include "wx/window.h"
37#endif
38
39#include "wx/private/graphics.h"
40#include "wx/rawbmp.h"
41#include "wx/vector.h"
42
43using namespace std;
44
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>
72#ifdef __WXMSW__
73#include <cairo-win32.h>
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"
78#endif
79
80#ifdef __WXGTK__
81#include <gtk/gtk.h>
82#include "wx/fontutil.h"
83#ifndef __WXGTK3__
84#include "wx/gtk/dc.h"
85#endif
86#endif
87
88#ifdef __WXMAC__
89#include "wx/osx/private.h"
90#include <cairo-quartz.h>
91#include <cairo-atsui.h>
92#endif
93
94class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData
95{
96public :
97 wxCairoPathData(wxGraphicsRenderer* renderer, cairo_t* path = NULL);
98 ~wxCairoPathData();
99
100 virtual wxGraphicsObjectRefData *Clone() const;
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
120 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
121
122 // adds another path
123 virtual void AddPath( const wxGraphicsPathData* path );
124
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
135 // appends a rectangle as a new closed subpath
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
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)
148 virtual void UnGetNativePath(void *p) const;
149
150 // transforms each point of this path by the matrix
151 virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
152
153 // gets the bounding box enclosing all points (possibly including control points)
154 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
155
156 virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxWINDING_RULE) const;
157
158private :
159 cairo_t* m_pathContext;
160};
161
162class WXDLLIMPEXP_CORE wxCairoMatrixData : public wxGraphicsMatrixData
163{
164public :
165 wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix = NULL ) ;
166 virtual ~wxCairoMatrixData() ;
167
168 virtual wxGraphicsObjectRefData *Clone() const ;
169
170 // concatenates the matrix
171 virtual void Concat( const wxGraphicsMatrixData *t );
172
173 // sets the matrix to the respective values
174 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
175 wxDouble tx=0.0, wxDouble ty=0.0);
176
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;
180
181 // makes this the inverse matrix
182 virtual void Invert();
183
184 // returns true if the elements of the transformation matrix are equal ?
185 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
186
187 // return true if this is the identity matrix
188 virtual bool IsIdentity() const;
189
190 //
191 // transformation
192 //
193
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)
201 virtual void Rotate( wxDouble angle );
202
203 //
204 // apply the transforms
205 //
206
207 // applies that matrix to the point
208 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
209
210 // applies the matrix except for translations
211 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
212
213 // returns the native representation
214 virtual void * GetNativeMatrix() const;
215private:
216 cairo_matrix_t m_matrix ;
217} ;
218
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
257{
258public:
259 wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
260 ~wxCairoPenData();
261
262 void Init();
263
264 virtual void Apply( wxGraphicsContext* context );
265 virtual wxDouble GetWidth() { return m_width; }
266
267private :
268 double m_width;
269
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;
276
277 wxDECLARE_NO_COPY_CLASS(wxCairoPenData);
278};
279
280class WXDLLIMPEXP_CORE wxCairoBrushData : public wxCairoPenBrushBaseData
281{
282public:
283 wxCairoBrushData( wxGraphicsRenderer* renderer );
284 wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
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);
292
293protected:
294 virtual void Init();
295
296 // common part of Create{Linear,Radial}GradientBrush()
297 void AddGradientStops(const wxGraphicsGradientStops& stops);
298};
299
300class wxCairoFontData : public wxGraphicsObjectRefData
301{
302public:
303 wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
304 wxCairoFontData(wxGraphicsRenderer* renderer,
305 double sizeInPixels,
306 const wxString& facename,
307 int flags,
308 const wxColour& col);
309 ~wxCairoFontData();
310
311 virtual bool Apply( wxGraphicsContext* context );
312#ifdef __WXGTK__
313 const wxFont& GetFont() const { return m_wxfont; }
314#endif
315private :
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
321 double m_size;
322 double m_red;
323 double m_green;
324 double m_blue;
325 double m_alpha;
326#ifdef __WXMAC__
327 cairo_font_face_t *m_font;
328#elif defined(__WXGTK__)
329 wxFont m_wxfont;
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.
342 wxCharBuffer m_fontName;
343 cairo_font_slant_t m_slant;
344 cairo_font_weight_t m_weight;
345};
346
347class wxCairoBitmapData : public wxGraphicsBitmapData
348{
349public:
350 wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp );
351#if wxUSE_IMAGE
352 wxCairoBitmapData(wxGraphicsRenderer* renderer, const wxImage& image);
353#endif // wxUSE_IMAGE
354 wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap );
355 ~wxCairoBitmapData();
356
357 virtual cairo_surface_t* GetCairoSurface() { return m_surface; }
358 virtual cairo_pattern_t* GetCairoPattern() { return m_pattern; }
359 virtual void* GetNativeBitmap() const { return m_surface; }
360 virtual wxSize GetSize() { return wxSize(m_width, m_height); }
361
362#if wxUSE_IMAGE
363 wxImage ConvertToImage() const;
364#endif // wxUSE_IMAGE
365
366private :
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
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
384class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext
385{
386public:
387 wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc );
388 wxCairoContext( wxGraphicsRenderer* renderer, const wxMemoryDC& dc );
389 wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc );
390#ifdef __WXGTK__
391 wxCairoContext( wxGraphicsRenderer* renderer, GdkWindow *window );
392#endif
393#ifdef __WXMSW__
394 wxCairoContext( wxGraphicsRenderer* renderer, HDC context );
395#endif
396 wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context );
397 wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window);
398
399 // If this ctor is used, Init() must be called by the derived class later.
400 wxCairoContext( wxGraphicsRenderer* renderer );
401
402 virtual ~wxCairoContext();
403
404 virtual bool ShouldOffset() const
405 {
406 if ( !m_enableOffset )
407 return false;
408
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
419 virtual void Clip( const wxRegion &region );
420#ifdef __WXMSW__
421 cairo_surface_t* m_mswSurface;
422 WindowHDC m_mswWindowHDC;
423#endif
424
425 // clips drawings to the rect
426 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
427
428 // resets the clipping to original extent
429 virtual void ResetClip();
430
431 virtual void * GetNativeContext();
432
433 virtual bool SetAntialiasMode(wxAntialiasMode antialias);
434
435 virtual bool SetInterpolationQuality(wxInterpolationQuality interpolation);
436
437 virtual bool SetCompositionMode(wxCompositionMode op);
438
439 virtual void BeginLayer(wxDouble opacity);
440
441 virtual void EndLayer();
442
443 virtual void StrokePath( const wxGraphicsPath& p );
444 virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxWINDING_RULE );
445
446 virtual void Translate( wxDouble dx , wxDouble dy );
447 virtual void Scale( wxDouble xScale , wxDouble yScale );
448 virtual void Rotate( wxDouble angle );
449
450 // concatenates this transform with the current transform of this context
451 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
452
453 // sets the transform of this context
454 virtual void SetTransform( const wxGraphicsMatrix& matrix );
455
456 // gets the matrix of this context
457 virtual wxGraphicsMatrix GetTransform() const;
458
459 virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
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
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
469protected:
470 virtual void DoDrawText( const wxString &str, wxDouble x, wxDouble y );
471
472 void Init(cairo_t *context);
473
474private:
475 cairo_t* m_context;
476
477 wxVector<float> m_layerOpacities;
478
479 wxDECLARE_NO_COPY_CLASS(wxCairoContext);
480};
481
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
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
644//-----------------------------------------------------------------------------
645// wxCairoPenData implementation
646//-----------------------------------------------------------------------------
647
648wxCairoPenData::~wxCairoPenData()
649{
650 delete[] m_userLengths;
651}
652
653void wxCairoPenData::Init()
654{
655 m_lengths = NULL;
656 m_userLengths = NULL;
657 m_width = 0;
658 m_count = 0;
659}
660
661wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
662 : wxCairoPenBrushBaseData(renderer, pen.GetColour(), pen.IsTransparent())
663{
664 Init();
665 m_width = pen.GetWidth();
666 if (m_width <= 0.0)
667 m_width = 0.1;
668
669 switch ( pen.GetCap() )
670 {
671 case wxCAP_ROUND :
672 m_cap = CAIRO_LINE_CAP_ROUND;
673 break;
674
675 case wxCAP_PROJECTING :
676 m_cap = CAIRO_LINE_CAP_SQUARE;
677 break;
678
679 case wxCAP_BUTT :
680 m_cap = CAIRO_LINE_CAP_BUTT;
681 break;
682
683 default :
684 m_cap = CAIRO_LINE_CAP_BUTT;
685 break;
686 }
687
688 switch ( pen.GetJoin() )
689 {
690 case wxJOIN_BEVEL :
691 m_join = CAIRO_LINE_JOIN_BEVEL;
692 break;
693
694 case wxJOIN_MITER :
695 m_join = CAIRO_LINE_JOIN_MITER;
696 break;
697
698 case wxJOIN_ROUND :
699 m_join = CAIRO_LINE_JOIN_ROUND;
700 break;
701
702 default :
703 m_join = CAIRO_LINE_JOIN_MITER;
704 break;
705 }
706
707 const double dashUnit = m_width < 1.0 ? 1.0 : m_width;
708 const double dotted[] =
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 };
724
725 switch ( pen.GetStyle() )
726 {
727 case wxPENSTYLE_SOLID :
728 break;
729
730 case wxPENSTYLE_DOT :
731 m_count = WXSIZEOF(dotted);
732 m_userLengths = new double[ m_count ] ;
733 memcpy( m_userLengths, dotted, sizeof(dotted) );
734 m_lengths = m_userLengths;
735 break;
736
737 case wxPENSTYLE_LONG_DASH :
738 m_lengths = dashed ;
739 m_count = WXSIZEOF(dashed);
740 break;
741
742 case wxPENSTYLE_SHORT_DASH :
743 m_lengths = short_dashed ;
744 m_count = WXSIZEOF(short_dashed);
745 break;
746
747 case wxPENSTYLE_DOT_DASH :
748 m_lengths = dotted_dashed ;
749 m_count = WXSIZEOF(dotted_dashed);
750 break;
751
752 case wxPENSTYLE_USER_DASH :
753 {
754 wxDash *wxdashes ;
755 m_count = pen.GetDashes( &wxdashes ) ;
756 if ((wxdashes != NULL) && (m_count > 0))
757 {
758 m_userLengths = new double[m_count] ;
759 for ( int i = 0 ; i < m_count ; ++i )
760 {
761 m_userLengths[i] = wxdashes[i] * dashUnit ;
762
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 ;
767 }
768 }
769 m_lengths = m_userLengths ;
770 }
771 break;
772
773 case wxPENSTYLE_STIPPLE :
774 case wxPENSTYLE_STIPPLE_MASK :
775 case wxPENSTYLE_STIPPLE_MASK_OPAQUE :
776 InitStipple(pen.GetStipple());
777 break;
778
779 default :
780 if ( pen.GetStyle() >= wxPENSTYLE_FIRST_HATCH
781 && pen.GetStyle() <= wxPENSTYLE_LAST_HATCH )
782 {
783 InitHatch(static_cast<wxHatchStyle>(pen.GetStyle()));
784 }
785 break;
786 }
787}
788
789void wxCairoPenData::Apply( wxGraphicsContext* context )
790{
791 wxCairoPenBrushBaseData::Apply(context);
792
793 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
794 cairo_set_line_width(ctext,m_width);
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);
798}
799
800//-----------------------------------------------------------------------------
801// wxCairoBrushData implementation
802//-----------------------------------------------------------------------------
803
804wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer )
805 : wxCairoPenBrushBaseData(renderer, wxColour(), true /* transparent */)
806{
807 Init();
808}
809
810wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer,
811 const wxBrush &brush )
812 : wxCairoPenBrushBaseData(renderer, brush.GetColour(), brush.IsTransparent())
813{
814 Init();
815
816 switch ( brush.GetStyle() )
817 {
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;
828 }
829}
830
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 (
843 m_pattern,
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
852 wxASSERT_MSG(cairo_pattern_status(m_pattern) == CAIRO_STATUS_SUCCESS,
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)
860{
861 m_pattern = cairo_pattern_create_linear(x1,y1,x2,y2);
862
863 AddGradientStops(stops);
864}
865
866void
867wxCairoBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
868 wxDouble xc, wxDouble yc,
869 wxDouble radius,
870 const wxGraphicsGradientStops& stops)
871{
872 m_pattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius);
873
874 AddGradientStops(stops);
875}
876
877void wxCairoBrushData::Init()
878{
879 m_pattern = NULL;
880 m_bmpdata = NULL;
881}
882
883//-----------------------------------------------------------------------------
884// wxCairoFontData implementation
885//-----------------------------------------------------------------------------
886
887void wxCairoFontData::InitColour(const wxColour& col)
888{
889 m_red = col.Red()/255.0;
890 m_green = col.Green()/255.0;
891 m_blue = col.Blue()/255.0;
892 m_alpha = col.Alpha()/255.0;
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,
906 const wxColour& col )
907 : wxGraphicsObjectRefData(renderer)
908#ifdef __WXGTK__
909 , m_wxfont(font)
910#endif
911{
912 InitColour(col);
913
914 m_size = font.GetPointSize();
915
916#ifdef __WXMAC__
917 m_font = cairo_quartz_font_face_create_for_cgfont( font.OSXGetCGFont() );
918#elif defined(__WXGTK__)
919#else
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 );
928#endif
929}
930
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
945#if defined(__WXMAC__)
946 m_font = NULL;
947#endif
948
949 // There is no need to set m_underlined under wxGTK in this case, it can
950 // only be used if m_font != NULL.
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
962wxCairoFontData::~wxCairoFontData()
963{
964#ifdef __WXMAC__
965 if ( m_font )
966 cairo_font_face_destroy( m_font );
967#endif
968}
969
970bool wxCairoFontData::Apply( wxGraphicsContext* context )
971{
972 cairo_t * ctext = (cairo_t*) context->GetNativeContext();
973 cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha);
974#ifdef __WXGTK__
975 if (m_wxfont.IsOk())
976 {
977 // Nothing to do, the caller uses Pango layout functions to do
978 // everything.
979 return true;
980 }
981#elif defined(__WXMAC__)
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.
992 cairo_select_font_face(ctext, m_fontName, m_slant, m_weight );
993 cairo_set_font_size(ctext, m_size );
994
995 // Indicate that we don't use native fonts for the platforms which care
996 // about this (currently only wxGTK).
997 return false;
998}
999
1000//-----------------------------------------------------------------------------
1001// wxCairoPathData implementation
1002//-----------------------------------------------------------------------------
1003
1004wxCairoPathData::wxCairoPathData( wxGraphicsRenderer* renderer, cairo_t* pathcontext)
1005 : wxGraphicsPathData(renderer)
1006{
1007 if (pathcontext)
1008 {
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);
1016 }
1017}
1018
1019wxCairoPathData::~wxCairoPathData()
1020{
1021 cairo_destroy(m_pathContext);
1022}
1023
1024wxGraphicsObjectRefData *wxCairoPathData::Clone() const
1025{
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);
1033 return new wxCairoPathData( GetRenderer() ,pathcontext);
1034}
1035
1036
1037void* wxCairoPathData::GetNativePath() const
1038{
1039 return cairo_copy_path(m_pathContext) ;
1040}
1041
1042void wxCairoPathData::UnGetNativePath(void *p) const
1043{
1044 cairo_path_destroy((cairo_path_t*)p);
1045}
1046
1047//
1048// The Primitives
1049//
1050
1051void wxCairoPathData::MoveToPoint( wxDouble x , wxDouble y )
1052{
1053 cairo_move_to(m_pathContext,x,y);
1054}
1055
1056void wxCairoPathData::AddLineToPoint( wxDouble x , wxDouble y )
1057{
1058 cairo_line_to(m_pathContext,x,y);
1059}
1060
1061void wxCairoPathData::AddPath( const wxGraphicsPathData* path )
1062{
1063 cairo_path_t* p = (cairo_path_t*)path->GetNativePath();
1064 cairo_append_path(m_pathContext, p);
1065 UnGetNativePath(p);
1066}
1067
1068void wxCairoPathData::CloseSubpath()
1069{
1070 cairo_close_path(m_pathContext);
1071}
1072
1073void wxCairoPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
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
1079void wxCairoPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
1080{
1081 double dx,dy;
1082 cairo_get_current_point(m_pathContext,&dx,&dy);
1083 if (x)
1084 *x = dx;
1085 if (y)
1086 *y = dy;
1087}
1088
1089void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
1090{
1091 // as clockwise means positive in our system (y pointing downwards)
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
1101void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix )
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);
1108}
1109
1110// gets the bounding box enclosing all points (possibly including control points)
1111void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
1112{
1113 double x1,y1,x2,y2;
1114
1115 cairo_stroke_extents( m_pathContext, &x1, &y1, &x2, &y2 );
1116 if ( x2 < x1 )
1117 {
1118 *x = x2;
1119 *w = x1-x2;
1120 }
1121 else
1122 {
1123 *x = x1;
1124 *w = x2-x1;
1125 }
1126
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
1139bool wxCairoPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
1140{
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;
1143}
1144
1145//-----------------------------------------------------------------------------
1146// wxCairoMatrixData implementation
1147//-----------------------------------------------------------------------------
1148
1149wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix )
1150 : wxGraphicsMatrixData(renderer)
1151{
1152 if ( matrix )
1153 m_matrix = *matrix;
1154}
1155
1156wxCairoMatrixData::~wxCairoMatrixData()
1157{
1158 // nothing to do
1159}
1160
1161wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const
1162{
1163 return new wxCairoMatrixData(GetRenderer(),&m_matrix);
1164}
1165
1166// concatenates the matrix
1167void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t )
1168{
1169 cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix());
1170}
1171
1172// sets the matrix to the respective values
1173void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1174 wxDouble tx, wxDouble ty)
1175{
1176 cairo_matrix_init( &m_matrix, a, b, c, d, tx, ty);
1177}
1178
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
1191// makes this the inverse matrix
1192void wxCairoMatrixData::Invert()
1193{
1194 cairo_matrix_invert( &m_matrix );
1195}
1196
1197// returns true if the elements of the transformation matrix are equal ?
1198bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
1199{
1200 const cairo_matrix_t* tm = (cairo_matrix_t*) t->GetNativeMatrix();
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 &&
1207 m_matrix.y0 == tm->y0 ) ;
1208}
1209
1210// return true if this is the identity matrix
1211bool wxCairoMatrixData::IsIdentity() const
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
1222void wxCairoMatrixData::Translate( wxDouble dx , wxDouble dy )
1223{
1224 cairo_matrix_translate( &m_matrix, dx, dy) ;
1225}
1226
1227// add the scale to this matrix
1228void wxCairoMatrixData::Scale( wxDouble xScale , wxDouble yScale )
1229{
1230 cairo_matrix_scale( &m_matrix, xScale, yScale) ;
1231}
1232
1233// add the rotation to this matrix (radians)
1234void wxCairoMatrixData::Rotate( wxDouble angle )
1235{
1236 cairo_matrix_rotate( &m_matrix, angle) ;
1237}
1238
1239//
1240// apply the transforms
1241//
1242
1243// applies that matrix to the point
1244void wxCairoMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
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
1253void wxCairoMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
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
1262void * wxCairoMatrixData::GetNativeMatrix() const
1263{
1264 return (void*) &m_matrix;
1265}
1266
1267// ----------------------------------------------------------------------------
1268// wxCairoBitmap implementation
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}
1310
1311wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, cairo_surface_t* bitmap ) :
1312 wxGraphicsBitmapData( renderer )
1313{
1314 m_surface = bitmap;
1315 m_pattern = cairo_pattern_create_for_surface(m_surface);
1316}
1317
1318wxCairoBitmapData::wxCairoBitmapData( wxGraphicsRenderer* renderer, const wxBitmap& bmp ) : wxGraphicsBitmapData( renderer )
1319{
1320 wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap"));
1321
1322#ifdef wxHAS_RAW_BITMAP
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...
1326 cairo_format_t bufferFormat = bmp.GetDepth() == 32
1327#if defined(__WXGTK__) && !defined(__WXGTK3__)
1328 || bmp.GetMask()
1329#endif
1330 ? CAIRO_FORMAT_ARGB32
1331 : CAIRO_FORMAT_RGB24;
1332
1333 int stride = InitBuffer(bmp.GetWidth(), bmp.GetHeight(), bufferFormat);
1334
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
1341 wxAlphaPixelData
1342 pixData(bmpSource, wxPoint(0, 0), wxSize(m_width, m_height));
1343 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1344
1345 wxAlphaPixelData::Iterator p(pixData);
1346 for (int y=0; y<m_height; y++)
1347 {
1348 wxAlphaPixelData::Iterator rowStart = p;
1349 wxUint32* const rowStartDst = data;
1350 for (int x=0; x<m_width; x++)
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 }
1367
1368 data = rowStartDst + stride / 4;
1369 p = rowStart;
1370 p.OffsetY(pixData, 1);
1371 }
1372 }
1373 else // no alpha
1374 {
1375 wxNativePixelData
1376 pixData(bmpSource, wxPoint(0, 0), wxSize(m_width, m_height));
1377 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1378
1379 wxNativePixelData::Iterator p(pixData);
1380 for (int y=0; y<m_height; y++)
1381 {
1382 wxNativePixelData::Iterator rowStart = p;
1383 wxUint32* const rowStartDst = data;
1384 for (int x=0; x<m_width; x++)
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 }
1394
1395 data = rowStartDst + stride / 4;
1396 p = rowStart;
1397 p.OffsetY(pixData, 1);
1398 }
1399 }
1400#if defined(__WXMSW__) || defined(__WXGTK3__)
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;
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."));
1411
1412 wxNativePixelData::Iterator p(pixData);
1413 for (int y=0; y<m_height; y++)
1414 {
1415 wxNativePixelData::Iterator rowStart = p;
1416 wxUint32* const rowStartDst = data;
1417 for (int x=0; x<m_width; x++)
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 }
1426
1427 data = rowStartDst + stride / 4;
1428 p = rowStart;
1429 p.OffsetY(pixData, 1);
1430 }
1431 }
1432#endif
1433
1434 InitSurface(bufferFormat, stride);
1435#endif // wxHAS_RAW_BITMAP
1436}
1437
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)
1458 : wxGraphicsBitmapData(renderer)
1459{
1460 const cairo_format_t bufferFormat = image.HasAlpha()
1461 ? CAIRO_FORMAT_ARGB32
1462 : CAIRO_FORMAT_RGB24;
1463
1464 int stride = InitBuffer(image.GetWidth(), image.GetHeight(), bufferFormat);
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 {
1478 wxUint32* const rowStartDst = dst;
1479
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 }
1490
1491 dst = rowStartDst + stride / 4;
1492 }
1493 }
1494 else // RGB
1495 {
1496 for ( int y = 0; y < m_height; y++ )
1497 {
1498 wxUint32* const rowStartDst = dst;
1499
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 }
1507
1508 dst = rowStartDst + stride / 4;
1509 }
1510 }
1511
1512 InitSurface(bufferFormat, stride);
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
1606wxCairoBitmapData::~wxCairoBitmapData()
1607{
1608 if (m_pattern)
1609 cairo_pattern_destroy(m_pattern);
1610
1611 if (m_surface)
1612 cairo_surface_destroy(m_surface);
1613
1614 delete [] m_buffer;
1615}
1616
1617//-----------------------------------------------------------------------------
1618// wxCairoContext implementation
1619//-----------------------------------------------------------------------------
1620
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
1641wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxPrinterDC& dc )
1642: wxGraphicsContext(renderer)
1643{
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
1654#ifdef __WXGTK20__
1655 const wxDCImpl *impl = dc.GetImpl();
1656 Init( (cairo_t*) impl->GetCairoContext() );
1657#endif
1658 wxSize sz = dc.GetSize();
1659 m_width = sz.x;
1660 m_height = sz.y;
1661
1662 wxPoint org = dc.GetDeviceOrigin();
1663 cairo_translate( m_context, org.x, org.y );
1664
1665 double sx,sy;
1666 dc.GetUserScale( &sx, &sy );
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
1678 cairo_scale( m_context, sx, sy );
1679
1680 org = dc.GetLogicalOrigin();
1681 cairo_translate( m_context, -org.x, -org.y );
1682}
1683
1684wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc )
1685: wxGraphicsContext(renderer)
1686{
1687 int width, height;
1688 dc.GetSize( &width, &height );
1689 m_width = width;
1690 m_height = height;
1691
1692 m_enableOffset = true;
1693
1694#ifdef __WXMSW__
1695 m_mswSurface = cairo_win32_surface_create((HDC)dc.GetHDC());
1696 Init( cairo_create(m_mswSurface) );
1697#endif
1698
1699#ifdef __WXGTK3__
1700 cairo_t* cr = static_cast<cairo_t*>(dc.GetImpl()->GetCairoContext());
1701 if (cr)
1702 Init(cr);
1703#elif defined __WXGTK20__
1704 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
1705 Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
1706
1707#if 0
1708 wxGraphicsMatrix matrix = CreateMatrix();
1709
1710 wxPoint org = dc.GetDeviceOrigin();
1711 matrix.Translate( org.x, org.y );
1712
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
1722#endif
1723
1724#ifdef __WXMAC__
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{
1735 int width, height;
1736 dc.GetSize( &width, &height );
1737 m_width = width;
1738 m_height = height;
1739
1740 m_enableOffset = true;
1741
1742#ifdef __WXMSW__
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
1764 Init( cairo_create(m_mswSurface) );
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 }
1772#endif
1773
1774#ifdef __WXGTK3__
1775 cairo_t* cr = static_cast<cairo_t*>(dc.GetImpl()->GetCairoContext());
1776 if (cr)
1777 Init(cr);
1778#elif defined __WXGTK20__
1779 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
1780 Init( gdk_cairo_create( impldc->GetGDKWindow() ) );
1781
1782#if 0
1783 wxGraphicsMatrix matrix = CreateMatrix();
1784
1785 wxPoint org = dc.GetDeviceOrigin();
1786 matrix.Translate( org.x, org.y );
1787
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 );
1796#endif
1797#endif
1798
1799#ifdef __WXMAC__
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 );
1804#endif
1805}
1806
1807#ifdef __WXGTK20__
1808wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkWindow *window )
1809: wxGraphicsContext(renderer)
1810{
1811 Init( gdk_cairo_create( window ) );
1812
1813#ifdef __WXGTK3__
1814 m_width = gdk_window_get_width(window);
1815 m_height = gdk_window_get_height(window);
1816#else
1817 int width, height;
1818 gdk_drawable_get_size(window, &width, &height);
1819 m_width = width;
1820 m_height = height;
1821#endif
1822}
1823#endif
1824
1825#ifdef __WXMSW__
1826wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, HDC handle )
1827: wxGraphicsContext(renderer)
1828{
1829 m_mswSurface = cairo_win32_surface_create(handle);
1830 Init( cairo_create(m_mswSurface) );
1831 m_width =
1832 m_height = 0;
1833}
1834#endif
1835
1836
1837wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context )
1838: wxGraphicsContext(renderer)
1839{
1840 Init( context );
1841 m_width =
1842 m_height = 0;
1843}
1844
1845wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window)
1846 : wxGraphicsContext(renderer)
1847#ifdef __WXMSW__
1848 , m_mswWindowHDC(GetHwndOf(window))
1849#endif
1850{
1851 m_enableOffset = true;
1852#ifdef __WXGTK__
1853 // something along these lines (copied from dcclient)
1854
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.
1858 if (window->m_wxwindow == NULL)
1859 {
1860 window = window->GetParent();
1861 }
1862
1863 wxASSERT_MSG( window->m_wxwindow, wxT("wxCairoContext needs a widget") );
1864
1865 Init(gdk_cairo_create(window->GTKGetDrawingWindow()));
1866
1867 wxSize sz = window->GetSize();
1868 m_width = sz.x;
1869 m_height = sz.y;
1870#endif
1871
1872#ifdef __WXMSW__
1873 m_mswSurface = cairo_win32_surface_create((HDC)m_mswWindowHDC);
1874 Init(cairo_create(m_mswSurface));
1875#endif
1876
1877}
1878
1879wxCairoContext::wxCairoContext(wxGraphicsRenderer* renderer) :
1880 wxGraphicsContext(renderer)
1881{
1882 m_context = NULL;
1883}
1884
1885wxCairoContext::~wxCairoContext()
1886{
1887 if ( m_context )
1888 {
1889 PopState();
1890 PopState();
1891 cairo_destroy(m_context);
1892 }
1893#ifdef __WXMSW__
1894 if ( m_mswSurface )
1895 cairo_surface_destroy(m_mswSurface);
1896#endif
1897}
1898
1899void wxCairoContext::Init(cairo_t *context)
1900{
1901 m_context = context ;
1902 PushState();
1903 PushState();
1904}
1905
1906
1907void wxCairoContext::Clip( const wxRegion& region )
1908{
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());
1915 ++ri;
1916 }
1917
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);
1924 path.UnGetNativePath(cp);
1925}
1926
1927void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1928{
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
1938 cairo_clip(m_context);
1939 path.UnGetNativePath(cp);
1940}
1941
1942void wxCairoContext::ResetClip()
1943{
1944 cairo_reset_clip(m_context);
1945}
1946
1947
1948void wxCairoContext::StrokePath( const wxGraphicsPath& path )
1949{
1950 if ( !m_pen.IsNull() )
1951 {
1952 wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
1953 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
1954 cairo_append_path(m_context,cp);
1955 ((wxCairoPenData*)m_pen.GetRefData())->Apply(this);
1956 cairo_stroke(m_context);
1957 path.UnGetNativePath(cp);
1958 }
1959}
1960
1961void wxCairoContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
1962{
1963 if ( !m_brush.IsNull() )
1964 {
1965 wxCairoOffsetHelper helper( m_context, ShouldOffset() ) ;
1966 cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ;
1967 cairo_append_path(m_context,cp);
1968 ((wxCairoBrushData*)m_brush.GetRefData())->Apply(this);
1969 cairo_set_fill_rule(m_context,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
1970 cairo_fill(m_context);
1971 path.UnGetNativePath(cp);
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
1991void wxCairoContext::ConcatTransform( const wxGraphicsMatrix& matrix )
1992{
1993 cairo_transform(m_context,(const cairo_matrix_t *) matrix.GetNativeMatrix());
1994}
1995
1996// sets the transform of this context
1997void wxCairoContext::SetTransform( const wxGraphicsMatrix& matrix )
1998{
1999 cairo_set_matrix(m_context,(const cairo_matrix_t*) matrix.GetNativeMatrix());
2000}
2001
2002// gets the matrix of this context
2003wxGraphicsMatrix wxCairoContext::GetTransform() const
2004{
2005 wxGraphicsMatrix matrix = CreateMatrix();
2006 cairo_get_matrix(m_context,(cairo_matrix_t*) matrix.GetNativeMatrix());
2007 return matrix;
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}
2021
2022void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2023{
2024 wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
2025 DrawBitmap(bitmap, x, y, w, h);
2026
2027}
2028
2029void wxCairoContext::DrawBitmap(const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2030{
2031 PushState();
2032
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.
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();
2042
2043 // prepare to draw the image
2044 cairo_translate(m_context, x, y);
2045 cairo_scale(m_context, scaleX, scaleY);
2046 cairo_set_source(m_context, pattern);
2047 // use the original size here since the context is scaled already...
2048 cairo_rectangle(m_context, 0, 0, size.GetWidth(), size.GetHeight());
2049 // fill the rectangle using the pattern
2050 cairo_fill(m_context);
2051
2052 PopState();
2053}
2054
2055void wxCairoContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
2056{
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);
2061}
2062
2063
2064void wxCairoContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
2065{
2066 wxCHECK_RET( !m_font.IsNull(),
2067 wxT("wxCairoContext::DrawText - no valid font set") );
2068
2069 if ( str.empty())
2070 return;
2071
2072 const wxCharBuffer data = str.utf8_str();
2073 if ( !data )
2074 return;
2075
2076 if ( ((wxCairoFontData*)m_font.GetRefData())->Apply(this) )
2077 {
2078#ifdef __WXGTK__
2079 PangoLayout *layout = pango_cairo_create_layout (m_context);
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);
2084
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 }
2094
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);
2100
2101 cairo_show_text(m_context, data);
2102}
2103
2104void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
2105 wxDouble *descent, wxDouble *externalLeading ) const
2106{
2107 wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetTextExtent - no valid font set") );
2108
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
2118 if ( str.empty())
2119 return;
2120
2121 if ( ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this) )
2122 {
2123#ifdef __WXGTK__
2124 int w, h;
2125
2126 PangoLayout *layout = pango_cairo_create_layout (m_context);
2127 const wxFont& font = static_cast<wxCairoFontData*>(m_font.GetRefData())->GetFont();
2128 pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description);
2129 const wxCharBuffer data = str.utf8_str();
2130 if ( !data )
2131 {
2132 return;
2133 }
2134 pango_layout_set_text(layout, data, data.length());
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);
2148 return;
2149#endif
2150 }
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);
2164
2165 // some backends have negative descents
2166
2167 if ( fe.descent < 0 )
2168 fe.descent = -fe.descent;
2169
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 }
2175
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 }
2183}
2184
2185void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
2186{
2187 widths.Empty();
2188 wxCHECK_RET( !m_font.IsNull(), wxT("wxCairoContext::GetPartialTextExtents - no valid font set") );
2189#if __WXGTK__
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
2213 // TODO
2214#endif
2215}
2216
2217void * wxCairoContext::GetNativeContext()
2218{
2219 return m_context;
2220}
2221
2222bool wxCairoContext::SetAntialiasMode(wxAntialiasMode antialias)
2223{
2224 if (m_antialias == antialias)
2225 return true;
2226
2227 m_antialias = antialias;
2228
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}
2244
2245bool wxCairoContext::SetInterpolationQuality(wxInterpolationQuality WXUNUSED(interpolation))
2246{
2247 // placeholder
2248 return false;
2249}
2250
2251bool wxCairoContext::SetCompositionMode(wxCompositionMode op)
2252{
2253 if ( m_composition == op )
2254 return true;
2255
2256 m_composition = op;
2257 cairo_operator_t cop;
2258 switch (op)
2259 {
2260 case wxCOMPOSITION_CLEAR:
2261 cop = CAIRO_OPERATOR_CLEAR;
2262 break;
2263 case wxCOMPOSITION_SOURCE:
2264 cop = CAIRO_OPERATOR_SOURCE;
2265 break;
2266 case wxCOMPOSITION_OVER:
2267 cop = CAIRO_OPERATOR_OVER;
2268 break;
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;
2298 break;
2299 default:
2300 return false;
2301 }
2302 cairo_set_operator(m_context, cop);
2303 return true;
2304}
2305
2306void wxCairoContext::BeginLayer(wxDouble opacity)
2307{
2308 m_layerOpacities.push_back(opacity);
2309 cairo_push_group(m_context);
2310}
2311
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}
2319
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);
2334 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
2335 virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc);
2336
2337 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
2338
2339 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
2340#if wxUSE_IMAGE
2341 virtual wxGraphicsContext * CreateContextFromImage(wxImage& image);
2342#endif // wxUSE_IMAGE
2343
2344 virtual wxGraphicsContext * CreateContext( wxWindow* window );
2345
2346 virtual wxGraphicsContext * CreateMeasuringContext();
2347#ifdef __WXMSW__
2348#if wxUSE_ENH_METAFILE
2349 virtual wxGraphicsContext * CreateContext( const wxEnhMetaFileDC& dc);
2350#endif
2351#endif
2352 // Path
2353
2354 virtual wxGraphicsPath CreatePath();
2355
2356 // Matrix
2357
2358 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
2359 wxDouble tx=0.0, wxDouble ty=0.0);
2360
2361
2362 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
2363
2364 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
2365
2366 virtual wxGraphicsBrush
2367 CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
2368 wxDouble x2, wxDouble y2,
2369 const wxGraphicsGradientStops& stops);
2370
2371 virtual wxGraphicsBrush
2372 CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
2373 wxDouble xc, wxDouble yc,
2374 wxDouble radius,
2375 const wxGraphicsGradientStops& stops);
2376
2377 // sets the font
2378 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
2379 virtual wxGraphicsFont CreateFont(double sizeInPixels,
2380 const wxString& facename,
2381 int flags = wxFONTFLAG_DEFAULT,
2382 const wxColour& col = *wxBLACK);
2383
2384 // create a native bitmap representation
2385 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
2386#if wxUSE_IMAGE
2387 virtual wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image);
2388 virtual wxImage CreateImageFromBitmap(const wxGraphicsBitmap& bmp);
2389#endif // wxUSE_IMAGE
2390
2391 // create a graphics bitmap from a native bitmap
2392 virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
2393
2394 // create a subimage from a native image representation
2395 virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
2396
2397protected :
2398 bool EnsureIsLoaded();
2399 void Load();
2400 void Unload();
2401 friend class wxCairoModule;
2402private :
2403 int m_loaded;
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;
2414// temporary hack to allow creating a cairo context on any platform
2415extern wxGraphicsRenderer* gCairoRenderer;
2416wxGraphicsRenderer* gCairoRenderer = &gs_cairoGraphicsRenderer;
2417
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
2443wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc)
2444{
2445 ENSURE_LOADED_OR_RETURN(NULL);
2446 return new wxCairoContext(this,dc);
2447}
2448
2449wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc)
2450{
2451 ENSURE_LOADED_OR_RETURN(NULL);
2452 return new wxCairoContext(this,dc);
2453}
2454
2455wxGraphicsContext * wxCairoRenderer::CreateContext( const wxPrinterDC& dc)
2456{
2457 ENSURE_LOADED_OR_RETURN(NULL);
2458 return new wxCairoContext(this, dc);
2459}
2460
2461#ifdef __WXMSW__
2462#if wxUSE_ENH_METAFILE
2463wxGraphicsContext * wxCairoRenderer::CreateContext( const wxEnhMetaFileDC& WXUNUSED(dc) )
2464{
2465 ENSURE_LOADED_OR_RETURN(NULL);
2466 return NULL;
2467}
2468#endif
2469#endif
2470
2471wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context )
2472{
2473 ENSURE_LOADED_OR_RETURN(NULL);
2474#ifdef __WXMSW__
2475 return new wxCairoContext(this,(HDC)context);
2476#else
2477 return new wxCairoContext(this,(cairo_t*)context);
2478#endif
2479}
2480
2481
2482wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window )
2483{
2484 ENSURE_LOADED_OR_RETURN(NULL);
2485#ifdef __WXGTK__
2486 return new wxCairoContext(this, static_cast<GdkWindow*>(window));
2487#else
2488 wxUnusedVar(window);
2489 return NULL;
2490#endif
2491}
2492
2493#if wxUSE_IMAGE
2494wxGraphicsContext * wxCairoRenderer::CreateContextFromImage(wxImage& image)
2495{
2496 return new wxCairoImageContext(this, image);
2497}
2498#endif // wxUSE_IMAGE
2499
2500wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext()
2501{
2502 ENSURE_LOADED_OR_RETURN(NULL);
2503#ifdef __WXGTK__
2504 return CreateContextFromNativeWindow(gdk_get_default_root_window());
2505#else
2506 return NULL;
2507 // TODO
2508#endif
2509}
2510
2511wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window )
2512{
2513 ENSURE_LOADED_OR_RETURN(NULL);
2514 return new wxCairoContext(this, window );
2515}
2516
2517// Path
2518
2519wxGraphicsPath wxCairoRenderer::CreatePath()
2520{
2521 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath);
2522 wxGraphicsPath path;
2523 path.SetRefData( new wxCairoPathData(this) );
2524 return path;
2525}
2526
2527
2528// Matrix
2529
2530wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
2531 wxDouble tx, wxDouble ty)
2532
2533{
2534 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix);
2535 wxGraphicsMatrix m;
2536 wxCairoMatrixData* data = new wxCairoMatrixData( this );
2537 data->Set( a,b,c,d,tx,ty ) ;
2538 m.SetRefData(data);
2539 return m;
2540}
2541
2542wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen)
2543{
2544 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen);
2545 if ( !pen.IsOk() || pen.GetStyle() == wxPENSTYLE_TRANSPARENT )
2546 return wxNullGraphicsPen;
2547 else
2548 {
2549 wxGraphicsPen p;
2550 p.SetRefData(new wxCairoPenData( this, pen ));
2551 return p;
2552 }
2553}
2554
2555wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush )
2556{
2557 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2558 if ( !brush.IsOk() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT )
2559 return wxNullGraphicsBrush;
2560 else
2561 {
2562 wxGraphicsBrush p;
2563 p.SetRefData(new wxCairoBrushData( this, brush ));
2564 return p;
2565 }
2566}
2567
2568wxGraphicsBrush
2569wxCairoRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
2570 wxDouble x2, wxDouble y2,
2571 const wxGraphicsGradientStops& stops)
2572{
2573 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2574 wxGraphicsBrush p;
2575 wxCairoBrushData* d = new wxCairoBrushData( this );
2576 d->CreateLinearGradientBrush(x1, y1, x2, y2, stops);
2577 p.SetRefData(d);
2578 return p;
2579}
2580
2581wxGraphicsBrush
2582wxCairoRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
2583 wxDouble xc, wxDouble yc, wxDouble r,
2584 const wxGraphicsGradientStops& stops)
2585{
2586 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2587 wxGraphicsBrush p;
2588 wxCairoBrushData* d = new wxCairoBrushData( this );
2589 d->CreateRadialGradientBrush(xo, yo, xc, yc, r, stops);
2590 p.SetRefData(d);
2591 return p;
2592}
2593
2594wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col )
2595{
2596 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
2597 if ( font.IsOk() )
2598 {
2599 wxGraphicsFont p;
2600 p.SetRefData(new wxCairoFontData( this , font, col ));
2601 return p;
2602 }
2603 else
2604 return wxNullGraphicsFont;
2605}
2606
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
2620wxGraphicsBitmap wxCairoRenderer::CreateBitmap( const wxBitmap& bmp )
2621{
2622 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
2623 if ( bmp.IsOk() )
2624 {
2625 wxGraphicsBitmap p;
2626 p.SetRefData(new wxCairoBitmapData( this , bmp ));
2627 return p;
2628 }
2629 else
2630 return wxNullGraphicsBitmap;
2631}
2632
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
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
2659#endif // wxUSE_IMAGE
2660
2661
2662wxGraphicsBitmap wxCairoRenderer::CreateBitmapFromNativeBitmap( void* bitmap )
2663{
2664 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
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
2675wxGraphicsBitmap
2676wxCairoRenderer::CreateSubBitmap(const wxGraphicsBitmap& WXUNUSED(bitmap),
2677 wxDouble WXUNUSED(x),
2678 wxDouble WXUNUSED(y),
2679 wxDouble WXUNUSED(w),
2680 wxDouble WXUNUSED(h))
2681{
2682 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
2683 wxFAIL_MSG("wxCairoRenderer::CreateSubBitmap is not implemented.");
2684 return wxNullGraphicsBitmap;
2685}
2686
2687wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()
2688{
2689 return &gs_cairoGraphicsRenderer;
2690}
2691
2692#else // !wxUSE_CAIRO
2693
2694wxGraphicsRenderer* wxGraphicsRenderer::GetCairoRenderer()
2695{
2696 return NULL;
2697}
2698
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
2710#endif // wxUSE_GRAPHICS_CONTEXT