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