1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/graphics.cpp
3 // Purpose:     wxGCDC class
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:     2006-09-30
7 // RCS-ID:      $Id: graphics.cpp 61747 2009-08-23 21:36:09Z VZ $
8 // Copyright:   (c) 2006 Stefan Csomor
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 #include "wx/wxprec.h"
13 
14 #include "wx/dc.h"
15 
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19 
20 #ifndef WX_PRECOMP
21 #include "wx/msw/wrapcdlg.h"
22 #include "wx/image.h"
23 #include "wx/window.h"
24 #include "wx/dc.h"
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/app.h"
28 #include "wx/bitmap.h"
29 #include "wx/dcmemory.h"
30 #include "wx/log.h"
31 #include "wx/icon.h"
32 #include "wx/dcprint.h"
33 #include "wx/module.h"
34 #endif
35 
36 #include "wx/graphics.h"
37 
38 #if wxUSE_GRAPHICS_CONTEXT
39 
40 #include <vector>
41 
42 using namespace std;
43 
44 //-----------------------------------------------------------------------------
45 // constants
46 //-----------------------------------------------------------------------------
47 
48 const double RAD2DEG = 180.0 / M_PI;
49 
50 //-----------------------------------------------------------------------------
51 // Local functions
52 //-----------------------------------------------------------------------------
53 
dmin(double a,double b)54 static inline double dmin(double a, double b) { return a < b ? a : b; }
dmax(double a,double b)55 static inline double dmax(double a, double b) { return a > b ? a : b; }
56 
DegToRad(double deg)57 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
RadToDeg(double deg)58 static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
59 
60 //-----------------------------------------------------------------------------
61 // device context implementation
62 //
63 // more and more of the dc functionality should be implemented by calling
64 // the appropricate wxGDIPlusContext, but we will have to do that step by step
65 // also coordinate conversions should be moved to native matrix ops
66 //-----------------------------------------------------------------------------
67 
68 // we always stock two context states, one at entry, to be able to preserve the
69 // state we were called with, the other one after changing to HI Graphics orientation
70 // (this one is used for getting back clippings etc)
71 
72 //-----------------------------------------------------------------------------
73 // wxGraphicsPath implementation
74 //-----------------------------------------------------------------------------
75 
76 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
77 
78 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
79 #include <commdlg.h>
80 #endif
81 
82 // TODO remove this dependency (gdiplus needs the macros)
83 
84 #ifndef max
85 #define max(a,b)            (((a) > (b)) ? (a) : (b))
86 #endif
87 
88 #ifndef min
89 #define min(a,b)            (((a) < (b)) ? (a) : (b))
90 #endif
91 
92 #include "gdiplus.h"
93 using namespace Gdiplus;
94 
95 class WXDLLIMPEXP_CORE wxGDIPlusPathData : public wxGraphicsPathData
96 {
97 public :
98     wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path = NULL);
99     ~wxGDIPlusPathData();
100 
101     virtual wxGraphicsObjectRefData *Clone() const;
102 
103     //
104     // These are the path primitives from which everything else can be constructed
105     //
106 
107     // begins a new subpath at (x,y)
108     virtual void MoveToPoint( wxDouble x, wxDouble y );
109 
110     // adds a straight line from the current point to (x,y)
111     virtual void AddLineToPoint( wxDouble x, wxDouble y );
112 
113     // adds a cubic Bezier curve from the current point, using two control points and an end point
114     virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
115 
116 
117     // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
118     virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
119 
120     // gets the last point of the current path, (0,0) if not yet set
121     virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
122 
123     // adds another path
124     virtual void AddPath( const wxGraphicsPathData* path );
125 
126     // closes the current sub-path
127     virtual void CloseSubpath();
128 
129     //
130     // These are convenience functions which - if not available natively will be assembled
131     // using the primitives from above
132     //
133 
134     // appends a rectangle as a new closed subpath
135     virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
136     /*
137 
138     // appends an ellipsis as a new closed subpath fitting the passed rectangle
139     virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
140 
141     // 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)
142     virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )  ;
143 */
144 
145     // returns the native path
GetNativePath() const146     virtual void * GetNativePath() const { return m_path; }
147 
148     // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
UnGetNativePath(void * WXUNUSED (path)) const149     virtual void UnGetNativePath(void * WXUNUSED(path)) const {}
150 
151     // transforms each point of this path by the matrix
152     virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
153 
154     // gets the bounding box enclosing all points (possibly including control points)
155     virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
156 
157     virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxODDEVEN_RULE) const;
158 
159 private :
160     GraphicsPath* m_path;
161 };
162 
163 class WXDLLIMPEXP_CORE wxGDIPlusMatrixData : public wxGraphicsMatrixData
164 {
165 public :
166     wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix = NULL) ;
167     virtual ~wxGDIPlusMatrixData() ;
168 
169     virtual wxGraphicsObjectRefData* Clone() const ;
170 
171     // concatenates the matrix
172     virtual void Concat( const wxGraphicsMatrixData *t );
173 
174     // sets the matrix to the respective values
175     virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
176         wxDouble tx=0.0, wxDouble ty=0.0);
177 
178     // gets the component valuess of the matrix
179     virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL,  wxDouble* c=NULL,
180                      wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const;
181 
182     // makes this the inverse matrix
183     virtual void Invert();
184 
185     // returns true if the elements of the transformation matrix are equal ?
186     virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
187 
188     // return true if this is the identity matrix
189     virtual bool IsIdentity() const;
190 
191     //
192     // transformation
193     //
194 
195     // add the translation to this matrix
196     virtual void Translate( wxDouble dx , wxDouble dy );
197 
198     // add the scale to this matrix
199     virtual void Scale( wxDouble xScale , wxDouble yScale );
200 
201     // add the rotation to this matrix (radians)
202     virtual void Rotate( wxDouble angle );
203 
204     //
205     // apply the transforms
206     //
207 
208     // applies that matrix to the point
209     virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
210 
211     // applies the matrix except for translations
212     virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
213 
214     // returns the native representation
215     virtual void * GetNativeMatrix() const;
216 private:
217     Matrix* m_matrix ;
218 } ;
219 
220 class WXDLLIMPEXP_CORE wxGDIPlusPenData : public wxGraphicsObjectRefData
221 {
222 public:
223     wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
224     ~wxGDIPlusPenData();
225 
226     void Init();
227 
GetWidth()228     virtual wxDouble GetWidth() { return m_width; }
GetGDIPlusPen()229     virtual Pen* GetGDIPlusPen() { return m_pen; }
230 
231 protected :
232     Pen* m_pen;
233     Image* m_penImage;
234     Brush* m_penBrush;
235 
236     wxDouble m_width;
237 };
238 
239 class WXDLLIMPEXP_CORE wxGDIPlusBrushData : public wxGraphicsObjectRefData
240 {
241 public:
242     wxGDIPlusBrushData( wxGraphicsRenderer* renderer );
243     wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
244     ~wxGDIPlusBrushData ();
245 
246     void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
247         const wxColour&c1, const wxColour&c2 );
248     void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
249         const wxColour &oColor, const wxColour &cColor );
GetGDIPlusBrush()250     virtual Brush* GetGDIPlusBrush() { return m_brush; }
251 
252 protected:
253     virtual void Init();
254 
255 private :
256     Brush* m_brush;
257     Image* m_brushImage;
258     GraphicsPath* m_brushPath;
259 };
260 
261 class WXDLLIMPEXP_CORE wxGDIPlusBitmapData : public wxGraphicsObjectRefData
262 {
263 public:
264     wxGDIPlusBitmapData( wxGraphicsRenderer* renderer );
265     wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, const wxBitmap &bmp );
266     ~wxGDIPlusBitmapData ();
267 
GetGDIPlusBitmap()268     virtual Bitmap* GetGDIPlusBitmap() { return m_bitmap; }
269 
270 private :
271     Bitmap* m_bitmap;
272     Bitmap* m_helper;
273 };
274 
275 class WXDLLIMPEXP_CORE wxGDIPlusFontData : public wxGraphicsObjectRefData
276 {
277 public:
278     wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
279     ~wxGDIPlusFontData();
280 
GetGDIPlusBrush()281     virtual Brush* GetGDIPlusBrush() { return m_textBrush; }
GetGDIPlusFont()282     virtual Font* GetGDIPlusFont() { return m_font; }
283 private :
284     Brush* m_textBrush;
285     Font* m_font;
286 };
287 
288 class WXDLLIMPEXP_CORE wxGDIPlusContext : public wxGraphicsContext
289 {
290 public:
291     wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc );
292     wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd );
293     wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr);
294     wxGDIPlusContext();
295 
296     virtual ~wxGDIPlusContext();
297 
298     virtual void Clip( const wxRegion &region );
299     // clips drawings to the rect
300     virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
301 
302     // resets the clipping to original extent
303     virtual void ResetClip();
304 
305     virtual void * GetNativeContext();
306 
307     virtual void StrokePath( const wxGraphicsPath& p );
308     virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxODDEVEN_RULE );
309 
310     // stroke lines connecting each of the points
311     virtual void StrokeLines( size_t n, const wxPoint2DDouble *points);
312 
313     // draws a polygon
314     virtual void DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle = wxODDEVEN_RULE );
315 
316     virtual void Translate( wxDouble dx , wxDouble dy );
317     virtual void Scale( wxDouble xScale , wxDouble yScale );
318     virtual void Rotate( wxDouble angle );
319 
320     // concatenates this transform with the current transform of this context
321     virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
322 
323     // sets the transform of this context
324     virtual void SetTransform( const wxGraphicsMatrix& matrix );
325 
326     // gets the matrix of this context
327     virtual wxGraphicsMatrix GetTransform() const;
328 
329     void DrawGraphicsBitmapInternal( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
330     virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
331     virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
332     virtual void PushState();
333     virtual void PopState();
334 
335     virtual void DrawText( const wxString &str, wxDouble x, wxDouble y);
336     virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
337         wxDouble *descent, wxDouble *externalLeading ) const;
338     virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
339     virtual bool ShouldOffset() const;
340 
341 private:
342     void    Init();
343     void    SetDefaults();
344 
345     Graphics* m_context;
346     vector<GraphicsState> m_stateStack;
347     GraphicsState m_state1;
348     GraphicsState m_state2;
349 
350     DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext)
351 };
352 
353 class WXDLLIMPEXP_CORE wxGDIPlusMeasuringContext : public wxGDIPlusContext
354 {
355 public:
wxGDIPlusMeasuringContext(wxGraphicsRenderer * renderer)356     wxGDIPlusMeasuringContext( wxGraphicsRenderer* renderer ) : wxGDIPlusContext( renderer , m_hdc = GetDC(NULL) )
357     {
358     }
wxGDIPlusMeasuringContext()359     wxGDIPlusMeasuringContext()
360     {
361     }
362 
~wxGDIPlusMeasuringContext()363     virtual ~wxGDIPlusMeasuringContext()
364     {
365         ReleaseDC( NULL, m_hdc );
366     }
367 
368 private:
369     HDC m_hdc ;
370     DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMeasuringContext)
371 } ;
372 
373 //-----------------------------------------------------------------------------
374 // wxGDIPlusPen implementation
375 //-----------------------------------------------------------------------------
376 
~wxGDIPlusPenData()377 wxGDIPlusPenData::~wxGDIPlusPenData()
378 {
379     delete m_pen;
380     delete m_penImage;
381     delete m_penBrush;
382 }
383 
Init()384 void wxGDIPlusPenData::Init()
385 {
386     m_pen = NULL ;
387     m_penImage = NULL;
388     m_penBrush = NULL;
389 }
390 
wxGDIPlusPenData(wxGraphicsRenderer * renderer,const wxPen & pen)391 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
392 : wxGraphicsObjectRefData(renderer)
393 {
394     Init();
395     m_width = pen.GetWidth();
396     if (m_width <= 0.0)
397         m_width = 0.1;
398 
399     m_pen = new Pen(Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
400         pen.GetColour().Green() , pen.GetColour().Blue() ), m_width );
401 
402     LineCap cap;
403     switch ( pen.GetCap() )
404     {
405     case wxCAP_ROUND :
406         cap = LineCapRound;
407         break;
408 
409     case wxCAP_PROJECTING :
410         cap = LineCapSquare;
411         break;
412 
413     case wxCAP_BUTT :
414         cap = LineCapFlat; // TODO verify
415         break;
416 
417     default :
418         cap = LineCapFlat;
419         break;
420     }
421     m_pen->SetLineCap(cap,cap, DashCapFlat);
422 
423     LineJoin join;
424     switch ( pen.GetJoin() )
425     {
426     case wxJOIN_BEVEL :
427         join = LineJoinBevel;
428         break;
429 
430     case wxJOIN_MITER :
431         join = LineJoinMiter;
432         break;
433 
434     case wxJOIN_ROUND :
435         join = LineJoinRound;
436         break;
437 
438     default :
439         join = LineJoinMiter;
440         break;
441     }
442 
443     m_pen->SetLineJoin(join);
444 
445     m_pen->SetDashStyle(DashStyleSolid);
446 
447     DashStyle dashStyle = DashStyleSolid;
448     switch ( pen.GetStyle() )
449     {
450     case wxSOLID :
451         break;
452 
453     case wxDOT :
454         dashStyle = DashStyleDot;
455         break;
456 
457     case wxLONG_DASH :
458         dashStyle = DashStyleDash; // TODO verify
459         break;
460 
461     case wxSHORT_DASH :
462         dashStyle = DashStyleDash;
463         break;
464 
465     case wxDOT_DASH :
466         dashStyle = DashStyleDashDot;
467         break;
468     case wxUSER_DASH :
469         {
470             dashStyle = DashStyleCustom;
471             wxDash *dashes;
472             int count = pen.GetDashes( &dashes );
473             if ((dashes != NULL) && (count > 0))
474             {
475                 REAL *userLengths = new REAL[count];
476                 for ( int i = 0; i < count; ++i )
477                 {
478                     userLengths[i] = dashes[i];
479                 }
480                 m_pen->SetDashPattern( userLengths, count);
481                 delete[] userLengths;
482             }
483         }
484         break;
485     case wxSTIPPLE :
486         {
487             wxBitmap* bmp = pen.GetStipple();
488             if ( bmp && bmp->Ok() )
489             {
490                 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
491                 m_penBrush = new TextureBrush(m_penImage);
492                 m_pen->SetBrush( m_penBrush );
493             }
494 
495         }
496         break;
497     default :
498         if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH )
499         {
500             HatchStyle style = HatchStyleHorizontal;
501             switch( pen.GetStyle() )
502             {
503             case wxBDIAGONAL_HATCH :
504                 style = HatchStyleBackwardDiagonal;
505                 break ;
506             case wxCROSSDIAG_HATCH :
507                 style = HatchStyleDiagonalCross;
508                 break ;
509             case wxFDIAGONAL_HATCH :
510                 style = HatchStyleForwardDiagonal;
511                 break ;
512             case wxCROSS_HATCH :
513                 style = HatchStyleCross;
514                 break ;
515             case wxHORIZONTAL_HATCH :
516                 style = HatchStyleHorizontal;
517                 break ;
518             case wxVERTICAL_HATCH :
519                 style = HatchStyleVertical;
520                 break ;
521 
522             }
523             m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
524                 pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent );
525             m_pen->SetBrush( m_penBrush );
526         }
527         break;
528     }
529     if ( dashStyle != DashStyleSolid )
530         m_pen->SetDashStyle(dashStyle);
531 }
532 
533 //-----------------------------------------------------------------------------
534 // wxGDIPlusBrush implementation
535 //-----------------------------------------------------------------------------
536 
wxGDIPlusBrushData(wxGraphicsRenderer * renderer)537 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer )
538 : wxGraphicsObjectRefData(renderer)
539 {
540     Init();
541 }
542 
wxGDIPlusBrushData(wxGraphicsRenderer * renderer,const wxBrush & brush)543 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush )
544 : wxGraphicsObjectRefData(renderer)
545 {
546     Init();
547     if ( brush.GetStyle() == wxSOLID)
548     {
549         m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
550             brush.GetColour().Green() , brush.GetColour().Blue() ) );
551     }
552     else if ( brush.IsHatch() )
553     {
554         HatchStyle style = HatchStyleHorizontal;
555         switch( brush.GetStyle() )
556         {
557         case wxBDIAGONAL_HATCH :
558             style = HatchStyleBackwardDiagonal;
559             break ;
560         case wxCROSSDIAG_HATCH :
561             style = HatchStyleDiagonalCross;
562             break ;
563         case wxFDIAGONAL_HATCH :
564             style = HatchStyleForwardDiagonal;
565             break ;
566         case wxCROSS_HATCH :
567             style = HatchStyleCross;
568             break ;
569         case wxHORIZONTAL_HATCH :
570             style = HatchStyleHorizontal;
571             break ;
572         case wxVERTICAL_HATCH :
573             style = HatchStyleVertical;
574             break ;
575 
576         }
577         m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
578             brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent );
579     }
580     else
581     {
582         wxBitmap* bmp = brush.GetStipple();
583         if ( bmp && bmp->Ok() )
584         {
585             wxDELETE( m_brushImage );
586             m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
587             m_brush = new TextureBrush(m_brushImage);
588         }
589     }
590 }
591 
~wxGDIPlusBrushData()592 wxGDIPlusBrushData::~wxGDIPlusBrushData()
593 {
594     delete m_brush;
595     delete m_brushImage;
596     delete m_brushPath;
597 };
598 
Init()599 void wxGDIPlusBrushData::Init()
600 {
601     m_brush = NULL;
602     m_brushImage= NULL;
603     m_brushPath= NULL;
604 }
605 
CreateLinearGradientBrush(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,const wxColour & c1,const wxColour & c2)606 void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
607 {
608     m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2),
609         Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ),
610         Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() ));
611 }
612 
CreateRadialGradientBrush(wxDouble xo,wxDouble yo,wxDouble xc,wxDouble yc,wxDouble radius,const wxColour & oColor,const wxColour & cColor)613 void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
614                                                const wxColour &oColor, const wxColour &cColor)
615 {
616     // Create a path that consists of a single circle.
617     m_brushPath = new GraphicsPath();
618     m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius));
619 
620     PathGradientBrush *b = new PathGradientBrush(m_brushPath);
621     m_brush = b;
622     b->SetCenterPoint( PointF(xo,yo));
623     b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() ));
624 
625     Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )};
626     int count = 1;
627     b->SetSurroundColors(colors, &count);
628 }
629 
wxGDIPlusBitmapData(wxGraphicsRenderer * renderer,const wxBitmap & bmp)630 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer,
631                         const wxBitmap &bmp) : wxGraphicsObjectRefData( renderer )
632 {
633     m_bitmap = NULL;
634     m_helper = NULL;
635     Bitmap* image = NULL;
636     if ( bmp.GetMask() )
637     {
638         Bitmap interim((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()) ;
639 
640         size_t width = interim.GetWidth();
641         size_t height = interim.GetHeight();
642         Rect bounds(0,0,width,height);
643 
644         image = new Bitmap(width,height,PixelFormat32bppPARGB) ;
645 
646         Bitmap interimMask((HBITMAP)bmp.GetMask()->GetMaskBitmap(),NULL);
647         wxASSERT(interimMask.GetPixelFormat() == PixelFormat1bppIndexed);
648 
649         BitmapData dataMask ;
650         interimMask.LockBits(&bounds,ImageLockModeRead,
651             interimMask.GetPixelFormat(),&dataMask);
652 
653 
654         BitmapData imageData ;
655         image->LockBits(&bounds,ImageLockModeWrite, PixelFormat32bppPARGB, &imageData);
656 
657         BYTE maskPattern = 0 ;
658         BYTE maskByte = 0;
659         size_t maskIndex ;
660 
661         for ( size_t y = 0 ; y < height ; ++y)
662         {
663             maskIndex = 0 ;
664             for( size_t x = 0 ; x < width; ++x)
665             {
666                 if ( x % 8 == 0)
667                 {
668                     maskPattern = 0x80;
669                     maskByte = *((BYTE*)dataMask.Scan0 + dataMask.Stride*y + maskIndex);
670                     maskIndex++;
671                 }
672                 else
673                     maskPattern = maskPattern >> 1;
674 
675                 ARGB *dest = (ARGB*)((BYTE*)imageData.Scan0 + imageData.Stride*y + x*4);
676                 if ( (maskByte & maskPattern) == 0 )
677                     *dest = 0x00000000;
678                 else
679                 {
680                     Color c ;
681                     interim.GetPixel(x,y,&c) ;
682                     *dest = (c.GetValue() | Color::AlphaMask);
683                 }
684             }
685         }
686 
687         image->UnlockBits(&imageData);
688 
689         interimMask.UnlockBits(&dataMask);
690         interim.UnlockBits(&dataMask);
691     }
692     else
693     {
694         image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
695         if ( bmp.HasAlpha() && GetPixelFormatSize(image->GetPixelFormat()) == 32 )
696         {
697             size_t width = image->GetWidth();
698             size_t height = image->GetHeight();
699             Rect bounds(0,0,width,height);
700             static BitmapData data ;
701 
702             m_helper = image ;
703             image = NULL ;
704             m_helper->LockBits(&bounds, ImageLockModeRead,
705                 m_helper->GetPixelFormat(),&data);
706 
707             image = new Bitmap(data.Width, data.Height, data.Stride,
708                 PixelFormat32bppPARGB , (BYTE*) data.Scan0);
709 
710             m_helper->UnlockBits(&data);
711         }
712     }
713     if ( image )
714         m_bitmap = image;
715 }
716 
~wxGDIPlusBitmapData()717 wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
718 {
719     delete m_bitmap;
720     delete m_helper;
721 }
722 
723 //-----------------------------------------------------------------------------
724 // wxGDIPlusFont implementation
725 //-----------------------------------------------------------------------------
726 
wxGDIPlusFontData(wxGraphicsRenderer * renderer,const wxFont & font,const wxColour & col)727 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font,
728                              const wxColour& col ) : wxGraphicsObjectRefData( renderer )
729 {
730     m_textBrush = NULL;
731     m_font = NULL;
732 
733     wxWCharBuffer s = font.GetFaceName().wc_str( *wxConvUI );
734     int size = font.GetPointSize();
735     int style = FontStyleRegular;
736     if ( font.GetStyle() == wxFONTSTYLE_ITALIC )
737         style |= FontStyleItalic;
738     if ( font.GetUnderlined() )
739         style |= FontStyleUnderline;
740     if ( font.GetWeight() == wxFONTWEIGHT_BOLD )
741         style |= FontStyleBold;
742     m_font = new Font( s , size , style );
743     m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() ,
744         col.Green() , col.Blue() ));
745 }
746 
~wxGDIPlusFontData()747 wxGDIPlusFontData::~wxGDIPlusFontData()
748 {
749     delete m_textBrush;
750     delete m_font;
751 }
752 
753 //-----------------------------------------------------------------------------
754 // wxGDIPlusPath implementation
755 //-----------------------------------------------------------------------------
756 
wxGDIPlusPathData(wxGraphicsRenderer * renderer,GraphicsPath * path)757 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path ) : wxGraphicsPathData(renderer)
758 {
759     if ( path )
760         m_path = path;
761     else
762         m_path = new GraphicsPath();
763 }
764 
~wxGDIPlusPathData()765 wxGDIPlusPathData::~wxGDIPlusPathData()
766 {
767     delete m_path;
768 }
769 
Clone() const770 wxGraphicsObjectRefData* wxGDIPlusPathData::Clone() const
771 {
772     return new wxGDIPlusPathData( GetRenderer() , m_path->Clone());
773 }
774 
775 //
776 // The Primitives
777 //
778 
MoveToPoint(wxDouble x,wxDouble y)779 void wxGDIPlusPathData::MoveToPoint( wxDouble x , wxDouble y )
780 {
781     m_path->StartFigure();
782     m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
783 }
784 
AddLineToPoint(wxDouble x,wxDouble y)785 void wxGDIPlusPathData::AddLineToPoint( wxDouble x , wxDouble y )
786 {
787     m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
788 }
789 
CloseSubpath()790 void wxGDIPlusPathData::CloseSubpath()
791 {
792     m_path->CloseFigure();
793 }
794 
AddCurveToPoint(wxDouble cx1,wxDouble cy1,wxDouble cx2,wxDouble cy2,wxDouble x,wxDouble y)795 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
796 {
797     PointF c1(cx1,cy1);
798     PointF c2(cx2,cy2);
799     PointF end(x,y);
800     PointF start;
801     m_path->GetLastPoint(&start);
802     m_path->AddBezier(start,c1,c2,end);
803 }
804 
805 // gets the last point of the current path, (0,0) if not yet set
GetCurrentPoint(wxDouble * x,wxDouble * y) const806 void wxGDIPlusPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
807 {
808     PointF start;
809     m_path->GetLastPoint(&start);
810     *x = start.X ;
811     *y = start.Y ;
812 }
813 
AddArc(wxDouble x,wxDouble y,wxDouble r,double startAngle,double endAngle,bool clockwise)814 void wxGDIPlusPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
815 {
816     double sweepAngle = endAngle - startAngle ;
817     if( fabs(sweepAngle) >= 2*M_PI)
818     {
819         sweepAngle = 2 * M_PI;
820     }
821     else
822     {
823         if ( clockwise )
824         {
825             if( sweepAngle < 0 )
826                 sweepAngle += 2 * M_PI;
827         }
828         else
829         {
830             if( sweepAngle > 0 )
831                 sweepAngle -= 2 * M_PI;
832 
833         }
834    }
835    m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle));
836 }
837 
AddRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h)838 void wxGDIPlusPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
839 {
840     m_path->AddRectangle(RectF(x,y,w,h));
841 }
842 
AddPath(const wxGraphicsPathData * path)843 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData* path )
844 {
845     m_path->AddPath( (GraphicsPath*) path->GetNativePath(), FALSE);
846 }
847 
848 
849 // transforms each point of this path by the matrix
Transform(const wxGraphicsMatrixData * matrix)850 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData* matrix )
851 {
852     m_path->Transform( (Matrix*) matrix->GetNativeMatrix() );
853 }
854 
855 // gets the bounding box enclosing all points (possibly including control points)
GetBox(wxDouble * x,wxDouble * y,wxDouble * w,wxDouble * h) const856 void wxGDIPlusPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
857 {
858     RectF bounds;
859     m_path->GetBounds( &bounds, NULL, NULL) ;
860     *x = bounds.X;
861     *y = bounds.Y;
862     *w = bounds.Width;
863     *h = bounds.Height;
864 }
865 
Contains(wxDouble x,wxDouble y,int fillStyle) const866 bool wxGDIPlusPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const
867 {
868     m_path->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
869     return m_path->IsVisible( (FLOAT) x,(FLOAT) y) == TRUE ;
870 }
871 
872 //-----------------------------------------------------------------------------
873 // wxGDIPlusMatrixData implementation
874 //-----------------------------------------------------------------------------
875 
wxGDIPlusMatrixData(wxGraphicsRenderer * renderer,Matrix * matrix)876 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix )
877     : wxGraphicsMatrixData(renderer)
878 {
879     if ( matrix )
880         m_matrix = matrix ;
881     else
882         m_matrix = new Matrix();
883 }
884 
~wxGDIPlusMatrixData()885 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
886 {
887     delete m_matrix;
888 }
889 
Clone() const890 wxGraphicsObjectRefData *wxGDIPlusMatrixData::Clone() const
891 {
892     return new wxGDIPlusMatrixData( GetRenderer(), m_matrix->Clone());
893 }
894 
895 // concatenates the matrix
Concat(const wxGraphicsMatrixData * t)896 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData *t )
897 {
898     m_matrix->Multiply( (Matrix*) t->GetNativeMatrix());
899 }
900 
901 // sets the matrix to the respective values
Set(wxDouble a,wxDouble b,wxDouble c,wxDouble d,wxDouble tx,wxDouble ty)902 void wxGDIPlusMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
903                  wxDouble tx, wxDouble ty)
904 {
905     m_matrix->SetElements(a,b,c,d,tx,ty);
906 }
907 
908 // gets the component valuess of the matrix
Get(wxDouble * a,wxDouble * b,wxDouble * c,wxDouble * d,wxDouble * tx,wxDouble * ty) const909 void wxGDIPlusMatrixData::Get(wxDouble* a, wxDouble* b,  wxDouble* c,
910                               wxDouble* d, wxDouble* tx, wxDouble* ty) const
911 {
912     REAL elements[6];
913     m_matrix->GetElements(elements);
914     if (a)  *a = elements[0];
915     if (b)  *b = elements[1];
916     if (c)  *c = elements[2];
917     if (d)  *d = elements[3];
918     if (tx) *tx= elements[4];
919     if (ty) *ty= elements[5];
920 }
921 
922 // makes this the inverse matrix
Invert()923 void wxGDIPlusMatrixData::Invert()
924 {
925     m_matrix->Invert();
926 }
927 
928 // returns true if the elements of the transformation matrix are equal ?
IsEqual(const wxGraphicsMatrixData * t) const929 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
930 {
931     return m_matrix->Equals((Matrix*) t->GetNativeMatrix())== TRUE ;
932 }
933 
934 // return true if this is the identity matrix
IsIdentity() const935 bool wxGDIPlusMatrixData::IsIdentity() const
936 {
937     return m_matrix->IsIdentity() == TRUE ;
938 }
939 
940 //
941 // transformation
942 //
943 
944 // add the translation to this matrix
Translate(wxDouble dx,wxDouble dy)945 void wxGDIPlusMatrixData::Translate( wxDouble dx , wxDouble dy )
946 {
947     m_matrix->Translate(dx,dy);
948 }
949 
950 // add the scale to this matrix
Scale(wxDouble xScale,wxDouble yScale)951 void wxGDIPlusMatrixData::Scale( wxDouble xScale , wxDouble yScale )
952 {
953     m_matrix->Scale(xScale,yScale);
954 }
955 
956 // add the rotation to this matrix (radians)
Rotate(wxDouble angle)957 void wxGDIPlusMatrixData::Rotate( wxDouble angle )
958 {
959     m_matrix->Rotate( angle );
960 }
961 
962 //
963 // apply the transforms
964 //
965 
966 // applies that matrix to the point
TransformPoint(wxDouble * x,wxDouble * y) const967 void wxGDIPlusMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
968 {
969     PointF pt(*x,*y);
970     m_matrix->TransformPoints(&pt);
971     *x = pt.X;
972     *y = pt.Y;
973 }
974 
975 // applies the matrix except for translations
TransformDistance(wxDouble * dx,wxDouble * dy) const976 void wxGDIPlusMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
977 {
978     PointF pt(*dx,*dy);
979     m_matrix->TransformVectors(&pt);
980     *dx = pt.X;
981     *dy = pt.Y;
982 }
983 
984 // returns the native representation
GetNativeMatrix() const985 void * wxGDIPlusMatrixData::GetNativeMatrix() const
986 {
987     return m_matrix;
988 }
989 
990 //-----------------------------------------------------------------------------
991 // wxGDIPlusContext implementation
992 //-----------------------------------------------------------------------------
993 
994 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
995 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMeasuringContext,wxGDIPlusContext)
996 
997 class wxGDIPlusOffsetHelper
998 {
999 public :
wxGDIPlusOffsetHelper(Graphics * gr,bool offset)1000     wxGDIPlusOffsetHelper( Graphics* gr , bool offset )
1001     {
1002         m_gr = gr;
1003         m_offset = offset;
1004         if ( m_offset )
1005             m_gr->TranslateTransform( 0.5, 0.5 );
1006     }
~wxGDIPlusOffsetHelper()1007     ~wxGDIPlusOffsetHelper( )
1008     {
1009         if ( m_offset )
1010             m_gr->TranslateTransform( -0.5, -0.5 );
1011     }
1012 public :
1013     Graphics* m_gr;
1014     bool m_offset;
1015 } ;
1016 
wxGDIPlusContext(wxGraphicsRenderer * renderer,HDC hdc)1017 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc  )
1018     : wxGraphicsContext(renderer)
1019 {
1020     Init();
1021     m_context = new Graphics( hdc);
1022     SetDefaults();
1023 }
1024 
wxGDIPlusContext(wxGraphicsRenderer * renderer,HWND hwnd)1025 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd  )
1026     : wxGraphicsContext(renderer)
1027 {
1028     Init();
1029     m_context = new Graphics( hwnd);
1030     SetDefaults();
1031 }
1032 
wxGDIPlusContext(wxGraphicsRenderer * renderer,Graphics * gr)1033 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr  )
1034     : wxGraphicsContext(renderer)
1035 {
1036     Init();
1037     m_context = gr;
1038     SetDefaults();
1039 }
1040 
wxGDIPlusContext()1041 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL)
1042 {
1043     Init();
1044 }
1045 
Init()1046 void wxGDIPlusContext::Init()
1047 {
1048     m_context = NULL;
1049     m_state1 = 0;
1050     m_state2= 0;
1051 }
1052 
SetDefaults()1053 void wxGDIPlusContext::SetDefaults()
1054 {
1055     m_context->SetTextRenderingHint(TextRenderingHintSystemDefault);
1056     m_context->SetPixelOffsetMode(PixelOffsetModeHalf);
1057     m_context->SetSmoothingMode(SmoothingModeHighQuality);
1058     m_state1 = m_context->Save();
1059     m_state2 = m_context->Save();
1060 }
1061 
~wxGDIPlusContext()1062 wxGDIPlusContext::~wxGDIPlusContext()
1063 {
1064     if ( m_context )
1065     {
1066         m_context->Restore( m_state2 );
1067         m_context->Restore( m_state1 );
1068         delete m_context;
1069     }
1070 }
1071 
1072 
Clip(const wxRegion & region)1073 void wxGDIPlusContext::Clip( const wxRegion &region )
1074 {
1075     Region rgn((HRGN)region.GetHRGN());
1076     m_context->SetClip(&rgn,CombineModeIntersect);
1077 }
1078 
Clip(wxDouble x,wxDouble y,wxDouble w,wxDouble h)1079 void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1080 {
1081     m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
1082 }
1083 
ResetClip()1084 void wxGDIPlusContext::ResetClip()
1085 {
1086     m_context->ResetClip();
1087 }
1088 
StrokeLines(size_t n,const wxPoint2DDouble * points)1089 void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
1090 {
1091     if ( !m_pen.IsNull() )
1092     {
1093         wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1094         Point *cpoints = new Point[n];
1095         for (size_t i = 0; i < n; i++)
1096         {
1097             cpoints[i].X = (int)(points[i].m_x );
1098             cpoints[i].Y = (int)(points[i].m_y );
1099 
1100         } // for (size_t i = 0; i < n; i++)
1101         m_context->DrawLines( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , cpoints , n ) ;
1102         delete[] cpoints;
1103     }
1104 }
1105 
DrawLines(size_t n,const wxPoint2DDouble * points,int WXUNUSED (fillStyle))1106 void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, int WXUNUSED(fillStyle) )
1107 {
1108     wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1109     Point *cpoints = new Point[n];
1110     for (size_t i = 0; i < n; i++)
1111     {
1112         cpoints[i].X = (int)(points[i].m_x );
1113         cpoints[i].Y = (int)(points[i].m_y );
1114 
1115     } // for (int i = 0; i < n; i++)
1116     if ( !m_brush.IsNull() )
1117         m_context->FillPolygon( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() , cpoints , n ) ;
1118     if ( !m_pen.IsNull() )
1119         m_context->DrawLines( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , cpoints , n ) ;
1120     delete[] cpoints;
1121 }
1122 
StrokePath(const wxGraphicsPath & path)1123 void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
1124 {
1125     if ( !m_pen.IsNull() )
1126     {
1127         wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1128         m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
1129     }
1130 }
1131 
FillPath(const wxGraphicsPath & path,int fillStyle)1132 void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , int fillStyle )
1133 {
1134     if ( !m_brush.IsNull() )
1135     {
1136         wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1137         ((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
1138         m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
1139             (GraphicsPath*) path.GetNativePath());
1140     }
1141 }
1142 
Rotate(wxDouble angle)1143 void wxGDIPlusContext::Rotate( wxDouble angle )
1144 {
1145     m_context->RotateTransform( RadToDeg(angle) );
1146 }
1147 
Translate(wxDouble dx,wxDouble dy)1148 void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
1149 {
1150     m_context->TranslateTransform( dx , dy );
1151 }
1152 
Scale(wxDouble xScale,wxDouble yScale)1153 void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
1154 {
1155     m_context->ScaleTransform(xScale,yScale);
1156 }
1157 
PushState()1158 void wxGDIPlusContext::PushState()
1159 {
1160     GraphicsState state = m_context->Save();
1161     m_stateStack.push_back(state);
1162 }
1163 
PopState()1164 void wxGDIPlusContext::PopState()
1165 {
1166     GraphicsState state = m_stateStack.back();
1167     m_stateStack.pop_back();
1168     m_context->Restore(state);
1169 }
1170 
1171 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
1172 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
1173 // bytes as parameter
1174 
DrawGraphicsBitmap(const wxGraphicsBitmap & bmp,wxDouble x,wxDouble y,wxDouble w,wxDouble h)1175 void wxGraphicsContext::DrawGraphicsBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1176 {
1177     static_cast<wxGDIPlusContext*>(this)->DrawGraphicsBitmapInternal(bmp, x, y, w, h);
1178 }
1179 
DrawGraphicsBitmapInternal(const wxGraphicsBitmap & bmp,wxDouble x,wxDouble y,wxDouble w,wxDouble h)1180 void wxGDIPlusContext::DrawGraphicsBitmapInternal( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1181 {
1182     Bitmap* image = static_cast<wxGDIPlusBitmapData*>(bmp.GetRefData())->GetGDIPlusBitmap();
1183     if ( image )
1184     {
1185         if( image->GetWidth() != (UINT) w || image->GetHeight() != (UINT) h )
1186         {
1187             Rect drawRect((REAL) x, (REAL)y, (REAL)w, (REAL)h);
1188             m_context->SetPixelOffsetMode( PixelOffsetModeNone );
1189             m_context->DrawImage(image, drawRect, 0 , 0 , image->GetWidth()-1, image->GetHeight()-1, UnitPixel ) ;
1190             m_context->SetPixelOffsetMode( PixelOffsetModeHalf );
1191         }
1192         else
1193             m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
1194     }
1195 }
1196 
DrawBitmap(const wxBitmap & bmp,wxDouble x,wxDouble y,wxDouble w,wxDouble h)1197 void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1198 {
1199     wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
1200     DrawGraphicsBitmapInternal(bitmap, x, y, w, h);
1201 }
1202 
DrawIcon(const wxIcon & icon,wxDouble x,wxDouble y,wxDouble w,wxDouble h)1203 void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1204 {
1205     // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
1206     // find out by looking at the bitmap data whether there really was alpha in it
1207     HICON hIcon = (HICON)icon.GetHICON();
1208     ICONINFO iconInfo ;
1209     // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1210     if (!GetIconInfo(hIcon,&iconInfo))
1211         return;
1212 
1213     Bitmap interim(iconInfo.hbmColor,NULL);
1214 
1215     Bitmap* image = NULL ;
1216 
1217     // if it's not 32 bit, it doesn't have an alpha channel, note that since the conversion doesn't
1218     // work correctly, asking IsAlphaPixelFormat at this point fails as well
1219     if( GetPixelFormatSize(interim.GetPixelFormat())!= 32 )
1220     {
1221         image = Bitmap::FromHICON(hIcon);
1222     }
1223     else
1224     {
1225         size_t width = interim.GetWidth();
1226         size_t height = interim.GetHeight();
1227         Rect bounds(0,0,width,height);
1228         BitmapData data ;
1229 
1230         interim.LockBits(&bounds, ImageLockModeRead,
1231             interim.GetPixelFormat(),&data);
1232 
1233         bool hasAlpha = false;
1234         for ( size_t y = 0 ; y < height && !hasAlpha ; ++y)
1235         {
1236             for( size_t x = 0 ; x < width && !hasAlpha; ++x)
1237             {
1238                 ARGB *dest = (ARGB*)((BYTE*)data.Scan0 + data.Stride*y + x*4);
1239                 if ( ( *dest & Color::AlphaMask ) != 0 )
1240                     hasAlpha = true;
1241             }
1242         }
1243 
1244         if ( hasAlpha )
1245         {
1246             image = new Bitmap(data.Width, data.Height, data.Stride,
1247                 PixelFormat32bppARGB , (BYTE*) data.Scan0);
1248         }
1249         else
1250         {
1251             image = Bitmap::FromHICON(hIcon);
1252         }
1253 
1254         interim.UnlockBits(&data);
1255     }
1256 
1257     m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
1258 
1259     delete image ;
1260     DeleteObject(iconInfo.hbmColor);
1261     DeleteObject(iconInfo.hbmMask);
1262 }
1263 
DrawText(const wxString & str,wxDouble x,wxDouble y)1264 void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
1265 {
1266     wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::DrawText - no valid font set") );
1267 
1268     if ( str.IsEmpty())
1269         return ;
1270 
1271     wxWCharBuffer s = str.wc_str( *wxConvUI );
1272     m_context->DrawString( s , -1 , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont() ,
1273             PointF( x , y ) , StringFormat::GenericTypographic() , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusBrush() );
1274 }
1275 
GetTextExtent(const wxString & str,wxDouble * width,wxDouble * height,wxDouble * descent,wxDouble * externalLeading) const1276 void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1277                                      wxDouble *descent, wxDouble *externalLeading ) const
1278 {
1279     wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1280 
1281     wxWCharBuffer s = str.wc_str( *wxConvUI );
1282     FontFamily ffamily ;
1283     Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
1284 
1285     f->GetFamily(&ffamily) ;
1286 
1287     REAL factorY = m_context->GetDpiY() / 72.0 ;
1288 
1289     REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
1290         f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1291     REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
1292         f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1293     REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
1294         f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1295 
1296     if ( height )
1297         *height = rHeight * factorY;
1298     if ( descent )
1299         *descent = rDescent * factorY;
1300     if ( externalLeading )
1301         *externalLeading = (rHeight - rAscent - rDescent) * factorY;
1302     // measuring empty strings is not guaranteed, so do it by hand
1303     if ( str.IsEmpty())
1304     {
1305         if ( width )
1306             *width = 0 ;
1307     }
1308     else
1309     {
1310         RectF layoutRect(0,0, 100000.0f, 100000.0f);
1311         StringFormat strFormat( StringFormat::GenericTypographic() );
1312         strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
1313 
1314         RectF bounds ;
1315         m_context->MeasureString((const wchar_t *) s , wcslen(s) , f, layoutRect, &strFormat, &bounds ) ;
1316         if ( width )
1317             *width = bounds.Width;
1318     }
1319 }
1320 
GetPartialTextExtents(const wxString & text,wxArrayDouble & widths) const1321 void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
1322 {
1323     widths.Empty();
1324     widths.Add(0, text.length());
1325 
1326     wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1327 
1328     if (text.empty())
1329         return;
1330 
1331     Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
1332     wxWCharBuffer ws = text.wc_str( *wxConvUI );
1333     size_t len = wcslen( ws ) ;
1334     wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1335 
1336     RectF layoutRect(0,0, 100000.0f, 100000.0f);
1337     StringFormat strFormat( StringFormat::GenericTypographic() );
1338 
1339     CharacterRange* ranges = new CharacterRange[len] ;
1340     Region* regions = new Region[len];
1341     for( size_t i = 0 ; i < len ; ++i)
1342     {
1343         ranges[i].First = i ;
1344         ranges[i].Length = 1 ;
1345     }
1346     strFormat.SetMeasurableCharacterRanges(len,ranges);
1347     strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
1348     m_context->MeasureCharacterRanges(ws, -1 , f,layoutRect, &strFormat,1,regions) ;
1349 
1350     RectF bbox ;
1351     for ( size_t i = 0 ; i < len ; ++i)
1352     {
1353         regions[i].GetBounds(&bbox,m_context);
1354         widths[i] = bbox.GetRight()-bbox.GetLeft();
1355     }
1356 }
1357 
ShouldOffset() const1358 bool wxGDIPlusContext::ShouldOffset() const
1359 {
1360     int penwidth = 0 ;
1361     if ( !m_pen.IsNull() )
1362     {
1363         penwidth = (int)((wxGDIPlusPenData*)m_pen.GetRefData())->GetWidth();
1364         if ( penwidth == 0 )
1365             penwidth = 1;
1366     }
1367     return ( penwidth % 2 ) == 1;
1368 }
1369 
GetNativeContext()1370 void* wxGDIPlusContext::GetNativeContext()
1371 {
1372     return m_context;
1373 }
1374 
1375 // concatenates this transform with the current transform of this context
ConcatTransform(const wxGraphicsMatrix & matrix)1376 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
1377 {
1378     m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
1379 }
1380 
1381 // sets the transform of this context
SetTransform(const wxGraphicsMatrix & matrix)1382 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
1383 {
1384     m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
1385 }
1386 
1387 // gets the matrix of this context
GetTransform() const1388 wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
1389 {
1390     wxGraphicsMatrix matrix = CreateMatrix();
1391     m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1392     return matrix;
1393 }
1394 //-----------------------------------------------------------------------------
1395 // wxGDIPlusRenderer declaration
1396 //-----------------------------------------------------------------------------
1397 
1398 class WXDLLIMPEXP_CORE wxGDIPlusRenderer : public wxGraphicsRenderer
1399 {
1400 public :
wxGDIPlusRenderer()1401     wxGDIPlusRenderer()
1402     {
1403         m_loaded = -1;
1404         m_gditoken = 0;
1405     }
1406 
~wxGDIPlusRenderer()1407     virtual ~wxGDIPlusRenderer()
1408     {
1409         if ( m_loaded == 1 )
1410         {
1411             Unload();
1412         }
1413     }
1414 
1415     // Context
1416 
1417     virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1418 
1419     virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
1420 
1421     virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1422 
1423     virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1424 
1425     virtual wxGraphicsContext * CreateContext( wxWindow* window );
1426 
1427     virtual wxGraphicsContext * CreateMeasuringContext();
1428 
1429     // Path
1430 
1431     virtual wxGraphicsPath CreatePath();
1432 
1433     // Matrix
1434 
1435     virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
1436         wxDouble tx=0.0, wxDouble ty=0.0);
1437 
1438 
1439     virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
1440 
1441     virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
1442 
1443     // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1444     virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1445         const wxColour&c1, const wxColour&c2) ;
1446 
1447     // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1448     // with radius r and color cColor
1449     virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
1450         const wxColour &oColor, const wxColour &cColor) ;
1451 
1452     // sets the font
1453     virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
1454 
1455     wxGraphicsBitmap CreateBitmap( const wxBitmap &bmp ) ;
1456 protected :
1457     bool EnsureIsLoaded();
1458     void Load();
1459     void Unload();
1460     friend class wxGDIPlusRendererModule;
1461 
1462 private :
1463     int m_loaded;
1464     ULONG_PTR m_gditoken;
1465 
1466     DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer)
1467 } ;
1468 
1469 //-----------------------------------------------------------------------------
1470 // wxGDIPlusRenderer implementation
1471 //-----------------------------------------------------------------------------
1472 
1473 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1474 
1475 static wxGDIPlusRenderer gs_GDIPlusRenderer;
1476 
GetDefaultRenderer()1477 wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1478 {
1479     return &gs_GDIPlusRenderer;
1480 }
1481 
EnsureIsLoaded()1482 bool wxGDIPlusRenderer::EnsureIsLoaded()
1483 {
1484     // load gdiplus.dll if not yet loaded, but don't bother doing it again
1485     // if we already tried and failed (we don't want to spend lot of time
1486     // returning NULL from wxGraphicsContext::Create(), which may be called
1487     // relatively frequently):
1488     if ( m_loaded == -1 )
1489     {
1490         Load();
1491     }
1492 
1493     return m_loaded == 1;
1494 }
1495 
1496 // call EnsureIsLoaded() and return returnOnFail value if it fails
1497 #define ENSURE_LOADED_OR_RETURN(returnOnFail)  \
1498     if ( !EnsureIsLoaded() )                   \
1499         return (returnOnFail)
1500 
1501 
Load()1502 void wxGDIPlusRenderer::Load()
1503 {
1504     GdiplusStartupInput input;
1505     GdiplusStartupOutput output;
1506     if ( GdiplusStartup(&m_gditoken,&input,&output) == Gdiplus::Ok )
1507     {
1508         wxLogTrace(wxT("gdiplus"), wxT("successfully initialized GDI+"));
1509         m_loaded = 1;
1510     }
1511     else
1512     {
1513         wxLogTrace(wxT("gdiplus"), wxT("failed to initialize GDI+, missing gdiplus.dll?"));
1514         m_loaded = 0;
1515     }
1516 }
1517 
Unload()1518 void wxGDIPlusRenderer::Unload()
1519 {
1520     if ( m_gditoken )
1521     {
1522         GdiplusShutdown(m_gditoken);
1523         m_gditoken = NULL;
1524     }
1525     m_loaded = -1; // next Load() will try again
1526 }
1527 
CreateContext(const wxWindowDC & dc)1528 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1529 {
1530     ENSURE_LOADED_OR_RETURN(NULL);
1531     return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1532 }
1533 
CreateContext(const wxMemoryDC & dc)1534 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc)
1535 {
1536     ENSURE_LOADED_OR_RETURN(NULL);
1537     return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1538 }
1539 
CreateMeasuringContext()1540 wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
1541 {
1542     ENSURE_LOADED_OR_RETURN(NULL);
1543     return new wxGDIPlusMeasuringContext(this);
1544 }
1545 
CreateContextFromNativeContext(void * context)1546 wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1547 {
1548     ENSURE_LOADED_OR_RETURN(NULL);
1549     return new wxGDIPlusContext(this,(Graphics*) context);
1550 }
1551 
1552 
CreateContextFromNativeWindow(void * window)1553 wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1554 {
1555     ENSURE_LOADED_OR_RETURN(NULL);
1556     return new wxGDIPlusContext(this,(HWND) window);
1557 }
1558 
CreateContext(wxWindow * window)1559 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1560 {
1561     ENSURE_LOADED_OR_RETURN(NULL);
1562     return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1563 }
1564 
1565 // Path
1566 
CreatePath()1567 wxGraphicsPath wxGDIPlusRenderer::CreatePath()
1568 {
1569     ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath);
1570     wxGraphicsPath m;
1571     m.SetRefData( new wxGDIPlusPathData(this));
1572     return m;
1573 }
1574 
1575 
1576 // Matrix
1577 
CreateMatrix(wxDouble a,wxDouble b,wxDouble c,wxDouble d,wxDouble tx,wxDouble ty)1578 wxGraphicsMatrix wxGDIPlusRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1579                                                            wxDouble tx, wxDouble ty)
1580 
1581 {
1582     ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix);
1583     wxGraphicsMatrix m;
1584     wxGDIPlusMatrixData* data = new wxGDIPlusMatrixData( this );
1585     data->Set( a,b,c,d,tx,ty ) ;
1586     m.SetRefData(data);
1587     return m;
1588 }
1589 
CreatePen(const wxPen & pen)1590 wxGraphicsPen wxGDIPlusRenderer::CreatePen(const wxPen& pen)
1591 {
1592     ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen);
1593     if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
1594         return wxNullGraphicsPen;
1595     else
1596     {
1597         wxGraphicsPen p;
1598         p.SetRefData(new wxGDIPlusPenData( this, pen ));
1599         return p;
1600     }
1601 }
1602 
CreateBrush(const wxBrush & brush)1603 wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
1604 {
1605     ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
1606     if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
1607         return wxNullGraphicsBrush;
1608     else
1609     {
1610         wxGraphicsBrush p;
1611         p.SetRefData(new wxGDIPlusBrushData( this, brush ));
1612         return p;
1613     }
1614 }
1615 
1616 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
CreateLinearGradientBrush(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,const wxColour & c1,const wxColour & c2)1617 wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1618                                                                       const wxColour&c1, const wxColour&c2)
1619 {
1620     ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
1621     wxGraphicsBrush p;
1622     wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1623     d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1624     p.SetRefData(d);
1625     return p;
1626  }
1627 
1628 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1629 // with radius r and color cColor
CreateRadialGradientBrush(wxDouble xo,wxDouble yo,wxDouble xc,wxDouble yc,wxDouble radius,const wxColour & oColor,const wxColour & cColor)1630 wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
1631                                                                       const wxColour &oColor, const wxColour &cColor)
1632 {
1633     ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
1634     wxGraphicsBrush p;
1635     wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1636     d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1637     p.SetRefData(d);
1638     return p;
1639 }
1640 
1641 // sets the font
CreateFont(const wxFont & font,const wxColour & col)1642 wxGraphicsFont wxGDIPlusRenderer::CreateFont( const wxFont &font , const wxColour &col )
1643 {
1644     ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
1645     if ( font.Ok() )
1646     {
1647         wxGraphicsFont p;
1648         p.SetRefData(new wxGDIPlusFontData( this , font, col ));
1649         return p;
1650     }
1651     else
1652         return wxNullGraphicsFont;
1653 }
1654 
CreateBitmap(const wxBitmap & bmp)1655 wxGraphicsBitmap wxGraphicsRenderer::CreateBitmap( const wxBitmap& bmp )
1656 {
1657     if ( bmp.Ok() )
1658     {
1659         wxGraphicsBitmap p;
1660         p.SetRefData(new wxGDIPlusBitmapData( this , bmp ));
1661         return p;
1662     }
1663     else
1664         return wxNullGraphicsBitmap;
1665 }
1666 
1667 // Shutdown GDI+ at app exit, before possible dll unload
1668 class wxGDIPlusRendererModule : public wxModule
1669 {
1670 public:
OnInit()1671     virtual bool OnInit() { return true; }
OnExit()1672     virtual void OnExit() { gs_GDIPlusRenderer.Unload(); }
1673 
1674 private:
1675     DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule)
1676 };
1677 
1678 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule, wxModule)
1679 
1680 #endif  // wxUSE_GRAPHICS_CONTEXT
1681