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