]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/graphics.cpp
preserve type when loaded image is rescaled, #11543
[wxWidgets.git] / src / msw / graphics.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/graphics.cpp
3// Purpose: wxGCDC class
4// Author: Stefan Csomor
5// Modified by:
6// Created: 2006-09-30
7// RCS-ID: $Id$
8// Copyright: (c) 2006 Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
18#include "wx/dc.h"
19
20#if wxUSE_GRAPHICS_CONTEXT
21
22#ifndef WX_PRECOMP
23 #include "wx/msw/wrapcdlg.h"
24 #include "wx/image.h"
25 #include "wx/window.h"
26 #include "wx/utils.h"
27 #include "wx/dialog.h"
28 #include "wx/app.h"
29 #include "wx/bitmap.h"
30 #include "wx/log.h"
31 #include "wx/icon.h"
32 #include "wx/module.h"
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"
38#endif
39
40#include "wx/private/graphics.h"
41#include "wx/msw/wrapgdip.h"
42#include "wx/msw/dc.h"
43#include "wx/dcgraph.h"
44
45#include "wx/stack.h"
46
47WX_DECLARE_STACK(GraphicsState, GraphicsStates);
48
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
87class wxGDIPlusPathData : public wxGraphicsPathData
88{
89public :
90 wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path = NULL);
91 ~wxGDIPlusPathData();
92
93 virtual wxGraphicsObjectRefData *Clone() const;
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
102 // adds a straight line from the current point to (x,y)
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
109 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
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
113 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
114
115 // adds another path
116 virtual void AddPath( const wxGraphicsPathData* path );
117
118 // closes the current sub-path
119 virtual void CloseSubpath();
120
121 //
122 // These are convenience functions which - if not available natively will be assembled
123 // using the primitives from above
124 //
125
126 // appends a rectangle as a new closed subpath
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
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 {}
142
143 // transforms each point of this path by the matrix
144 virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
145
146 // gets the bounding box enclosing all points (possibly including control points)
147 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
148
149 virtual bool Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxODDEVEN_RULE) const;
150
151private :
152 GraphicsPath* m_path;
153};
154
155class wxGDIPlusMatrixData : public wxGraphicsMatrixData
156{
157public :
158 wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix = NULL) ;
159 virtual ~wxGDIPlusMatrixData() ;
160
161 virtual wxGraphicsObjectRefData* Clone() const ;
162
163 // concatenates the matrix
164 virtual void Concat( const wxGraphicsMatrixData *t );
165
166 // sets the matrix to the respective values
167 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
168 wxDouble tx=0.0, wxDouble ty=0.0);
169
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;
173
174 // makes this the inverse matrix
175 virtual void Invert();
176
177 // returns true if the elements of the transformation matrix are equal ?
178 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
179
180 // return true if this is the identity matrix
181 virtual bool IsIdentity() const;
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)
194 virtual void Rotate( wxDouble angle );
195
196 //
197 // apply the transforms
198 //
199
200 // applies that matrix to the point
201 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
202
203 // applies the matrix except for translations
204 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
205
206 // returns the native representation
207 virtual void * GetNativeMatrix() const;
208private:
209 Matrix* m_matrix ;
210} ;
211
212class wxGDIPlusPenData : public wxGraphicsObjectRefData
213{
214public:
215 wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
216 ~wxGDIPlusPenData();
217
218 void Init();
219
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;
229};
230
231class wxGDIPlusBrushData : public wxGraphicsObjectRefData
232{
233public:
234 wxGDIPlusBrushData( wxGraphicsRenderer* renderer );
235 wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
236 ~wxGDIPlusBrushData ();
237
238 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
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;
251};
252
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
267class wxGDIPlusFontData : public wxGraphicsObjectRefData
268{
269public:
270 wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
271 ~wxGDIPlusFontData();
272
273 virtual Brush* GetGDIPlusBrush() { return m_textBrush; }
274 virtual Font* GetGDIPlusFont() { return m_font; }
275private :
276 Brush* m_textBrush;
277 Font* m_font;
278};
279
280class wxGDIPlusContext : public wxGraphicsContext
281{
282public:
283 wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc , wxDouble width, wxDouble height );
284 wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd );
285 wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr);
286 wxGDIPlusContext();
287
288 virtual ~wxGDIPlusContext();
289
290 virtual void Clip( const wxRegion &region );
291 // clips drawings to the rect
292 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
293
294 // resets the clipping to original extent
295 virtual void ResetClip();
296
297 virtual void * GetNativeContext();
298
299 virtual void StrokePath( const wxGraphicsPath& p );
300 virtual void FillPath( const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxODDEVEN_RULE );
301
302 // stroke lines connecting each of the points
303 virtual void StrokeLines( size_t n, const wxPoint2DDouble *points);
304
305 // draws a polygon
306 virtual void DrawLines( size_t n, const wxPoint2DDouble *points, wxPolygonFillMode fillStyle = wxODDEVEN_RULE );
307
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();
315
316 virtual void Translate( wxDouble dx , wxDouble dy );
317 virtual void Scale( wxDouble xScale , wxDouble yScale );
318 virtual void Rotate( wxDouble angle );
319
320 // concatenates this transform with the current transform of this context
321 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
322
323 // sets the transform of this context
324 virtual void SetTransform( const wxGraphicsMatrix& matrix );
325
326 // gets the matrix of this context
327 virtual wxGraphicsMatrix GetTransform() const;
328
329 virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
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 );
332 virtual void PushState();
333 virtual void PopState();
334
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;
338 virtual bool ShouldOffset() const;
339 virtual void GetSize( wxDouble* width, wxDouble *height );
340
341private:
342 void Init();
343 void SetDefaults();
344
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
350 Graphics* m_context;
351 GraphicsStates m_stateStack;
352 GraphicsState m_state1;
353 GraphicsState m_state2;
354
355 wxDouble m_width;
356 wxDouble m_height;
357
358 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext)
359};
360
361class wxGDIPlusMeasuringContext : public wxGDIPlusContext
362{
363public:
364 wxGDIPlusMeasuringContext( wxGraphicsRenderer* renderer ) : wxGDIPlusContext( renderer , m_hdc = GetDC(NULL), 1000, 1000 )
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
381//-----------------------------------------------------------------------------
382// wxGDIPlusPen implementation
383//-----------------------------------------------------------------------------
384
385wxGDIPlusPenData::~wxGDIPlusPenData()
386{
387 delete m_pen;
388 delete m_penImage;
389 delete m_penBrush;
390}
391
392void wxGDIPlusPenData::Init()
393{
394 m_pen = NULL ;
395 m_penImage = NULL;
396 m_penBrush = NULL;
397}
398
399wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
400: wxGraphicsObjectRefData(renderer)
401{
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;
536 }
537 if ( dashStyle != DashStyleSolid )
538 m_pen->SetDashStyle(dashStyle);
539}
540
541//-----------------------------------------------------------------------------
542// wxGDIPlusBrush implementation
543//-----------------------------------------------------------------------------
544
545wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer )
546: wxGraphicsObjectRefData(renderer)
547{
548 Init();
549}
550
551wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush )
552: wxGraphicsObjectRefData(renderer)
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 }
588 else
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
600wxGDIPlusBrushData::~wxGDIPlusBrushData()
601{
602 delete m_brush;
603 delete m_brushImage;
604 delete m_brushPath;
605};
606
607void wxGDIPlusBrushData::Init()
608{
609 m_brush = NULL;
610 m_brushImage= NULL;
611 m_brushPath= NULL;
612}
613
614void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
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
621void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
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
638//-----------------------------------------------------------------------------
639// wxGDIPlusFont implementation
640//-----------------------------------------------------------------------------
641
642wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font,
643 const wxColour& col ) : wxGraphicsObjectRefData( renderer )
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}
661
662wxGDIPlusFontData::~wxGDIPlusFontData()
663{
664 delete m_textBrush;
665 delete m_font;
666}
667
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
683wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer,
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
777//-----------------------------------------------------------------------------
778// wxGDIPlusPath implementation
779//-----------------------------------------------------------------------------
780
781wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path ) : wxGraphicsPathData(renderer)
782{
783 if ( path )
784 m_path = path;
785 else
786 m_path = new GraphicsPath();
787}
788
789wxGDIPlusPathData::~wxGDIPlusPathData()
790{
791 delete m_path;
792}
793
794wxGraphicsObjectRefData* wxGDIPlusPathData::Clone() const
795{
796 return new wxGDIPlusPathData( GetRenderer() , m_path->Clone());
797}
798
799//
800// The Primitives
801//
802
803void wxGDIPlusPathData::MoveToPoint( wxDouble x , wxDouble y )
804{
805 m_path->StartFigure();
806 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
807}
808
809void wxGDIPlusPathData::AddLineToPoint( wxDouble x , wxDouble y )
810{
811 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
812}
813
814void wxGDIPlusPathData::CloseSubpath()
815{
816 m_path->CloseFigure();
817}
818
819void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
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
830void wxGDIPlusPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
831{
832 PointF start;
833 m_path->GetLastPoint(&start);
834 *x = start.X ;
835 *y = start.Y ;
836}
837
838void wxGDIPlusPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
839{
840 double sweepAngle = endAngle - startAngle ;
841 if( fabs(sweepAngle) >= 2*M_PI)
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 }
859 m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle));
860}
861
862void wxGDIPlusPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
863{
864 m_path->AddRectangle(RectF(x,y,w,h));
865}
866
867void wxGDIPlusPathData::AddPath( const wxGraphicsPathData* path )
868{
869 m_path->AddPath( (GraphicsPath*) path->GetNativePath(), FALSE);
870}
871
872
873// transforms each point of this path by the matrix
874void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData* matrix )
875{
876 m_path->Transform( (Matrix*) matrix->GetNativeMatrix() );
877}
878
879// gets the bounding box enclosing all points (possibly including control points)
880void wxGDIPlusPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
881{
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;
888}
889
890bool wxGDIPlusPathData::Contains( wxDouble x, wxDouble y, wxPolygonFillMode fillStyle ) const
891{
892 m_path->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
893 return m_path->IsVisible( (FLOAT) x,(FLOAT) y) == TRUE ;
894}
895
896//-----------------------------------------------------------------------------
897// wxGDIPlusMatrixData implementation
898//-----------------------------------------------------------------------------
899
900wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix )
901 : wxGraphicsMatrixData(renderer)
902{
903 if ( matrix )
904 m_matrix = matrix ;
905 else
906 m_matrix = new Matrix();
907}
908
909wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
910{
911 delete m_matrix;
912}
913
914wxGraphicsObjectRefData *wxGDIPlusMatrixData::Clone() const
915{
916 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix->Clone());
917}
918
919// concatenates the matrix
920void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData *t )
921{
922 m_matrix->Multiply( (Matrix*) t->GetNativeMatrix());
923}
924
925// sets the matrix to the respective values
926void wxGDIPlusMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
927 wxDouble tx, wxDouble ty)
928{
929 m_matrix->SetElements(a,b,c,d,tx,ty);
930}
931
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
946// makes this the inverse matrix
947void wxGDIPlusMatrixData::Invert()
948{
949 m_matrix->Invert();
950}
951
952// returns true if the elements of the transformation matrix are equal ?
953bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
954{
955 return m_matrix->Equals((Matrix*) t->GetNativeMatrix())== TRUE ;
956}
957
958// return true if this is the identity matrix
959bool wxGDIPlusMatrixData::IsIdentity() const
960{
961 return m_matrix->IsIdentity() == TRUE ;
962}
963
964//
965// transformation
966//
967
968// add the translation to this matrix
969void wxGDIPlusMatrixData::Translate( wxDouble dx , wxDouble dy )
970{
971 m_matrix->Translate(dx,dy);
972}
973
974// add the scale to this matrix
975void wxGDIPlusMatrixData::Scale( wxDouble xScale , wxDouble yScale )
976{
977 m_matrix->Scale(xScale,yScale);
978}
979
980// add the rotation to this matrix (radians)
981void wxGDIPlusMatrixData::Rotate( wxDouble angle )
982{
983 m_matrix->Rotate( angle );
984}
985
986//
987// apply the transforms
988//
989
990// applies that matrix to the point
991void wxGDIPlusMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
992{
993 PointF pt(*x,*y);
994 m_matrix->TransformPoints(&pt);
995 *x = pt.X;
996 *y = pt.Y;
997}
998
999// applies the matrix except for translations
1000void wxGDIPlusMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
1001{
1002 PointF pt(*dx,*dy);
1003 m_matrix->TransformVectors(&pt);
1004 *dx = pt.X;
1005 *dy = pt.Y;
1006}
1007
1008// returns the native representation
1009void * wxGDIPlusMatrixData::GetNativeMatrix() const
1010{
1011 return m_matrix;
1012}
1013
1014//-----------------------------------------------------------------------------
1015// wxGDIPlusContext implementation
1016//-----------------------------------------------------------------------------
1017
1018IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
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} ;
1040
1041wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc, wxDouble width, wxDouble height )
1042 : wxGraphicsContext(renderer)
1043{
1044 Init();
1045 m_context = new Graphics( hdc);
1046 m_width = width;
1047 m_height = height;
1048 SetDefaults();
1049}
1050
1051wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd )
1052 : wxGraphicsContext(renderer)
1053{
1054 Init();
1055 m_context = new Graphics( hwnd);
1056 RECT rect = wxGetWindowRect(hwnd);
1057 m_width = rect.right - rect.left;
1058 m_height = rect.bottom - rect.top;
1059 SetDefaults();
1060}
1061
1062wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr )
1063 : wxGraphicsContext(renderer)
1064{
1065 Init();
1066 m_context = gr;
1067 SetDefaults();
1068}
1069
1070wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL)
1071{
1072 Init();
1073}
1074
1075void wxGDIPlusContext::Init()
1076{
1077 m_context = NULL;
1078 m_state1 = 0;
1079 m_state2= 0;
1080 m_height = 0;
1081 m_width = 0;
1082}
1083
1084void wxGDIPlusContext::SetDefaults()
1085{
1086 m_context->SetTextRenderingHint(TextRenderingHintSystemDefault);
1087 m_context->SetPixelOffsetMode(PixelOffsetModeHalf);
1088 m_context->SetSmoothingMode(SmoothingModeHighQuality);
1089 m_state1 = m_context->Save();
1090 m_state2 = m_context->Save();
1091}
1092
1093wxGDIPlusContext::~wxGDIPlusContext()
1094{
1095 if ( m_context )
1096 {
1097 m_context->Restore( m_state2 );
1098 m_context->Restore( m_state1 );
1099 delete m_context;
1100 }
1101}
1102
1103
1104void wxGDIPlusContext::Clip( const wxRegion &region )
1105{
1106 Region rgn((HRGN)region.GetHRGN());
1107 m_context->SetClip(&rgn,CombineModeIntersect);
1108}
1109
1110void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1111{
1112 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
1113}
1114
1115void wxGDIPlusContext::ResetClip()
1116{
1117 m_context->ResetClip();
1118}
1119
1120void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
1121{
1122 if (m_composition == wxCOMPOSITION_DEST)
1123 return;
1124
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 }
1138}
1139
1140void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, wxPolygonFillMode WXUNUSED(fillStyle) )
1141{
1142 if (m_composition == wxCOMPOSITION_DEST)
1143 return;
1144
1145 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
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;
1158}
1159
1160void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
1161{
1162 if (m_composition == wxCOMPOSITION_DEST)
1163 return;
1164
1165 if ( !m_pen.IsNull() )
1166 {
1167 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1168 m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
1169 }
1170}
1171
1172void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , wxPolygonFillMode fillStyle )
1173{
1174 if (m_composition == wxCOMPOSITION_DEST)
1175 return;
1176
1177 if ( !m_brush.IsNull() )
1178 {
1179 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1180 ((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
1181 m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
1182 (GraphicsPath*) path.GetNativePath());
1183 }
1184}
1185
1186bool wxGDIPlusContext::SetAntialiasMode(wxAntialiasMode antialias)
1187{
1188 if (m_antialias == antialias)
1189 return true;
1190
1191 m_antialias = antialias;
1192
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;
1213
1214 m_composition = op;
1215
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
1236void wxGDIPlusContext::BeginLayer(wxDouble /* opacity */)
1237{
1238 // TODO
1239}
1240
1241void wxGDIPlusContext::EndLayer()
1242{
1243 // TODO
1244}
1245
1246void wxGDIPlusContext::Rotate( wxDouble angle )
1247{
1248 m_context->RotateTransform( RadToDeg(angle) );
1249}
1250
1251void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
1252{
1253 m_context->TranslateTransform( dx , dy );
1254}
1255
1256void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
1257{
1258 m_context->ScaleTransform(xScale,yScale);
1259}
1260
1261void wxGDIPlusContext::PushState()
1262{
1263 GraphicsState state = m_context->Save();
1264 m_stateStack.push(state);
1265}
1266
1267void wxGDIPlusContext::PopState()
1268{
1269 GraphicsState state = m_stateStack.top();
1270 m_stateStack.pop();
1271 m_context->Restore(state);
1272}
1273
1274void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1275{
1276 if (m_composition == wxCOMPOSITION_DEST)
1277 return;
1278
1279 Bitmap* image = static_cast<wxGDIPlusBitmapData*>(bmp.GetRefData())->GetGDIPlusBitmap();
1280 if ( image )
1281 {
1282 if( image->GetWidth() != (UINT) w || image->GetHeight() != (UINT) h )
1283 {
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 );
1288 }
1289 else
1290 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
1291 }
1292}
1293
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);
1298}
1299
1300void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1301{
1302 if (m_composition == wxCOMPOSITION_DEST)
1303 return;
1304
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
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
1313 Bitmap interim(iconInfo.hbmColor,NULL);
1314
1315 Bitmap* image = NULL ;
1316
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
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);
1332
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 {
1346 image = new Bitmap(data.Width, data.Height, data.Stride,
1347 PixelFormat32bppARGB , (BYTE*) data.Scan0);
1348 }
1349 else
1350 {
1351 image = Bitmap::FromHICON(hIcon);
1352 }
1353
1354 interim.UnlockBits(&data);
1355 }
1356
1357 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
1358
1359 delete image ;
1360 DeleteObject(iconInfo.hbmColor);
1361 DeleteObject(iconInfo.hbmMask);
1362}
1363
1364void wxGDIPlusContext::DoDrawFilledText(const wxString& str,
1365 wxDouble x, wxDouble y,
1366 const wxGraphicsBrush& brush)
1367{
1368 if (m_composition == wxCOMPOSITION_DEST)
1369 return;
1370
1371 wxCHECK_RET( !m_font.IsNull(),
1372 wxT("wxGDIPlusContext::DrawText - no valid font set") );
1373
1374 if ( str.IsEmpty())
1375 return ;
1376
1377 wxGDIPlusFontData * const
1378 fontData = (wxGDIPlusFontData *)m_font.GetRefData();
1379 wxGDIPlusBrushData * const
1380 brushData = (wxGDIPlusBrushData *)brush.GetRefData();
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 );
1392}
1393
1394void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1395 wxDouble *descent, wxDouble *externalLeading ) const
1396{
1397 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1398
1399 wxWCharBuffer s = str.wc_str( *wxConvUI );
1400 FontFamily ffamily ;
1401 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
1402
1403 f->GetFamily(&ffamily) ;
1404
1405 REAL factorY = m_context->GetDpiY() / 72.0 ;
1406
1407 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
1408 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1409 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
1410 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1411 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
1412 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1413
1414 if ( height )
1415 *height = rHeight * factorY;
1416 if ( descent )
1417 *descent = rDescent * factorY;
1418 if ( externalLeading )
1419 *externalLeading = (rHeight - rAscent - rDescent) * factorY;
1420 // measuring empty strings is not guaranteed, so do it by hand
1421 if ( str.IsEmpty())
1422 {
1423 if ( width )
1424 *width = 0 ;
1425 }
1426 else
1427 {
1428 RectF layoutRect(0,0, 100000.0f, 100000.0f);
1429 StringFormat strFormat( StringFormat::GenericTypographic() );
1430 strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
1431
1432 RectF bounds ;
1433 m_context->MeasureString((const wchar_t *) s , wcslen(s) , f, layoutRect, &strFormat, &bounds ) ;
1434 if ( width )
1435 *width = bounds.Width;
1436 }
1437}
1438
1439void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
1440{
1441 widths.Empty();
1442 widths.Add(0, text.length());
1443
1444 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1445
1446 if (text.empty())
1447 return;
1448
1449 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
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);
1455 StringFormat strFormat( StringFormat::GenericTypographic() );
1456
1457 size_t startPosition = 0;
1458 size_t remainder = len;
1459 const size_t maxSpan = 32;
1460 CharacterRange* ranges = new CharacterRange[maxSpan] ;
1461 Region* regions = new Region[maxSpan];
1462
1463 while( remainder > 0 )
1464 {
1465 size_t span = wxMin( maxSpan, remainder );
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 }
1482 remainder -= span;
1483 startPosition += span;
1484 }
1485
1486 delete[] ranges;
1487 delete[] regions;
1488}
1489
1490bool wxGDIPlusContext::ShouldOffset() const
1491{
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
1502void* wxGDIPlusContext::GetNativeContext()
1503{
1504 return m_context;
1505}
1506
1507// concatenates this transform with the current transform of this context
1508void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
1509{
1510 m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
1511}
1512
1513// sets the transform of this context
1514void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
1515{
1516 m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
1517}
1518
1519// gets the matrix of this context
1520wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
1521{
1522 wxGraphicsMatrix matrix = CreateMatrix();
1523 m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1524 return matrix;
1525}
1526
1527void wxGDIPlusContext::GetSize( wxDouble* width, wxDouble *height )
1528{
1529 *width = m_width;
1530 *height = m_height;
1531}
1532//-----------------------------------------------------------------------------
1533// wxGDIPlusRenderer declaration
1534//-----------------------------------------------------------------------------
1535
1536class wxGDIPlusRenderer : public wxGraphicsRenderer
1537{
1538public :
1539 wxGDIPlusRenderer()
1540 {
1541 m_loaded = -1;
1542 m_gditoken = 0;
1543 }
1544
1545 virtual ~wxGDIPlusRenderer()
1546 {
1547 if ( m_loaded == 1 )
1548 {
1549 Unload();
1550 }
1551 }
1552
1553 // Context
1554
1555 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1556
1557 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
1558
1559 virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc);
1560
1561 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1562
1563 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1564
1565 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1566
1567 virtual wxGraphicsContext * CreateMeasuringContext();
1568
1569 // Path
1570
1571 virtual wxGraphicsPath CreatePath();
1572
1573 // Matrix
1574
1575 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
1576 wxDouble tx=0.0, wxDouble ty=0.0);
1577
1578
1579 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
1580
1581 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
1582
1583 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1584 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1585 const wxColour&c1, const wxColour&c2) ;
1586
1587 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1588 // with radius r and color cColor
1589 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
1590 const wxColour &oColor, const wxColour &cColor) ;
1591
1592 // sets the font
1593 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
1594
1595 // create a native bitmap representation
1596 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
1597
1598 // create a graphics bitmap from a native bitmap
1599 virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
1600
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
1604protected :
1605 bool EnsureIsLoaded();
1606 void Load();
1607 void Unload();
1608 friend class wxGDIPlusRendererModule;
1609
1610private :
1611 int m_loaded;
1612 ULONG_PTR m_gditoken;
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
1630bool wxGDIPlusRenderer::EnsureIsLoaded()
1631{
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 )
1637 {
1638 Load();
1639 }
1640
1641 return m_loaded == 1;
1642}
1643
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
1650void wxGDIPlusRenderer::Load()
1651{
1652 GdiplusStartupInput input;
1653 GdiplusStartupOutput output;
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 }
1664}
1665
1666void wxGDIPlusRenderer::Unload()
1667{
1668 if ( m_gditoken )
1669 {
1670 GdiplusShutdown(m_gditoken);
1671 m_gditoken = NULL;
1672 }
1673 m_loaded = -1; // next Load() will try again
1674}
1675
1676wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1677{
1678 ENSURE_LOADED_OR_RETURN(NULL);
1679 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
1680 wxSize sz = dc.GetSize();
1681 return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
1682}
1683
1684wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxPrinterDC& dc)
1685{
1686 ENSURE_LOADED_OR_RETURN(NULL);
1687 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
1688 wxSize sz = dc.GetSize();
1689 return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
1690}
1691
1692wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc)
1693{
1694 ENSURE_LOADED_OR_RETURN(NULL);
1695 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
1696 wxSize sz = dc.GetSize();
1697 return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
1698}
1699
1700wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
1701{
1702 ENSURE_LOADED_OR_RETURN(NULL);
1703 return new wxGDIPlusMeasuringContext(this);
1704}
1705
1706wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1707{
1708 ENSURE_LOADED_OR_RETURN(NULL);
1709 return new wxGDIPlusContext(this,(Graphics*) context);
1710}
1711
1712
1713wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1714{
1715 ENSURE_LOADED_OR_RETURN(NULL);
1716 return new wxGDIPlusContext(this,(HWND) window);
1717}
1718
1719wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1720{
1721 ENSURE_LOADED_OR_RETURN(NULL);
1722 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1723}
1724
1725// Path
1726
1727wxGraphicsPath wxGDIPlusRenderer::CreatePath()
1728{
1729 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath);
1730 wxGraphicsPath m;
1731 m.SetRefData( new wxGDIPlusPathData(this));
1732 return m;
1733}
1734
1735
1736// Matrix
1737
1738wxGraphicsMatrix wxGDIPlusRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
1739 wxDouble tx, wxDouble ty)
1740
1741{
1742 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix);
1743 wxGraphicsMatrix m;
1744 wxGDIPlusMatrixData* data = new wxGDIPlusMatrixData( this );
1745 data->Set( a,b,c,d,tx,ty ) ;
1746 m.SetRefData(data);
1747 return m;
1748}
1749
1750wxGraphicsPen wxGDIPlusRenderer::CreatePen(const wxPen& pen)
1751{
1752 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen);
1753 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
1754 return wxNullGraphicsPen;
1755 else
1756 {
1757 wxGraphicsPen p;
1758 p.SetRefData(new wxGDIPlusPenData( this, pen ));
1759 return p;
1760 }
1761}
1762
1763wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
1764{
1765 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
1766 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
1767 return wxNullGraphicsBrush;
1768 else
1769 {
1770 wxGraphicsBrush p;
1771 p.SetRefData(new wxGDIPlusBrushData( this, brush ));
1772 return p;
1773 }
1774}
1775
1776// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1777wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1778 const wxColour&c1, const wxColour&c2)
1779{
1780 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
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 }
1787
1788// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1789// with radius r and color cColor
1790wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
1791 const wxColour &oColor, const wxColour &cColor)
1792{
1793 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
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;
1799}
1800
1801// sets the font
1802wxGraphicsFont wxGDIPlusRenderer::CreateFont( const wxFont &font , const wxColour &col )
1803{
1804 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
1805 if ( font.Ok() )
1806 {
1807 wxGraphicsFont p;
1808 p.SetRefData(new wxGDIPlusFontData( this , font, col ));
1809 return p;
1810 }
1811 else
1812 return wxNullGraphicsFont;
1813}
1814
1815wxGraphicsBitmap wxGDIPlusRenderer::CreateBitmap( const wxBitmap &bitmap )
1816{
1817 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
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
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
1841wxGraphicsBitmap wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1842{
1843 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
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
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
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
1896#endif // wxUSE_GRAPHICS_CONTEXT