]> git.saurik.com Git - wxWidgets.git/blame - src/msw/graphics.cpp
fix wxMenu leak (reopened #9089)
[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{
1011fbeb
SC
1264 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::DrawText - no valid font set") );
1265
1266 if ( str.IsEmpty())
6fea499c
SC
1267 return ;
1268
1269 wxWCharBuffer s = str.wc_str( *wxConvUI );
cb3a0d42 1270 m_context->DrawString( s , -1 , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont() ,
0c7bd159 1271 PointF( x , y ) , StringFormat::GenericTypographic() , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusBrush() );
6fea499c
SC
1272}
1273
1274void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1275 wxDouble *descent, wxDouble *externalLeading ) const
1276{
1011fbeb
SC
1277 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1278
6fea499c
SC
1279 wxWCharBuffer s = str.wc_str( *wxConvUI );
1280 FontFamily ffamily ;
2c820406 1281 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
cb3a0d42 1282
83576e68 1283 f->GetFamily(&ffamily) ;
6fea499c
SC
1284
1285 REAL factorY = m_context->GetDpiY() / 72.0 ;
1286
1287 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
83576e68 1288 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1289 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
83576e68 1290 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1291 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
83576e68 1292 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c
SC
1293
1294 if ( height )
595fda6f 1295 *height = rHeight * factorY;
6fea499c 1296 if ( descent )
595fda6f 1297 *descent = rDescent * factorY;
6fea499c 1298 if ( externalLeading )
595fda6f 1299 *externalLeading = (rHeight - rAscent - rDescent) * factorY;
6fea499c 1300 // measuring empty strings is not guaranteed, so do it by hand
cb3a0d42 1301 if ( str.IsEmpty())
6fea499c
SC
1302 {
1303 if ( width )
1304 *width = 0 ;
1305 }
1306 else
1307 {
6fea499c 1308 RectF layoutRect(0,0, 100000.0f, 100000.0f);
0c7bd159
SC
1309 StringFormat strFormat( StringFormat::GenericTypographic() );
1310 strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
1311
1312 RectF bounds ;
1313 m_context->MeasureString((const wchar_t *) s , wcslen(s) , f, layoutRect, &strFormat, &bounds ) ;
6fea499c 1314 if ( width )
0c7bd159 1315 *width = bounds.Width;
6fea499c
SC
1316 }
1317}
1318
cb3a0d42 1319void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
6fea499c
SC
1320{
1321 widths.Empty();
1322 widths.Add(0, text.length());
1323
1011fbeb
SC
1324 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1325
6fea499c
SC
1326 if (text.empty())
1327 return;
1328
2c820406 1329 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
6fea499c
SC
1330 wxWCharBuffer ws = text.wc_str( *wxConvUI );
1331 size_t len = wcslen( ws ) ;
1332 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1333
1334 RectF layoutRect(0,0, 100000.0f, 100000.0f);
0c7bd159 1335 StringFormat strFormat( StringFormat::GenericTypographic() );
6fea499c
SC
1336
1337 CharacterRange* ranges = new CharacterRange[len] ;
1338 Region* regions = new Region[len];
0c7bd159 1339 for( size_t i = 0 ; i < len ; ++i)
6fea499c
SC
1340 {
1341 ranges[i].First = i ;
1342 ranges[i].Length = 1 ;
1343 }
1344 strFormat.SetMeasurableCharacterRanges(len,ranges);
0c7bd159 1345 strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
83576e68 1346 m_context->MeasureCharacterRanges(ws, -1 , f,layoutRect, &strFormat,1,regions) ;
6fea499c
SC
1347
1348 RectF bbox ;
0c7bd159 1349 for ( size_t i = 0 ; i < len ; ++i)
6fea499c
SC
1350 {
1351 regions[i].GetBounds(&bbox,m_context);
1352 widths[i] = bbox.GetRight()-bbox.GetLeft();
1353 }
1354}
1355
d9485f89
RD
1356bool wxGDIPlusContext::ShouldOffset() const
1357{
1358 int penwidth = 0 ;
1359 if ( !m_pen.IsNull() )
1360 {
1361 penwidth = (int)((wxGDIPlusPenData*)m_pen.GetRefData())->GetWidth();
1362 if ( penwidth == 0 )
1363 penwidth = 1;
1364 }
1365 return ( penwidth % 2 ) == 1;
1366}
1367
cb3a0d42 1368void* wxGDIPlusContext::GetNativeContext()
6fea499c 1369{
cb3a0d42 1370 return m_context;
6fea499c
SC
1371}
1372
83576e68 1373// concatenates this transform with the current transform of this context
a4e73390 1374void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
539e2795 1375{
a4e73390 1376 m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1377}
1378
1379// sets the transform of this context
a4e73390 1380void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
83576e68 1381{
a4e73390 1382 m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1383}
1384
1385// gets the matrix of this context
a4e73390 1386wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
83576e68 1387{
a4e73390
SC
1388 wxGraphicsMatrix matrix = CreateMatrix();
1389 m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1390 return matrix;
83576e68
SC
1391}
1392//-----------------------------------------------------------------------------
1393// wxGDIPlusRenderer declaration
1394//-----------------------------------------------------------------------------
1395
eb4083ef 1396class wxGDIPlusRenderer : public wxGraphicsRenderer
83576e68
SC
1397{
1398public :
cb3a0d42 1399 wxGDIPlusRenderer()
83576e68 1400 {
bce82a75 1401 m_loaded = -1;
cb3a0d42 1402 m_gditoken = 0;
83576e68
SC
1403 }
1404
cb3a0d42 1405 virtual ~wxGDIPlusRenderer()
83576e68 1406 {
bce82a75 1407 if ( m_loaded == 1 )
83576e68
SC
1408 {
1409 Unload();
1410 }
1411 }
1412
1413 // Context
1414
1415 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1416
773ccc31
SC
1417 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
1418
0b822969
RR
1419 virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc);
1420
83576e68
SC
1421 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1422
1423 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1424
1425 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1426
091ef146
SC
1427 virtual wxGraphicsContext * CreateMeasuringContext();
1428
83576e68
SC
1429 // Path
1430
a4e73390 1431 virtual wxGraphicsPath CreatePath();
83576e68
SC
1432
1433 // Matrix
1434
cb3a0d42 1435 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
83576e68
SC
1436 wxDouble tx=0.0, wxDouble ty=0.0);
1437
1438
2c820406 1439 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
83576e68 1440
2c820406 1441 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
83576e68
SC
1442
1443 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
cb3a0d42 1444 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68
SC
1445 const wxColour&c1, const wxColour&c2) ;
1446
cb3a0d42 1447 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
83576e68 1448 // with radius r and color cColor
2c820406 1449 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
1450 const wxColour &oColor, const wxColour &cColor) ;
1451
1452 // sets the font
2c820406 1453 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
bce28872
SC
1454
1455 // create a native bitmap representation
1456 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
1457
1458 // create a subimage from a native image representation
1459 virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
1460
83576e68 1461protected :
bce82a75 1462 bool EnsureIsLoaded();
83576e68
SC
1463 void Load();
1464 void Unload();
385addaf 1465 friend class wxGDIPlusRendererModule;
83576e68
SC
1466
1467private :
bce82a75 1468 int m_loaded;
cb3a0d42 1469 ULONG_PTR m_gditoken;
83576e68
SC
1470
1471 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer)
1472} ;
1473
1474//-----------------------------------------------------------------------------
1475// wxGDIPlusRenderer implementation
1476//-----------------------------------------------------------------------------
1477
1478IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1479
1480static wxGDIPlusRenderer gs_GDIPlusRenderer;
1481
1482wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1483{
1484 return &gs_GDIPlusRenderer;
1485}
1486
bce82a75 1487bool wxGDIPlusRenderer::EnsureIsLoaded()
83576e68 1488{
bce82a75
VS
1489 // load gdiplus.dll if not yet loaded, but don't bother doing it again
1490 // if we already tried and failed (we don't want to spend lot of time
1491 // returning NULL from wxGraphicsContext::Create(), which may be called
1492 // relatively frequently):
1493 if ( m_loaded == -1 )
83576e68
SC
1494 {
1495 Load();
1496 }
bce82a75
VS
1497
1498 return m_loaded == 1;
83576e68
SC
1499}
1500
bce82a75
VS
1501// call EnsureIsLoaded() and return returnOnFail value if it fails
1502#define ENSURE_LOADED_OR_RETURN(returnOnFail) \
1503 if ( !EnsureIsLoaded() ) \
1504 return (returnOnFail)
1505
1506
83576e68
SC
1507void wxGDIPlusRenderer::Load()
1508{
1509 GdiplusStartupInput input;
1510 GdiplusStartupOutput output;
bce82a75
VS
1511 if ( GdiplusStartup(&m_gditoken,&input,&output) == Gdiplus::Ok )
1512 {
1513 wxLogTrace("gdiplus", "successfully initialized GDI+");
1514 m_loaded = 1;
1515 }
1516 else
1517 {
1518 wxLogTrace("gdiplus", "failed to initialize GDI+, missing gdiplus.dll?");
1519 m_loaded = 0;
1520 }
83576e68
SC
1521}
1522
1523void wxGDIPlusRenderer::Unload()
1524{
1525 if ( m_gditoken )
385addaf 1526 {
83576e68 1527 GdiplusShutdown(m_gditoken);
385addaf
VZ
1528 m_gditoken = NULL;
1529 }
bce82a75 1530 m_loaded = -1; // next Load() will try again
83576e68
SC
1531}
1532
1533wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1534{
bce82a75 1535 ENSURE_LOADED_OR_RETURN(NULL);
52018692
SC
1536 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
1537 return new wxGDIPlusContext(this,(HDC) msw->GetHDC());
83576e68
SC
1538}
1539
0b822969
RR
1540wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxPrinterDC& dc)
1541{
bce82a75 1542 ENSURE_LOADED_OR_RETURN(NULL);
0b822969
RR
1543 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
1544 return new wxGDIPlusContext(this,(HDC) msw->GetHDC());
1545}
1546
773ccc31
SC
1547wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc)
1548{
bce82a75 1549 ENSURE_LOADED_OR_RETURN(NULL);
52018692
SC
1550 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
1551 return new wxGDIPlusContext(this,(HDC) msw->GetHDC());
773ccc31
SC
1552}
1553
091ef146
SC
1554wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
1555{
bce82a75 1556 ENSURE_LOADED_OR_RETURN(NULL);
0c7bd159 1557 return new wxGDIPlusMeasuringContext(this);
091ef146
SC
1558}
1559
83576e68
SC
1560wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1561{
bce82a75 1562 ENSURE_LOADED_OR_RETURN(NULL);
83576e68
SC
1563 return new wxGDIPlusContext(this,(Graphics*) context);
1564}
1565
1566
1567wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1568{
bce82a75 1569 ENSURE_LOADED_OR_RETURN(NULL);
83576e68
SC
1570 return new wxGDIPlusContext(this,(HWND) window);
1571}
1572
1573wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1574{
bce82a75 1575 ENSURE_LOADED_OR_RETURN(NULL);
83576e68
SC
1576 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1577}
1578
1579// Path
1580
a4e73390 1581wxGraphicsPath wxGDIPlusRenderer::CreatePath()
83576e68 1582{
bce82a75 1583 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath);
a4e73390
SC
1584 wxGraphicsPath m;
1585 m.SetRefData( new wxGDIPlusPathData(this));
1586 return m;
83576e68
SC
1587}
1588
1589
1590// Matrix
1591
cb3a0d42 1592wxGraphicsMatrix wxGDIPlusRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
83576e68
SC
1593 wxDouble tx, wxDouble ty)
1594
1595{
bce82a75 1596 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix);
a4e73390
SC
1597 wxGraphicsMatrix m;
1598 wxGDIPlusMatrixData* data = new wxGDIPlusMatrixData( this );
1599 data->Set( a,b,c,d,tx,ty ) ;
1600 m.SetRefData(data);
83576e68 1601 return m;
539e2795
SC
1602}
1603
cb3a0d42 1604wxGraphicsPen wxGDIPlusRenderer::CreatePen(const wxPen& pen)
6fea499c 1605{
bce82a75 1606 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen);
83576e68 1607 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
2c820406 1608 return wxNullGraphicsPen;
83576e68 1609 else
2c820406
SC
1610 {
1611 wxGraphicsPen p;
1612 p.SetRefData(new wxGDIPlusPenData( this, pen ));
1613 return p;
1614 }
6fea499c 1615}
7ba86d93 1616
cb3a0d42 1617wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
539e2795 1618{
bce82a75 1619 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
83576e68 1620 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
2c820406 1621 return wxNullGraphicsBrush;
83576e68 1622 else
2c820406
SC
1623 {
1624 wxGraphicsBrush p;
1625 p.SetRefData(new wxGDIPlusBrushData( this, brush ));
1626 return p;
1627 }
539e2795
SC
1628}
1629
83576e68 1630// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
cb3a0d42
VZ
1631wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1632 const wxColour&c1, const wxColour&c2)
539e2795 1633{
bce82a75 1634 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2c820406
SC
1635 wxGraphicsBrush p;
1636 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1637 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1638 p.SetRefData(d);
1639 return p;
1640 }
539e2795 1641
cb3a0d42 1642// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
83576e68 1643// with radius r and color cColor
2c820406 1644wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
cb3a0d42 1645 const wxColour &oColor, const wxColour &cColor)
83576e68 1646{
bce82a75 1647 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2c820406
SC
1648 wxGraphicsBrush p;
1649 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1650 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1651 p.SetRefData(d);
1652 return p;
83576e68 1653}
539e2795 1654
83576e68 1655// sets the font
cb3a0d42 1656wxGraphicsFont wxGDIPlusRenderer::CreateFont( const wxFont &font , const wxColour &col )
83576e68 1657{
bce82a75 1658 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
83576e68 1659 if ( font.Ok() )
cb3a0d42 1660 {
2c820406
SC
1661 wxGraphicsFont p;
1662 p.SetRefData(new wxGDIPlusFontData( this , font, col ));
1663 return p;
1664 }
83576e68 1665 else
2c820406 1666 return wxNullGraphicsFont;
83576e68 1667}
7ba86d93 1668
bce28872
SC
1669wxGraphicsBitmap wxGDIPlusRenderer::CreateBitmap( const wxBitmap &bitmap )
1670{
bce82a75 1671 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
bce28872
SC
1672 if ( bitmap.Ok() )
1673 {
1674 wxGraphicsBitmap p;
1675 p.SetRefData(new wxGDIPlusBitmapData( this , bitmap ));
1676 return p;
1677 }
1678 else
1679 return wxNullGraphicsBitmap;
1680}
1681
1682wxGraphicsBitmap wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1683{
bce82a75 1684 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
bce28872
SC
1685 Bitmap* image = static_cast<wxGDIPlusBitmapData*>(bitmap.GetRefData())->GetGDIPlusBitmap();
1686 if ( image )
1687 {
1688 wxGraphicsBitmap p;
1689 p.SetRefData(new wxGDIPlusBitmapData( this , image->Clone( (REAL) x , (REAL) y , (REAL) w , (REAL) h , PixelFormat32bppPARGB) ));
1690 return p;
1691 }
1692 else
1693 return wxNullGraphicsBitmap;
1694}
1695
385addaf
VZ
1696// Shutdown GDI+ at app exit, before possible dll unload
1697class wxGDIPlusRendererModule : public wxModule
1698{
1699public:
1700 virtual bool OnInit() { return true; }
1701 virtual void OnExit() { gs_GDIPlusRenderer.Unload(); }
1702
1703private:
1704 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule)
1705};
1706
1707IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule, wxModule)
1708
7ba86d93 1709#endif // wxUSE_GRAPHICS_CONTEXT