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 ®ion );
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 ®ion )
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