1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/graphics.cpp
3 // Purpose: wxGCDC class
4 // Author: Stefan Csomor
7 // Copyright: (c) 2006 Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
19 #if wxUSE_GRAPHICS_CONTEXT
22 #include "wx/msw/wrapcdlg.h"
24 #include "wx/window.h"
26 #include "wx/dialog.h"
28 #include "wx/bitmap.h"
31 #include "wx/module.h"
32 // include all dc types that are used as a param
34 #include "wx/dcclient.h"
35 #include "wx/dcmemory.h"
36 #include "wx/dcprint.h"
41 #include "wx/private/graphics.h"
42 #include "wx/msw/wrapgdip.h"
43 #include "wx/msw/dc.h"
44 #if wxUSE_ENH_METAFILE
45 #include "wx/msw/enhmeta.h"
47 #include "wx/dcgraph.h"
49 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
51 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
58 //-----------------------------------------------------------------------------
60 //-----------------------------------------------------------------------------
62 const double RAD2DEG
= 180.0 / M_PI
;
64 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
68 inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
69 inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
71 inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
72 inline double RadToDeg(double deg
) { return (deg
* 180.0) / M_PI
; }
74 // translate a wxColour to a Color
75 inline Color
wxColourToColor(const wxColour
& col
)
77 return Color(col
.Alpha(), col
.Red(), col
.Green(), col
.Blue());
80 // Do not use this pointer directly, it's only used by
81 // GetDrawTextStringFormat() and the cleanup code in wxGDIPlusRendererModule.
82 StringFormat
* gs_drawTextStringFormat
= NULL
;
84 // Get the string format used for the text drawing and measuring functions:
85 // notice that it must be the same one for all of them, otherwise the drawn
86 // text might be of different size than what measuring it returned.
87 inline StringFormat
* GetDrawTextStringFormat()
89 if ( !gs_drawTextStringFormat
)
91 gs_drawTextStringFormat
= new StringFormat(StringFormat::GenericTypographic());
93 // This doesn't make any difference for DrawText() actually but we want
94 // this behaviour when measuring text.
95 gs_drawTextStringFormat
->SetFormatFlags
97 gs_drawTextStringFormat
->GetFormatFlags()
98 | StringFormatFlagsMeasureTrailingSpaces
102 return gs_drawTextStringFormat
;
105 } // anonymous namespace
107 //-----------------------------------------------------------------------------
108 // device context implementation
110 // more and more of the dc functionality should be implemented by calling
111 // the appropricate wxGDIPlusContext, but we will have to do that step by step
112 // also coordinate conversions should be moved to native matrix ops
113 //-----------------------------------------------------------------------------
115 // we always stock two context states, one at entry, to be able to preserve the
116 // state we were called with, the other one after changing to HI Graphics orientation
117 // (this one is used for getting back clippings etc)
119 //-----------------------------------------------------------------------------
120 // wxGraphicsPath implementation
121 //-----------------------------------------------------------------------------
123 class wxGDIPlusContext
;
125 class wxGDIPlusPathData
: public wxGraphicsPathData
128 wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
= NULL
);
129 ~wxGDIPlusPathData();
131 virtual wxGraphicsObjectRefData
*Clone() const;
134 // These are the path primitives from which everything else can be constructed
137 // begins a new subpath at (x,y)
138 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
140 // adds a straight line from the current point to (x,y)
141 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
143 // adds a cubic Bezier curve from the current point, using two control points and an end point
144 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
147 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
148 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
150 // gets the last point of the current path, (0,0) if not yet set
151 virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const;
154 virtual void AddPath( const wxGraphicsPathData
* path
);
156 // closes the current sub-path
157 virtual void CloseSubpath();
160 // These are convenience functions which - if not available natively will be assembled
161 // using the primitives from above
164 // appends a rectangle as a new closed subpath
165 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
168 // appends an ellipsis as a new closed subpath fitting the passed rectangle
169 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
171 // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
172 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
175 // returns the native path
176 virtual void * GetNativePath() const { return m_path
; }
178 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
179 virtual void UnGetNativePath(void * WXUNUSED(path
)) const {}
181 // transforms each point of this path by the matrix
182 virtual void Transform( const wxGraphicsMatrixData
* matrix
) ;
184 // gets the bounding box enclosing all points (possibly including control points)
185 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const;
187 virtual bool Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
) const;
190 GraphicsPath
* m_path
;
193 class wxGDIPlusMatrixData
: public wxGraphicsMatrixData
196 wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
= NULL
) ;
197 virtual ~wxGDIPlusMatrixData() ;
199 virtual wxGraphicsObjectRefData
* Clone() const ;
201 // concatenates the matrix
202 virtual void Concat( const wxGraphicsMatrixData
*t
);
204 // sets the matrix to the respective values
205 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
206 wxDouble tx
=0.0, wxDouble ty
=0.0);
208 // gets the component valuess of the matrix
209 virtual void Get(wxDouble
* a
=NULL
, wxDouble
* b
=NULL
, wxDouble
* c
=NULL
,
210 wxDouble
* d
=NULL
, wxDouble
* tx
=NULL
, wxDouble
* ty
=NULL
) const;
212 // makes this the inverse matrix
213 virtual void Invert();
215 // returns true if the elements of the transformation matrix are equal ?
216 virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ;
218 // return true if this is the identity matrix
219 virtual bool IsIdentity() const;
225 // add the translation to this matrix
226 virtual void Translate( wxDouble dx
, wxDouble dy
);
228 // add the scale to this matrix
229 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
231 // add the rotation to this matrix (radians)
232 virtual void Rotate( wxDouble angle
);
235 // apply the transforms
238 // applies that matrix to the point
239 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
) const;
241 // applies the matrix except for translations
242 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const;
244 // returns the native representation
245 virtual void * GetNativeMatrix() const;
250 class wxGDIPlusPenData
: public wxGraphicsObjectRefData
253 wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
258 virtual wxDouble
GetWidth() { return m_width
; }
259 virtual Pen
* GetGDIPlusPen() { return m_pen
; }
269 class wxGDIPlusBrushData
: public wxGraphicsObjectRefData
272 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
);
273 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
274 ~wxGDIPlusBrushData ();
276 void CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
277 wxDouble x2
, wxDouble y2
,
278 const wxGraphicsGradientStops
& stops
);
279 void CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
280 wxDouble xc
, wxDouble yc
,
282 const wxGraphicsGradientStops
& stops
);
284 virtual Brush
* GetGDIPlusBrush() { return m_brush
; }
290 // common part of Create{Linear,Radial}GradientBrush()
291 template <typename T
>
292 void SetGradientStops(T
*brush
, const wxGraphicsGradientStops
& stops
);
296 GraphicsPath
* m_brushPath
;
299 class WXDLLIMPEXP_CORE wxGDIPlusBitmapData
: public wxGraphicsBitmapData
302 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
);
303 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, const wxBitmap
&bmp
);
304 ~wxGDIPlusBitmapData ();
306 virtual Bitmap
* GetGDIPlusBitmap() { return m_bitmap
; }
307 virtual void* GetNativeBitmap() const { return m_bitmap
; }
310 wxImage
ConvertToImage() const;
311 #endif // wxUSE_IMAGE
318 class wxGDIPlusFontData
: public wxGraphicsObjectRefData
321 wxGDIPlusFontData( wxGraphicsRenderer
* renderer
,
323 const wxColour
& col
);
324 wxGDIPlusFontData(wxGraphicsRenderer
* renderer
,
325 const wxString
& name
,
328 const wxColour
& col
);
329 ~wxGDIPlusFontData();
331 virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; }
332 virtual Font
* GetGDIPlusFont() { return m_font
; }
335 // Common part of all ctors, flags here is a combination of values of
336 // FontStyle GDI+ enum.
337 void Init(const wxString
& name
,
347 class wxGDIPlusContext
: public wxGraphicsContext
350 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, const wxDC
& dc
);
351 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
);
352 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
);
353 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
);
354 wxGDIPlusContext(wxGraphicsRenderer
* renderer
);
356 virtual ~wxGDIPlusContext();
358 virtual void Clip( const wxRegion
®ion
);
359 // clips drawings to the rect
360 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
362 // resets the clipping to original extent
363 virtual void ResetClip();
365 virtual void * GetNativeContext();
367 virtual void StrokePath( const wxGraphicsPath
& p
);
368 virtual void FillPath( const wxGraphicsPath
& p
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
370 virtual void DrawRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
372 // stroke lines connecting each of the points
373 virtual void StrokeLines( size_t n
, const wxPoint2DDouble
*points
);
375 // We don't have any specific implementation for this one in wxMSW but
376 // override it just to avoid warnings about hiding the base class virtual.
377 virtual void StrokeLines( size_t n
, const wxPoint2DDouble
*beginPoints
, const wxPoint2DDouble
*endPoints
)
379 wxGraphicsContext::StrokeLines(n
, beginPoints
, endPoints
);
383 virtual void DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
385 virtual bool SetAntialiasMode(wxAntialiasMode antialias
);
387 virtual bool SetInterpolationQuality(wxInterpolationQuality interpolation
);
389 virtual bool SetCompositionMode(wxCompositionMode op
);
391 virtual void BeginLayer(wxDouble opacity
);
393 virtual void EndLayer();
395 virtual void Translate( wxDouble dx
, wxDouble dy
);
396 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
397 virtual void Rotate( wxDouble angle
);
399 // concatenates this transform with the current transform of this context
400 virtual void ConcatTransform( const wxGraphicsMatrix
& matrix
);
402 // sets the transform of this context
403 virtual void SetTransform( const wxGraphicsMatrix
& matrix
);
405 // gets the matrix of this context
406 virtual wxGraphicsMatrix
GetTransform() const;
408 virtual void DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
409 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
410 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
411 virtual void PushState();
412 virtual void PopState();
414 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
415 wxDouble
*descent
, wxDouble
*externalLeading
) const;
416 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
417 virtual bool ShouldOffset() const;
418 virtual void GetSize( wxDouble
* width
, wxDouble
*height
);
420 Graphics
* GetGraphics() const { return m_context
; }
424 wxDouble m_fontScaleRatio
;
426 // Used from ctors (including those in the derived classes) and takes
427 // ownership of the graphics pointer that must be non-NULL.
428 void Init(Graphics
* graphics
, int width
, int height
);
431 virtual void DoDrawText(const wxString
& str
, wxDouble x
, wxDouble y
);
434 wxStack
<GraphicsState
> m_stateStack
;
435 GraphicsState m_state1
;
436 GraphicsState m_state2
;
438 wxDECLARE_NO_COPY_CLASS(wxGDIPlusContext
);
443 class wxGDIPlusImageContext
: public wxGDIPlusContext
446 wxGDIPlusImageContext(wxGraphicsRenderer
* renderer
, wxImage
& image
) :
447 wxGDIPlusContext(renderer
),
449 m_bitmap(renderer
, image
)
453 new Graphics(m_bitmap
.GetGDIPlusBitmap()),
459 virtual ~wxGDIPlusImageContext()
461 m_image
= m_bitmap
.ConvertToImage();
466 wxGDIPlusBitmapData m_bitmap
;
468 wxDECLARE_NO_COPY_CLASS(wxGDIPlusImageContext
);
471 #endif // wxUSE_IMAGE
473 class wxGDIPlusMeasuringContext
: public wxGDIPlusContext
476 wxGDIPlusMeasuringContext( wxGraphicsRenderer
* renderer
) : wxGDIPlusContext( renderer
, m_hdc
= GetDC(NULL
), 1000, 1000 )
480 virtual ~wxGDIPlusMeasuringContext()
482 ReleaseDC( NULL
, m_hdc
);
489 class wxGDIPlusPrintingContext
: public wxGDIPlusContext
492 wxGDIPlusPrintingContext( wxGraphicsRenderer
* renderer
, const wxDC
& dc
);
493 virtual ~wxGDIPlusPrintingContext() { }
497 //-----------------------------------------------------------------------------
498 // wxGDIPlusRenderer declaration
499 //-----------------------------------------------------------------------------
501 class wxGDIPlusRenderer
: public wxGraphicsRenderer
510 virtual ~wxGDIPlusRenderer()
520 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
522 virtual wxGraphicsContext
* CreateContext( const wxMemoryDC
& dc
);
524 #if wxUSE_PRINTING_ARCHITECTURE
525 virtual wxGraphicsContext
* CreateContext( const wxPrinterDC
& dc
);
528 #if wxUSE_ENH_METAFILE
529 virtual wxGraphicsContext
* CreateContext( const wxEnhMetaFileDC
& dc
);
532 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
534 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
536 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
539 virtual wxGraphicsContext
* CreateContextFromImage(wxImage
& image
);
540 #endif // wxUSE_IMAGE
542 virtual wxGraphicsContext
* CreateMeasuringContext();
546 virtual wxGraphicsPath
CreatePath();
550 virtual wxGraphicsMatrix
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
551 wxDouble tx
=0.0, wxDouble ty
=0.0);
554 virtual wxGraphicsPen
CreatePen(const wxPen
& pen
) ;
556 virtual wxGraphicsBrush
CreateBrush(const wxBrush
& brush
) ;
558 virtual wxGraphicsBrush
559 CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
560 wxDouble x2
, wxDouble y2
,
561 const wxGraphicsGradientStops
& stops
);
563 virtual wxGraphicsBrush
564 CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
565 wxDouble xc
, wxDouble yc
,
567 const wxGraphicsGradientStops
& stops
);
569 // create a native bitmap representation
570 virtual wxGraphicsBitmap
CreateBitmap( const wxBitmap
&bitmap
);
572 virtual wxGraphicsBitmap
CreateBitmapFromImage(const wxImage
& image
);
573 virtual wxImage
CreateImageFromBitmap(const wxGraphicsBitmap
& bmp
);
574 #endif // wxUSE_IMAGE
576 virtual wxGraphicsFont
CreateFont( const wxFont
& font
,
577 const wxColour
& col
);
579 virtual wxGraphicsFont
CreateFont(double size
,
580 const wxString
& facename
,
581 int flags
= wxFONTFLAG_DEFAULT
,
582 const wxColour
& col
= *wxBLACK
);
584 // create a graphics bitmap from a native bitmap
585 virtual wxGraphicsBitmap
CreateBitmapFromNativeBitmap( void* bitmap
);
587 // create a subimage from a native image representation
588 virtual wxGraphicsBitmap
CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
591 bool EnsureIsLoaded();
594 friend class wxGDIPlusRendererModule
;
598 ULONG_PTR m_gditoken
;
600 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
)
603 //-----------------------------------------------------------------------------
604 // wxGDIPlusPen implementation
605 //-----------------------------------------------------------------------------
607 wxGDIPlusPenData::~wxGDIPlusPenData()
614 void wxGDIPlusPenData::Init()
621 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
622 : wxGraphicsObjectRefData(renderer
)
625 m_width
= pen
.GetWidth();
629 m_pen
= new Pen(wxColourToColor(pen
.GetColour()), m_width
);
632 switch ( pen
.GetCap() )
638 case wxCAP_PROJECTING
:
643 cap
= LineCapFlat
; // TODO verify
650 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
653 switch ( pen
.GetJoin() )
656 join
= LineJoinBevel
;
660 join
= LineJoinMiter
;
664 join
= LineJoinRound
;
668 join
= LineJoinMiter
;
672 m_pen
->SetLineJoin(join
);
674 m_pen
->SetDashStyle(DashStyleSolid
);
676 DashStyle dashStyle
= DashStyleSolid
;
677 switch ( pen
.GetStyle() )
679 case wxPENSTYLE_SOLID
:
682 case wxPENSTYLE_DOT
:
683 dashStyle
= DashStyleDot
;
686 case wxPENSTYLE_LONG_DASH
:
687 dashStyle
= DashStyleDash
; // TODO verify
690 case wxPENSTYLE_SHORT_DASH
:
691 dashStyle
= DashStyleDash
;
694 case wxPENSTYLE_DOT_DASH
:
695 dashStyle
= DashStyleDashDot
;
697 case wxPENSTYLE_USER_DASH
:
699 dashStyle
= DashStyleCustom
;
701 int count
= pen
.GetDashes( &dashes
);
702 if ((dashes
!= NULL
) && (count
> 0))
704 REAL
*userLengths
= new REAL
[count
];
705 for ( int i
= 0; i
< count
; ++i
)
707 userLengths
[i
] = dashes
[i
];
709 m_pen
->SetDashPattern( userLengths
, count
);
710 delete[] userLengths
;
714 case wxPENSTYLE_STIPPLE
:
716 wxBitmap
* bmp
= pen
.GetStipple();
717 if ( bmp
&& bmp
->IsOk() )
719 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),
721 (HPALETTE
)bmp
->GetPalette()->GetHPALETTE()
726 m_penBrush
= new TextureBrush(m_penImage
);
727 m_pen
->SetBrush( m_penBrush
);
733 if ( pen
.GetStyle() >= wxPENSTYLE_FIRST_HATCH
&&
734 pen
.GetStyle() <= wxPENSTYLE_LAST_HATCH
)
737 switch( pen
.GetStyle() )
739 case wxPENSTYLE_BDIAGONAL_HATCH
:
740 style
= HatchStyleBackwardDiagonal
;
742 case wxPENSTYLE_CROSSDIAG_HATCH
:
743 style
= HatchStyleDiagonalCross
;
745 case wxPENSTYLE_FDIAGONAL_HATCH
:
746 style
= HatchStyleForwardDiagonal
;
748 case wxPENSTYLE_CROSS_HATCH
:
749 style
= HatchStyleCross
;
751 case wxPENSTYLE_HORIZONTAL_HATCH
:
752 style
= HatchStyleHorizontal
;
754 case wxPENSTYLE_VERTICAL_HATCH
:
755 style
= HatchStyleVertical
;
758 style
= HatchStyleHorizontal
;
760 m_penBrush
= new HatchBrush
763 wxColourToColor(pen
.GetColour()),
766 m_pen
->SetBrush( m_penBrush
);
770 if ( dashStyle
!= DashStyleSolid
)
771 m_pen
->SetDashStyle(dashStyle
);
774 //-----------------------------------------------------------------------------
775 // wxGDIPlusBrush implementation
776 //-----------------------------------------------------------------------------
778 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
)
779 : wxGraphicsObjectRefData(renderer
)
784 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
785 : wxGraphicsObjectRefData(renderer
)
788 if ( brush
.GetStyle() == wxSOLID
)
790 m_brush
= new SolidBrush(wxColourToColor( brush
.GetColour()));
792 else if ( brush
.IsHatch() )
795 switch( brush
.GetStyle() )
797 case wxBRUSHSTYLE_BDIAGONAL_HATCH
:
798 style
= HatchStyleBackwardDiagonal
;
800 case wxBRUSHSTYLE_CROSSDIAG_HATCH
:
801 style
= HatchStyleDiagonalCross
;
803 case wxBRUSHSTYLE_FDIAGONAL_HATCH
:
804 style
= HatchStyleForwardDiagonal
;
806 case wxBRUSHSTYLE_CROSS_HATCH
:
807 style
= HatchStyleCross
;
809 case wxBRUSHSTYLE_HORIZONTAL_HATCH
:
810 style
= HatchStyleHorizontal
;
812 case wxBRUSHSTYLE_VERTICAL_HATCH
:
813 style
= HatchStyleVertical
;
816 style
= HatchStyleHorizontal
;
818 m_brush
= new HatchBrush
821 wxColourToColor(brush
.GetColour()),
827 wxBitmap
* bmp
= brush
.GetStipple();
828 if ( bmp
&& bmp
->IsOk() )
830 wxDELETE( m_brushImage
);
831 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),
833 (HPALETTE
)bmp
->GetPalette()->GetHPALETTE()
838 m_brush
= new TextureBrush(m_brushImage
);
843 wxGDIPlusBrushData::~wxGDIPlusBrushData()
850 void wxGDIPlusBrushData::Init()
857 template <typename T
>
859 wxGDIPlusBrushData::SetGradientStops(T
*brush
,
860 const wxGraphicsGradientStops
& stops
)
862 const unsigned numStops
= stops
.GetCount();
865 // initial and final colours are set during the brush creation, nothing
870 wxVector
<Color
> colors(numStops
);
871 wxVector
<REAL
> positions(numStops
);
873 for ( unsigned i
= 0; i
< numStops
; i
++ )
875 wxGraphicsGradientStop stop
= stops
.Item(i
);
877 colors
[i
] = wxColourToColor(stop
.GetColour());
878 positions
[i
] = stop
.GetPosition();
881 brush
->SetInterpolationColors(&colors
[0], &positions
[0], numStops
);
885 wxGDIPlusBrushData::CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
886 wxDouble x2
, wxDouble y2
,
887 const wxGraphicsGradientStops
& stops
)
889 LinearGradientBrush
* const
890 brush
= new LinearGradientBrush(PointF(x1
, y1
) , PointF(x2
, y2
),
891 wxColourToColor(stops
.GetStartColour()),
892 wxColourToColor(stops
.GetEndColour()));
895 SetGradientStops(brush
, stops
);
899 wxGDIPlusBrushData::CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
900 wxDouble xc
, wxDouble yc
,
902 const wxGraphicsGradientStops
& stops
)
904 m_brushPath
= new GraphicsPath();
905 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
),
906 (REAL
)(2*radius
), (REAL
)(2*radius
));
908 PathGradientBrush
* const brush
= new PathGradientBrush(m_brushPath
);
910 brush
->SetCenterPoint(PointF(xo
, yo
));
911 brush
->SetCenterColor(wxColourToColor(stops
.GetStartColour()));
913 const Color
col(wxColourToColor(stops
.GetEndColour()));
915 brush
->SetSurroundColors(&col
, &count
);
917 SetGradientStops(brush
, stops
);
920 //-----------------------------------------------------------------------------
921 // wxGDIPlusFont implementation
922 //-----------------------------------------------------------------------------
925 wxGDIPlusFontData::Init(const wxString
& name
,
931 m_font
= new Font(name
.wc_str(), size
, style
, fontUnit
);
933 m_textBrush
= new SolidBrush(wxColourToColor(col
));
936 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer
* renderer
,
938 const wxColour
& col
)
939 : wxGraphicsObjectRefData( renderer
)
941 int style
= FontStyleRegular
;
942 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
943 style
|= FontStyleItalic
;
944 if ( font
.GetUnderlined() )
945 style
|= FontStyleUnderline
;
946 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
947 style
|= FontStyleBold
;
949 Init(font
.GetFaceName(), font
.GetPointSize(), style
, col
, UnitPoint
);
952 wxGDIPlusFontData::wxGDIPlusFontData(wxGraphicsRenderer
* renderer
,
953 const wxString
& name
,
956 const wxColour
& col
) :
957 wxGraphicsObjectRefData(renderer
)
959 Init(name
, sizeInPixels
, style
, col
, UnitPixel
);
962 wxGDIPlusFontData::~wxGDIPlusFontData()
968 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
969 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
970 // bytes as parameter, since there is no real copying of the data going in, only references are stored
971 // m_helper has to be kept alive as well
973 //-----------------------------------------------------------------------------
974 // wxGDIPlusBitmapData implementation
975 //-----------------------------------------------------------------------------
977 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
) :
978 wxGraphicsBitmapData( renderer
), m_bitmap( bitmap
)
983 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
,
984 const wxBitmap
&bmp
) : wxGraphicsBitmapData( renderer
)
989 Bitmap
* image
= NULL
;
992 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),
994 (HPALETTE
)bmp
.GetPalette()->GetHPALETTE()
1000 size_t width
= interim
.GetWidth();
1001 size_t height
= interim
.GetHeight();
1002 Rect
bounds(0,0,width
,height
);
1004 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
1006 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
1007 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
1009 BitmapData dataMask
;
1010 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
1011 interimMask
.GetPixelFormat(),&dataMask
);
1014 BitmapData imageData
;
1015 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
1017 BYTE maskPattern
= 0 ;
1021 for ( size_t y
= 0 ; y
< height
; ++y
)
1024 for( size_t x
= 0 ; x
< width
; ++x
)
1029 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
1033 maskPattern
= maskPattern
>> 1;
1035 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
1036 if ( (maskByte
& maskPattern
) == 0 )
1041 interim
.GetPixel(x
,y
,&c
) ;
1042 *dest
= (c
.GetValue() | Color::AlphaMask
);
1047 image
->UnlockBits(&imageData
);
1049 interimMask
.UnlockBits(&dataMask
);
1050 interim
.UnlockBits(&dataMask
);
1054 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),
1056 (HPALETTE
)bmp
.GetPalette()->GetHPALETTE()
1061 if ( bmp
.HasAlpha() && GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
1063 size_t width
= image
->GetWidth();
1064 size_t height
= image
->GetHeight();
1065 Rect
bounds(0,0,width
,height
);
1066 static BitmapData data
;
1070 m_helper
->LockBits(&bounds
, ImageLockModeRead
,
1071 m_helper
->GetPixelFormat(),&data
);
1073 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1074 PixelFormat32bppPARGB
, (BYTE
*) data
.Scan0
);
1076 m_helper
->UnlockBits(&data
);
1085 wxImage
wxGDIPlusBitmapData::ConvertToImage() const
1087 // We could use Bitmap::LockBits() and convert to wxImage directly but
1088 // passing by wxBitmap is easier. It would be nice to measure performance
1089 // of the two methods but for this the second one would need to be written
1092 if ( m_bitmap
->GetHBITMAP(Color(0xffffffff), &hbmp
) != Gdiplus::Ok
)
1096 bmp
.SetWidth(m_bitmap
->GetWidth());
1097 bmp
.SetHeight(m_bitmap
->GetHeight());
1098 bmp
.SetHBITMAP(hbmp
);
1099 bmp
.SetDepth(IsAlphaPixelFormat(m_bitmap
->GetPixelFormat()) ? 32 : 24);
1100 return bmp
.ConvertToImage();
1103 #endif // wxUSE_IMAGE
1105 wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
1111 //-----------------------------------------------------------------------------
1112 // wxGDIPlusPath implementation
1113 //-----------------------------------------------------------------------------
1115 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
) : wxGraphicsPathData(renderer
)
1120 m_path
= new GraphicsPath();
1123 wxGDIPlusPathData::~wxGDIPlusPathData()
1128 wxGraphicsObjectRefData
* wxGDIPlusPathData::Clone() const
1130 return new wxGDIPlusPathData( GetRenderer() , m_path
->Clone());
1137 void wxGDIPlusPathData::MoveToPoint( wxDouble x
, wxDouble y
)
1139 m_path
->StartFigure();
1140 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
1143 void wxGDIPlusPathData::AddLineToPoint( wxDouble x
, wxDouble y
)
1145 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
1148 void wxGDIPlusPathData::CloseSubpath()
1150 m_path
->CloseFigure();
1153 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
1159 m_path
->GetLastPoint(&start
);
1160 m_path
->AddBezier(start
,c1
,c2
,end
);
1163 // gets the last point of the current path, (0,0) if not yet set
1164 void wxGDIPlusPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const
1167 m_path
->GetLastPoint(&start
);
1172 void wxGDIPlusPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
1174 double sweepAngle
= endAngle
- startAngle
;
1175 if( fabs(sweepAngle
) >= 2*M_PI
)
1177 sweepAngle
= 2 * M_PI
;
1183 if( sweepAngle
< 0 )
1184 sweepAngle
+= 2 * M_PI
;
1188 if( sweepAngle
> 0 )
1189 sweepAngle
-= 2 * M_PI
;
1193 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
1196 void wxGDIPlusPathData::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1198 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
1201 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData
* path
)
1203 m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
);
1207 // transforms each point of this path by the matrix
1208 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData
* matrix
)
1210 m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() );
1213 // gets the bounding box enclosing all points (possibly including control points)
1214 void wxGDIPlusPathData::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const
1217 m_path
->GetBounds( &bounds
, NULL
, NULL
) ;
1224 bool wxGDIPlusPathData::Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
) const
1226 m_path
->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1227 return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE
;
1230 //-----------------------------------------------------------------------------
1231 // wxGDIPlusMatrixData implementation
1232 //-----------------------------------------------------------------------------
1234 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
)
1235 : wxGraphicsMatrixData(renderer
)
1240 m_matrix
= new Matrix();
1243 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
1248 wxGraphicsObjectRefData
*wxGDIPlusMatrixData::Clone() const
1250 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix
->Clone());
1253 // concatenates the matrix
1254 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData
*t
)
1256 m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix());
1259 // sets the matrix to the respective values
1260 void wxGDIPlusMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1261 wxDouble tx
, wxDouble ty
)
1263 m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
);
1266 // gets the component valuess of the matrix
1267 void wxGDIPlusMatrixData::Get(wxDouble
* a
, wxDouble
* b
, wxDouble
* c
,
1268 wxDouble
* d
, wxDouble
* tx
, wxDouble
* ty
) const
1271 m_matrix
->GetElements(elements
);
1272 if (a
) *a
= elements
[0];
1273 if (b
) *b
= elements
[1];
1274 if (c
) *c
= elements
[2];
1275 if (d
) *d
= elements
[3];
1276 if (tx
) *tx
= elements
[4];
1277 if (ty
) *ty
= elements
[5];
1280 // makes this the inverse matrix
1281 void wxGDIPlusMatrixData::Invert()
1286 // returns true if the elements of the transformation matrix are equal ?
1287 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const
1289 return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE
;
1292 // return true if this is the identity matrix
1293 bool wxGDIPlusMatrixData::IsIdentity() const
1295 return m_matrix
->IsIdentity() == TRUE
;
1302 // add the translation to this matrix
1303 void wxGDIPlusMatrixData::Translate( wxDouble dx
, wxDouble dy
)
1305 m_matrix
->Translate(dx
,dy
);
1308 // add the scale to this matrix
1309 void wxGDIPlusMatrixData::Scale( wxDouble xScale
, wxDouble yScale
)
1311 m_matrix
->Scale(xScale
,yScale
);
1314 // add the rotation to this matrix (radians)
1315 void wxGDIPlusMatrixData::Rotate( wxDouble angle
)
1317 m_matrix
->Rotate( RadToDeg(angle
) );
1321 // apply the transforms
1324 // applies that matrix to the point
1325 void wxGDIPlusMatrixData::TransformPoint( wxDouble
*x
, wxDouble
*y
) const
1328 m_matrix
->TransformPoints(&pt
);
1333 // applies the matrix except for translations
1334 void wxGDIPlusMatrixData::TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const
1337 m_matrix
->TransformVectors(&pt
);
1342 // returns the native representation
1343 void * wxGDIPlusMatrixData::GetNativeMatrix() const
1348 //-----------------------------------------------------------------------------
1349 // wxGDIPlusContext implementation
1350 //-----------------------------------------------------------------------------
1352 class wxGDIPlusOffsetHelper
1355 wxGDIPlusOffsetHelper( Graphics
* gr
, bool offset
)
1360 m_gr
->TranslateTransform( 0.5, 0.5 );
1362 ~wxGDIPlusOffsetHelper( )
1365 m_gr
->TranslateTransform( -0.5, -0.5 );
1372 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
)
1373 : wxGraphicsContext(renderer
)
1375 Init(new Graphics(hdc
), width
, height
);
1378 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, const wxDC
& dc
)
1379 : wxGraphicsContext(renderer
)
1381 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1382 HDC hdc
= (HDC
) msw
->GetHDC();
1383 wxSize sz
= dc
.GetSize();
1385 Init(new Graphics(hdc
), sz
.x
, sz
.y
);
1388 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
)
1389 : wxGraphicsContext(renderer
)
1391 RECT rect
= wxGetWindowRect(hwnd
);
1392 Init(new Graphics(hwnd
), rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
1393 m_enableOffset
= true;
1396 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
)
1397 : wxGraphicsContext(renderer
)
1402 wxGDIPlusContext::wxGDIPlusContext(wxGraphicsRenderer
* renderer
)
1403 : wxGraphicsContext(renderer
)
1405 // Derived class must call Init() later but just set m_context to NULL for
1406 // safety to avoid crashing in our dtor if Init() ends up not being called.
1410 void wxGDIPlusContext::Init(Graphics
* graphics
, int width
, int height
)
1412 m_context
= graphics
;
1417 m_fontScaleRatio
= 1.0;
1419 m_context
->SetTextRenderingHint(TextRenderingHintSystemDefault
);
1420 m_context
->SetPixelOffsetMode(PixelOffsetModeHalf
);
1421 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
1422 m_context
->SetInterpolationMode(InterpolationModeHighQuality
);
1423 m_state1
= m_context
->Save();
1424 m_state2
= m_context
->Save();
1427 wxGDIPlusContext::~wxGDIPlusContext()
1431 m_context
->Restore( m_state2
);
1432 m_context
->Restore( m_state1
);
1438 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
1440 Region
rgn((HRGN
)region
.GetHRGN());
1441 m_context
->SetClip(&rgn
,CombineModeIntersect
);
1444 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1446 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
1449 void wxGDIPlusContext::ResetClip()
1451 m_context
->ResetClip();
1454 void wxGDIPlusContext::DrawRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1456 if (m_composition
== wxCOMPOSITION_DEST
)
1459 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1460 Brush
*brush
= m_brush
.IsNull() ? NULL
: ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush();
1461 Pen
*pen
= m_pen
.IsNull() ? NULL
: ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen();
1465 // the offset is used to fill only the inside of the rectangle and not paint underneath
1466 // its border which may influence a transparent Pen
1469 offset
= pen
->GetWidth();
1470 m_context
->FillRectangle( brush
, (REAL
)x
+ offset
/2, (REAL
)y
+ offset
/2, (REAL
)w
- offset
, (REAL
)h
- offset
);
1475 m_context
->DrawRectangle( pen
, (REAL
)x
, (REAL
)y
, (REAL
)w
, (REAL
)h
);
1479 void wxGDIPlusContext::StrokeLines( size_t n
, const wxPoint2DDouble
*points
)
1481 if (m_composition
== wxCOMPOSITION_DEST
)
1484 if ( !m_pen
.IsNull() )
1486 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1487 Point
*cpoints
= new Point
[n
];
1488 for (size_t i
= 0; i
< n
; i
++)
1490 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1491 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1493 } // for (size_t i = 0; i < n; i++)
1494 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1499 void wxGDIPlusContext::DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode
WXUNUSED(fillStyle
) )
1501 if (m_composition
== wxCOMPOSITION_DEST
)
1504 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1505 Point
*cpoints
= new Point
[n
];
1506 for (size_t i
= 0; i
< n
; i
++)
1508 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1509 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1511 } // for (int i = 0; i < n; i++)
1512 if ( !m_brush
.IsNull() )
1513 m_context
->FillPolygon( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() , cpoints
, n
) ;
1514 if ( !m_pen
.IsNull() )
1515 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1519 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
& path
)
1521 if (m_composition
== wxCOMPOSITION_DEST
)
1524 if ( !m_pen
.IsNull() )
1526 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1527 m_context
->DrawPath( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath
*) path
.GetNativePath() );
1531 void wxGDIPlusContext::FillPath( const wxGraphicsPath
& path
, wxPolygonFillMode fillStyle
)
1533 if (m_composition
== wxCOMPOSITION_DEST
)
1536 if ( !m_brush
.IsNull() )
1538 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1539 ((GraphicsPath
*) path
.GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1540 m_context
->FillPath( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() ,
1541 (GraphicsPath
*) path
.GetNativePath());
1545 bool wxGDIPlusContext::SetAntialiasMode(wxAntialiasMode antialias
)
1547 if (m_antialias
== antialias
)
1550 m_antialias
= antialias
;
1552 SmoothingMode antialiasMode
;
1555 case wxANTIALIAS_DEFAULT
:
1556 antialiasMode
= SmoothingModeHighQuality
;
1558 case wxANTIALIAS_NONE
:
1559 antialiasMode
= SmoothingModeNone
;
1564 m_context
->SetSmoothingMode(antialiasMode
);
1568 bool wxGDIPlusContext::SetInterpolationQuality(wxInterpolationQuality interpolation
)
1570 if (m_interpolation
== interpolation
)
1573 InterpolationMode interpolationMode
= InterpolationModeDefault
;
1574 switch (interpolation
)
1576 case wxINTERPOLATION_DEFAULT
:
1577 interpolationMode
= InterpolationModeDefault
;
1580 case wxINTERPOLATION_NONE
:
1581 interpolationMode
= InterpolationModeNearestNeighbor
;
1584 case wxINTERPOLATION_FAST
:
1585 interpolationMode
= InterpolationModeLowQuality
;
1588 case wxINTERPOLATION_GOOD
:
1589 interpolationMode
= InterpolationModeHighQuality
;
1592 case wxINTERPOLATION_BEST
:
1593 interpolationMode
= InterpolationModeHighQualityBicubic
;
1600 if ( m_context
->SetInterpolationMode(interpolationMode
) != Gdiplus::Ok
)
1603 m_interpolation
= interpolation
;
1608 bool wxGDIPlusContext::SetCompositionMode(wxCompositionMode op
)
1610 if ( m_composition
== op
)
1615 if (m_composition
== wxCOMPOSITION_DEST
)
1618 CompositingMode cop
;
1621 case wxCOMPOSITION_SOURCE
:
1622 cop
= CompositingModeSourceCopy
;
1624 case wxCOMPOSITION_OVER
:
1625 cop
= CompositingModeSourceOver
;
1631 m_context
->SetCompositingMode(cop
);
1635 void wxGDIPlusContext::BeginLayer(wxDouble
/* opacity */)
1640 void wxGDIPlusContext::EndLayer()
1645 void wxGDIPlusContext::Rotate( wxDouble angle
)
1647 m_context
->RotateTransform( RadToDeg(angle
) );
1650 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
1652 m_context
->TranslateTransform( dx
, dy
);
1655 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
1657 m_context
->ScaleTransform(xScale
,yScale
);
1660 void wxGDIPlusContext::PushState()
1662 GraphicsState state
= m_context
->Save();
1663 m_stateStack
.push(state
);
1666 void wxGDIPlusContext::PopState()
1668 wxCHECK_RET( !m_stateStack
.empty(), wxT("No state to pop") );
1670 GraphicsState state
= m_stateStack
.top();
1672 m_context
->Restore(state
);
1675 void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1677 if (m_composition
== wxCOMPOSITION_DEST
)
1680 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bmp
.GetRefData())->GetGDIPlusBitmap();
1683 if( image
->GetWidth() != (UINT
) w
|| image
->GetHeight() != (UINT
) h
)
1685 Rect
drawRect((REAL
) x
, (REAL
)y
, (REAL
)w
, (REAL
)h
);
1686 m_context
->SetPixelOffsetMode( PixelOffsetModeNone
);
1687 m_context
->DrawImage(image
, drawRect
, 0 , 0 , image
->GetWidth(), image
->GetHeight(), UnitPixel
) ;
1688 m_context
->SetPixelOffsetMode( PixelOffsetModeHalf
);
1691 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1695 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1697 wxGraphicsBitmap bitmap
= GetRenderer()->CreateBitmap(bmp
);
1698 DrawBitmap(bitmap
, x
, y
, w
, h
);
1701 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1703 if (m_composition
== wxCOMPOSITION_DEST
)
1706 // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
1707 // find out by looking at the bitmap data whether there really was alpha in it
1708 HICON hIcon
= (HICON
)icon
.GetHICON();
1710 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1711 if (!GetIconInfo(hIcon
,&iconInfo
))
1714 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
1716 Bitmap
* image
= NULL
;
1718 // if it's not 32 bit, it doesn't have an alpha channel, note that since the conversion doesn't
1719 // work correctly, asking IsAlphaPixelFormat at this point fails as well
1720 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
1722 image
= Bitmap::FromHICON(hIcon
);
1726 size_t width
= interim
.GetWidth();
1727 size_t height
= interim
.GetHeight();
1728 Rect
bounds(0,0,width
,height
);
1731 interim
.LockBits(&bounds
, ImageLockModeRead
,
1732 interim
.GetPixelFormat(),&data
);
1734 bool hasAlpha
= false;
1735 for ( size_t y
= 0 ; y
< height
&& !hasAlpha
; ++y
)
1737 for( size_t x
= 0 ; x
< width
&& !hasAlpha
; ++x
)
1739 ARGB
*dest
= (ARGB
*)((BYTE
*)data
.Scan0
+ data
.Stride
*y
+ x
*4);
1740 if ( ( *dest
& Color::AlphaMask
) != 0 )
1747 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1748 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1752 image
= Bitmap::FromHICON(hIcon
);
1755 interim
.UnlockBits(&data
);
1758 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1761 DeleteObject(iconInfo
.hbmColor
);
1762 DeleteObject(iconInfo
.hbmMask
);
1765 void wxGDIPlusContext::DoDrawText(const wxString
& str
,
1766 wxDouble x
, wxDouble y
)
1768 if (m_composition
== wxCOMPOSITION_DEST
)
1771 wxCHECK_RET( !m_font
.IsNull(),
1772 wxT("wxGDIPlusContext::DrawText - no valid font set") );
1777 wxGDIPlusFontData
* const
1778 fontData
= (wxGDIPlusFontData
*)m_font
.GetRefData();
1780 m_context
->DrawString
1782 str
.wc_str(*wxConvUI
), // string to draw, always Unicode
1783 -1, // length: string is NUL-terminated
1784 fontData
->GetGDIPlusFont(),
1786 GetDrawTextStringFormat(),
1787 fontData
->GetGDIPlusBrush()
1791 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1792 wxDouble
*descent
, wxDouble
*externalLeading
) const
1794 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1796 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1797 FontFamily ffamily
;
1798 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1800 f
->GetFamily(&ffamily
) ;
1802 REAL factorY
= m_fontScaleRatio
;
1804 // Notice that we must use the real font style or the results would be
1805 // incorrect for italic/bold fonts.
1806 const INT style
= f
->GetStyle();
1807 const REAL size
= f
->GetSize();
1808 const REAL emHeight
= ffamily
.GetEmHeight(style
);
1809 REAL rDescent
= ffamily
.GetCellDescent(style
) * size
/ emHeight
;
1810 REAL rAscent
= ffamily
.GetCellAscent(style
) * size
/ emHeight
;
1811 REAL rHeight
= ffamily
.GetLineSpacing(style
) * size
/ emHeight
;
1814 *height
= rHeight
* factorY
;
1816 *descent
= rDescent
* factorY
;
1817 if ( externalLeading
)
1818 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
;
1819 // measuring empty strings is not guaranteed, so do it by hand
1827 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1830 m_context
->MeasureString((const wchar_t *) s
, wcslen(s
) , f
, layoutRect
, GetDrawTextStringFormat(), &bounds
) ;
1832 *width
= bounds
.Width
;
1834 *height
= bounds
.Height
;
1838 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1841 widths
.Add(0, text
.length());
1843 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1848 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1849 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
1850 size_t len
= wcslen( ws
) ;
1851 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1853 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1854 StringFormat
strFormat( GetDrawTextStringFormat() );
1856 size_t startPosition
= 0;
1857 size_t remainder
= len
;
1858 const size_t maxSpan
= 32;
1859 CharacterRange
* ranges
= new CharacterRange
[maxSpan
] ;
1860 Region
* regions
= new Region
[maxSpan
];
1862 while( remainder
> 0 )
1864 size_t span
= wxMin( maxSpan
, remainder
);
1866 for( size_t i
= 0 ; i
< span
; ++i
)
1868 ranges
[i
].First
= 0 ;
1869 ranges
[i
].Length
= startPosition
+i
+1 ;
1871 strFormat
.SetMeasurableCharacterRanges(span
,ranges
);
1872 m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,span
,regions
) ;
1875 for ( size_t i
= 0 ; i
< span
; ++i
)
1877 regions
[i
].GetBounds(&bbox
,m_context
);
1878 widths
[startPosition
+i
] = bbox
.Width
;
1881 startPosition
+= span
;
1888 bool wxGDIPlusContext::ShouldOffset() const
1890 if ( !m_enableOffset
)
1894 if ( !m_pen
.IsNull() )
1896 penwidth
= (int)((wxGDIPlusPenData
*)m_pen
.GetRefData())->GetWidth();
1897 if ( penwidth
== 0 )
1900 return ( penwidth
% 2 ) == 1;
1903 void* wxGDIPlusContext::GetNativeContext()
1908 // concatenates this transform with the current transform of this context
1909 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
& matrix
)
1911 m_context
->MultiplyTransform((Matrix
*) matrix
.GetNativeMatrix());
1914 // sets the transform of this context
1915 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
& matrix
)
1917 m_context
->SetTransform((Matrix
*) matrix
.GetNativeMatrix());
1920 // gets the matrix of this context
1921 wxGraphicsMatrix
wxGDIPlusContext::GetTransform() const
1923 wxGraphicsMatrix matrix
= CreateMatrix();
1924 m_context
->GetTransform((Matrix
*) matrix
.GetNativeMatrix());
1928 void wxGDIPlusContext::GetSize( wxDouble
* width
, wxDouble
*height
)
1934 //-----------------------------------------------------------------------------
1935 // wxGDIPlusPrintingContext implementation
1936 //-----------------------------------------------------------------------------
1938 wxGDIPlusPrintingContext::wxGDIPlusPrintingContext( wxGraphicsRenderer
* renderer
,
1940 : wxGDIPlusContext(renderer
, dc
)
1942 Graphics
* context
= GetGraphics();
1944 //m_context->SetPageUnit(UnitDocument);
1946 // Setup page scale, based on DPI ratio.
1947 // Antecedent should be 100dpi when the default page unit
1948 // (UnitDisplay) is used. Page unit UnitDocument would require 300dpi
1949 // instead. Note that calling SetPageScale() does not have effect on
1950 // non-printing DCs (that is, any other than wxPrinterDC or
1951 // wxEnhMetaFileDC).
1952 REAL dpiRatio
= 100.0 / context
->GetDpiY();
1953 context
->SetPageScale(dpiRatio
);
1955 // We use this modifier when measuring fonts. It is needed because the
1956 // page scale is modified above.
1957 m_fontScaleRatio
= context
->GetDpiY() / 72.0;
1960 //-----------------------------------------------------------------------------
1961 // wxGDIPlusRenderer implementation
1962 //-----------------------------------------------------------------------------
1964 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
)
1966 static wxGDIPlusRenderer gs_GDIPlusRenderer
;
1968 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1970 return &gs_GDIPlusRenderer
;
1973 bool wxGDIPlusRenderer::EnsureIsLoaded()
1975 // load gdiplus.dll if not yet loaded, but don't bother doing it again
1976 // if we already tried and failed (we don't want to spend lot of time
1977 // returning NULL from wxGraphicsContext::Create(), which may be called
1978 // relatively frequently):
1979 if ( m_loaded
== -1 )
1984 return m_loaded
== 1;
1987 // call EnsureIsLoaded() and return returnOnFail value if it fails
1988 #define ENSURE_LOADED_OR_RETURN(returnOnFail) \
1989 if ( !EnsureIsLoaded() ) \
1990 return (returnOnFail)
1993 void wxGDIPlusRenderer::Load()
1995 GdiplusStartupInput input
;
1996 GdiplusStartupOutput output
;
1997 if ( GdiplusStartup(&m_gditoken
,&input
,&output
) == Gdiplus::Ok
)
1999 wxLogTrace("gdiplus", "successfully initialized GDI+");
2004 wxLogTrace("gdiplus", "failed to initialize GDI+, missing gdiplus.dll?");
2009 void wxGDIPlusRenderer::Unload()
2013 GdiplusShutdown(m_gditoken
);
2016 m_loaded
= -1; // next Load() will try again
2019 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
)
2021 ENSURE_LOADED_OR_RETURN(NULL
);
2022 wxGDIPlusContext
* context
= new wxGDIPlusContext(this, dc
);
2023 context
->EnableOffset(true);
2027 #if wxUSE_PRINTING_ARCHITECTURE
2028 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxPrinterDC
& dc
)
2030 ENSURE_LOADED_OR_RETURN(NULL
);
2031 wxGDIPlusContext
* context
= new wxGDIPlusPrintingContext(this, dc
);
2036 #if wxUSE_ENH_METAFILE
2037 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxEnhMetaFileDC
& dc
)
2039 ENSURE_LOADED_OR_RETURN(NULL
);
2040 wxGDIPlusContext
* context
= new wxGDIPlusPrintingContext(this, dc
);
2045 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxMemoryDC
& dc
)
2047 ENSURE_LOADED_OR_RETURN(NULL
);
2048 wxGDIPlusContext
* context
= new wxGDIPlusContext(this, dc
);
2049 context
->EnableOffset(true);
2054 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromImage(wxImage
& image
)
2056 ENSURE_LOADED_OR_RETURN(NULL
);
2057 wxGDIPlusContext
* context
= new wxGDIPlusImageContext(this, image
);
2058 context
->EnableOffset(true);
2062 #endif // wxUSE_IMAGE
2064 wxGraphicsContext
* wxGDIPlusRenderer::CreateMeasuringContext()
2066 ENSURE_LOADED_OR_RETURN(NULL
);
2067 return new wxGDIPlusMeasuringContext(this);
2070 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context
)
2072 ENSURE_LOADED_OR_RETURN(NULL
);
2073 return new wxGDIPlusContext(this,(Graphics
*) context
);
2077 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window
)
2079 ENSURE_LOADED_OR_RETURN(NULL
);
2080 return new wxGDIPlusContext(this,(HWND
) window
);
2083 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( wxWindow
* window
)
2085 ENSURE_LOADED_OR_RETURN(NULL
);
2086 return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() );
2091 wxGraphicsPath
wxGDIPlusRenderer::CreatePath()
2093 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath
);
2095 m
.SetRefData( new wxGDIPlusPathData(this));
2102 wxGraphicsMatrix
wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
2103 wxDouble tx
, wxDouble ty
)
2106 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix
);
2108 wxGDIPlusMatrixData
* data
= new wxGDIPlusMatrixData( this );
2109 data
->Set( a
,b
,c
,d
,tx
,ty
) ;
2114 wxGraphicsPen
wxGDIPlusRenderer::CreatePen(const wxPen
& pen
)
2116 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen
);
2117 if ( !pen
.IsOk() || pen
.GetStyle() == wxTRANSPARENT
)
2118 return wxNullGraphicsPen
;
2122 p
.SetRefData(new wxGDIPlusPenData( this, pen
));
2127 wxGraphicsBrush
wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush
)
2129 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
2130 if ( !brush
.IsOk() || brush
.GetStyle() == wxTRANSPARENT
)
2131 return wxNullGraphicsBrush
;
2135 p
.SetRefData(new wxGDIPlusBrushData( this, brush
));
2141 wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
2142 wxDouble x2
, wxDouble y2
,
2143 const wxGraphicsGradientStops
& stops
)
2145 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
2147 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
2148 d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, stops
);
2154 wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
2155 wxDouble xc
, wxDouble yc
,
2157 const wxGraphicsGradientStops
& stops
)
2159 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
2161 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
2162 d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,stops
);
2168 wxGDIPlusRenderer::CreateFont( const wxFont
&font
,
2169 const wxColour
&col
)
2171 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont
);
2175 p
.SetRefData(new wxGDIPlusFontData( this, font
, col
));
2179 return wxNullGraphicsFont
;
2183 wxGDIPlusRenderer::CreateFont(double size
,
2184 const wxString
& facename
,
2186 const wxColour
& col
)
2188 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont
);
2190 // Convert wxFont flags to GDI+ style:
2191 int style
= FontStyleRegular
;
2192 if ( flags
& wxFONTFLAG_ITALIC
)
2193 style
|= FontStyleItalic
;
2194 if ( flags
& wxFONTFLAG_UNDERLINED
)
2195 style
|= FontStyleUnderline
;
2196 if ( flags
& wxFONTFLAG_BOLD
)
2197 style
|= FontStyleBold
;
2198 if ( flags
& wxFONTFLAG_STRIKETHROUGH
)
2199 style
|= FontStyleStrikeout
;
2203 f
.SetRefData(new wxGDIPlusFontData(this, facename
, size
, style
, col
));
2207 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmap( const wxBitmap
&bitmap
)
2209 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2210 if ( bitmap
.IsOk() )
2213 p
.SetRefData(new wxGDIPlusBitmapData( this , bitmap
));
2217 return wxNullGraphicsBitmap
;
2222 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmapFromImage(const wxImage
& image
)
2224 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2227 // Notice that we rely on conversion from wxImage to wxBitmap here but
2228 // we could probably do it more efficiently by converting from wxImage
2229 // to GDI+ Bitmap directly, i.e. copying wxImage pixels to the buffer
2230 // returned by Bitmap::LockBits(). However this would require writing
2231 // code specific for this task while like this we can reuse existing
2232 // code (see also wxGDIPlusBitmapData::ConvertToImage()).
2233 wxGraphicsBitmap gb
;
2234 gb
.SetRefData(new wxGDIPlusBitmapData(this, image
));
2238 return wxNullGraphicsBitmap
;
2242 wxImage
wxGDIPlusRenderer::CreateImageFromBitmap(const wxGraphicsBitmap
& bmp
)
2244 ENSURE_LOADED_OR_RETURN(wxNullImage
);
2245 const wxGDIPlusBitmapData
* const
2246 data
= static_cast<wxGDIPlusBitmapData
*>(bmp
.GetGraphicsData());
2248 return data
? data
->ConvertToImage() : wxNullImage
;
2251 #endif // wxUSE_IMAGE
2254 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmapFromNativeBitmap( void *bitmap
)
2256 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2257 if ( bitmap
!= NULL
)
2260 p
.SetRefData(new wxGDIPlusBitmapData( this , (Bitmap
*) bitmap
));
2264 return wxNullGraphicsBitmap
;
2267 wxGraphicsBitmap
wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
2269 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2270 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bitmap
.GetRefData())->GetGDIPlusBitmap();
2274 p
.SetRefData(new wxGDIPlusBitmapData( this , image
->Clone( (REAL
) x
, (REAL
) y
, (REAL
) w
, (REAL
) h
, PixelFormat32bppPARGB
) ));
2278 return wxNullGraphicsBitmap
;
2281 // Shutdown GDI+ at app exit, before possible dll unload
2282 class wxGDIPlusRendererModule
: public wxModule
2285 wxGDIPlusRendererModule()
2287 // We must be uninitialized before GDI+ DLL itself is unloaded.
2288 AddDependency("wxGdiPlusModule");
2291 virtual bool OnInit() { return true; }
2292 virtual void OnExit()
2294 wxDELETE(gs_drawTextStringFormat
);
2296 gs_GDIPlusRenderer
.Unload();
2300 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule
)
2303 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule
, wxModule
)
2305 // ----------------------------------------------------------------------------
2306 // wxMSW-specific parts of wxGCDC
2307 // ----------------------------------------------------------------------------
2309 WXHDC
wxGCDC::AcquireHDC()
2311 wxGraphicsContext
* const gc
= GetGraphicsContext();
2316 // we can't get the HDC if it is not a GDI+ context
2317 wxGraphicsRenderer
* r1
= gc
->GetRenderer();
2318 wxGraphicsRenderer
* r2
= wxGraphicsRenderer::GetCairoRenderer();
2323 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
2324 return g
? g
->GetHDC() : NULL
;
2327 void wxGCDC::ReleaseHDC(WXHDC hdc
)
2332 wxGraphicsContext
* const gc
= GetGraphicsContext();
2333 wxCHECK_RET( gc
, "can't release HDC because there is no wxGraphicsContext" );
2336 // we can't get the HDC if it is not a GDI+ context
2337 wxGraphicsRenderer
* r1
= gc
->GetRenderer();
2338 wxGraphicsRenderer
* r2
= wxGraphicsRenderer::GetCairoRenderer();
2343 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
2344 wxCHECK_RET( g
, "can't release HDC because there is no Graphics" );
2346 g
->ReleaseHDC((HDC
)hdc
);
2349 #endif // wxUSE_GRAPHICS_CONTEXT