]> git.saurik.com Git - wxWidgets.git/blob - src/msw/graphics.cpp
Forward port 2.8 fix.
[wxWidgets.git] / src / msw / graphics.cpp
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
47 WX_DECLARE_STACK(GraphicsState, GraphicsStates);
48
49 //-----------------------------------------------------------------------------
50 // constants
51 //-----------------------------------------------------------------------------
52
53 const double RAD2DEG = 180.0 / M_PI;
54
55 //-----------------------------------------------------------------------------
56 // Local functions
57 //-----------------------------------------------------------------------------
58
59 static inline double dmin(double a, double b) { return a < b ? a : b; }
60 static inline double dmax(double a, double b) { return a > b ? a : b; }
61
62 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
63 static 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
87 class wxGDIPlusPathData : public wxGraphicsPathData
88 {
89 public :
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
151 private :
152 GraphicsPath* m_path;
153 };
154
155 class wxGDIPlusMatrixData : public wxGraphicsMatrixData
156 {
157 public :
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;
208 private:
209 Matrix* m_matrix ;
210 } ;
211
212 class wxGDIPlusPenData : public wxGraphicsObjectRefData
213 {
214 public:
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
223 protected :
224 Pen* m_pen;
225 Image* m_penImage;
226 Brush* m_penBrush;
227
228 wxDouble m_width;
229 };
230
231 class wxGDIPlusBrushData : public wxGraphicsObjectRefData
232 {
233 public:
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
244 protected:
245 virtual void Init();
246
247 private :
248 Brush* m_brush;
249 Image* m_brushImage;
250 GraphicsPath* m_brushPath;
251 };
252
253 class WXDLLIMPEXP_CORE wxGDIPlusBitmapData : public wxGraphicsObjectRefData
254 {
255 public:
256 wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, Bitmap* bitmap );
257 wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, const wxBitmap &bmp );
258 ~wxGDIPlusBitmapData ();
259
260 virtual Bitmap* GetGDIPlusBitmap() { return m_bitmap; }
261
262 private :
263 Bitmap* m_bitmap;
264 Bitmap* m_helper;
265 };
266
267 class wxGDIPlusFontData : public wxGraphicsObjectRefData
268 {
269 public:
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; }
275 private :
276 Brush* m_textBrush;
277 Font* m_font;
278 };
279
280 class wxGDIPlusContext : public wxGraphicsContext
281 {
282 public:
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
341 private:
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
361 class wxGDIPlusMeasuringContext : public wxGDIPlusContext
362 {
363 public:
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
376 private:
377 HDC m_hdc ;
378 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMeasuringContext)
379 } ;
380
381 //-----------------------------------------------------------------------------
382 // wxGDIPlusPen implementation
383 //-----------------------------------------------------------------------------
384
385 wxGDIPlusPenData::~wxGDIPlusPenData()
386 {
387 delete m_pen;
388 delete m_penImage;
389 delete m_penBrush;
390 }
391
392 void wxGDIPlusPenData::Init()
393 {
394 m_pen = NULL ;
395 m_penImage = NULL;
396 m_penBrush = NULL;
397 }
398
399 wxGDIPlusPenData::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
545 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer )
546 : wxGraphicsObjectRefData(renderer)
547 {
548 Init();
549 }
550
551 wxGDIPlusBrushData::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
600 wxGDIPlusBrushData::~wxGDIPlusBrushData()
601 {
602 delete m_brush;
603 delete m_brushImage;
604 delete m_brushPath;
605 };
606
607 void wxGDIPlusBrushData::Init()
608 {
609 m_brush = NULL;
610 m_brushImage= NULL;
611 m_brushPath= NULL;
612 }
613
614 void 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
621 void 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
642 wxGDIPlusFontData::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
662 wxGDIPlusFontData::~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
677 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, Bitmap* bitmap ) :
678 wxGraphicsObjectRefData( renderer ), m_bitmap( bitmap )
679 {
680 m_helper = NULL;
681 }
682
683 wxGDIPlusBitmapData::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
771 wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
772 {
773 delete m_bitmap;
774 delete m_helper;
775 }
776
777 //-----------------------------------------------------------------------------
778 // wxGDIPlusPath implementation
779 //-----------------------------------------------------------------------------
780
781 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path ) : wxGraphicsPathData(renderer)
782 {
783 if ( path )
784 m_path = path;
785 else
786 m_path = new GraphicsPath();
787 }
788
789 wxGDIPlusPathData::~wxGDIPlusPathData()
790 {
791 delete m_path;
792 }
793
794 wxGraphicsObjectRefData* wxGDIPlusPathData::Clone() const
795 {
796 return new wxGDIPlusPathData( GetRenderer() , m_path->Clone());
797 }
798
799 //
800 // The Primitives
801 //
802
803 void 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
809 void wxGDIPlusPathData::AddLineToPoint( wxDouble x , wxDouble y )
810 {
811 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
812 }
813
814 void wxGDIPlusPathData::CloseSubpath()
815 {
816 m_path->CloseFigure();
817 }
818
819 void 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
830 void 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
838 void 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
862 void wxGDIPlusPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
863 {
864 m_path->AddRectangle(RectF(x,y,w,h));
865 }
866
867 void 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
874 void 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)
880 void 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
890 bool 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
900 wxGDIPlusMatrixData::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
909 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
910 {
911 delete m_matrix;
912 }
913
914 wxGraphicsObjectRefData *wxGDIPlusMatrixData::Clone() const
915 {
916 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix->Clone());
917 }
918
919 // concatenates the matrix
920 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData *t )
921 {
922 m_matrix->Multiply( (Matrix*) t->GetNativeMatrix());
923 }
924
925 // sets the matrix to the respective values
926 void 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
933 void 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
947 void wxGDIPlusMatrixData::Invert()
948 {
949 m_matrix->Invert();
950 }
951
952 // returns true if the elements of the transformation matrix are equal ?
953 bool 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
959 bool wxGDIPlusMatrixData::IsIdentity() const
960 {
961 return m_matrix->IsIdentity() == TRUE ;
962 }
963
964 //
965 // transformation
966 //
967
968 // add the translation to this matrix
969 void wxGDIPlusMatrixData::Translate( wxDouble dx , wxDouble dy )
970 {
971 m_matrix->Translate(dx,dy);
972 }
973
974 // add the scale to this matrix
975 void wxGDIPlusMatrixData::Scale( wxDouble xScale , wxDouble yScale )
976 {
977 m_matrix->Scale(xScale,yScale);
978 }
979
980 // add the rotation to this matrix (radians)
981 void 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
991 void 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
1000 void 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
1009 void * wxGDIPlusMatrixData::GetNativeMatrix() const
1010 {
1011 return m_matrix;
1012 }
1013
1014 //-----------------------------------------------------------------------------
1015 // wxGDIPlusContext implementation
1016 //-----------------------------------------------------------------------------
1017
1018 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
1019 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMeasuringContext,wxGDIPlusContext)
1020
1021 class wxGDIPlusOffsetHelper
1022 {
1023 public :
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 }
1036 public :
1037 Graphics* m_gr;
1038 bool m_offset;
1039 } ;
1040
1041 wxGDIPlusContext::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
1051 wxGDIPlusContext::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
1062 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr )
1063 : wxGraphicsContext(renderer)
1064 {
1065 Init();
1066 m_context = gr;
1067 SetDefaults();
1068 }
1069
1070 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL)
1071 {
1072 Init();
1073 }
1074
1075 void 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
1084 void 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
1093 wxGDIPlusContext::~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
1104 void wxGDIPlusContext::Clip( const wxRegion &region )
1105 {
1106 Region rgn((HRGN)region.GetHRGN());
1107 m_context->SetClip(&rgn,CombineModeIntersect);
1108 }
1109
1110 void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1111 {
1112 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
1113 }
1114
1115 void wxGDIPlusContext::ResetClip()
1116 {
1117 m_context->ResetClip();
1118 }
1119
1120 void 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
1140 void 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
1160 void 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
1172 void 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
1186 bool 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
1209 bool 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
1236 void wxGDIPlusContext::BeginLayer(wxDouble /* opacity */)
1237 {
1238 // TODO
1239 }
1240
1241 void wxGDIPlusContext::EndLayer()
1242 {
1243 // TODO
1244 }
1245
1246 void wxGDIPlusContext::Rotate( wxDouble angle )
1247 {
1248 m_context->RotateTransform( RadToDeg(angle) );
1249 }
1250
1251 void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
1252 {
1253 m_context->TranslateTransform( dx , dy );
1254 }
1255
1256 void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
1257 {
1258 m_context->ScaleTransform(xScale,yScale);
1259 }
1260
1261 void wxGDIPlusContext::PushState()
1262 {
1263 GraphicsState state = m_context->Save();
1264 m_stateStack.push(state);
1265 }
1266
1267 void wxGDIPlusContext::PopState()
1268 {
1269 GraphicsState state = m_stateStack.top();
1270 m_stateStack.pop();
1271 m_context->Restore(state);
1272 }
1273
1274 void 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
1294 void 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
1300 void 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
1364 void 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
1394 void 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
1439 void 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
1490 bool 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
1502 void* wxGDIPlusContext::GetNativeContext()
1503 {
1504 return m_context;
1505 }
1506
1507 // concatenates this transform with the current transform of this context
1508 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
1509 {
1510 m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
1511 }
1512
1513 // sets the transform of this context
1514 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
1515 {
1516 m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
1517 }
1518
1519 // gets the matrix of this context
1520 wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
1521 {
1522 wxGraphicsMatrix matrix = CreateMatrix();
1523 m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1524 return matrix;
1525 }
1526
1527 void wxGDIPlusContext::GetSize( wxDouble* width, wxDouble *height )
1528 {
1529 *width = m_width;
1530 *height = m_height;
1531 }
1532 //-----------------------------------------------------------------------------
1533 // wxGDIPlusRenderer declaration
1534 //-----------------------------------------------------------------------------
1535
1536 class wxGDIPlusRenderer : public wxGraphicsRenderer
1537 {
1538 public :
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
1604 protected :
1605 bool EnsureIsLoaded();
1606 void Load();
1607 void Unload();
1608 friend class wxGDIPlusRendererModule;
1609
1610 private :
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
1621 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1622
1623 static wxGDIPlusRenderer gs_GDIPlusRenderer;
1624
1625 wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1626 {
1627 return &gs_GDIPlusRenderer;
1628 }
1629
1630 bool 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
1650 void 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
1666 void 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
1676 wxGraphicsContext * 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
1684 wxGraphicsContext * 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
1692 wxGraphicsContext * 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
1700 wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
1701 {
1702 ENSURE_LOADED_OR_RETURN(NULL);
1703 return new wxGDIPlusMeasuringContext(this);
1704 }
1705
1706 wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1707 {
1708 ENSURE_LOADED_OR_RETURN(NULL);
1709 return new wxGDIPlusContext(this,(Graphics*) context);
1710 }
1711
1712
1713 wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1714 {
1715 ENSURE_LOADED_OR_RETURN(NULL);
1716 return new wxGDIPlusContext(this,(HWND) window);
1717 }
1718
1719 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1720 {
1721 ENSURE_LOADED_OR_RETURN(NULL);
1722 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1723 }
1724
1725 // Path
1726
1727 wxGraphicsPath 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
1738 wxGraphicsMatrix 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
1750 wxGraphicsPen 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
1763 wxGraphicsBrush 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
1777 wxGraphicsBrush 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
1790 wxGraphicsBrush 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
1802 wxGraphicsFont 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
1815 wxGraphicsBitmap 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
1828 wxGraphicsBitmap 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
1841 wxGraphicsBitmap 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
1856 class wxGDIPlusRendererModule : public wxModule
1857 {
1858 public:
1859 virtual bool OnInit() { return true; }
1860 virtual void OnExit() { gs_GDIPlusRenderer.Unload(); }
1861
1862 private:
1863 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule)
1864 };
1865
1866 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule, wxModule)
1867
1868 // ----------------------------------------------------------------------------
1869 // wxMSW-specific parts of wxGCDC
1870 // ----------------------------------------------------------------------------
1871
1872 WXHDC 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
1882 void 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