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