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