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