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