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