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