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 ®ion );
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 ®ion )
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