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