1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/graphics.cpp
3 // Purpose: wxGCDC class
4 // Author: Stefan Csomor
8 // Copyright: (c) 2006 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
20 #if wxUSE_GRAPHICS_CONTEXT
23 #include "wx/msw/wrapcdlg.h"
25 #include "wx/window.h"
27 #include "wx/dialog.h"
29 #include "wx/bitmap.h"
32 #include "wx/module.h"
33 // include all dc types that are used as a param
35 #include "wx/dcclient.h"
36 #include "wx/dcmemory.h"
37 #include "wx/dcprint.h"
40 #include "wx/private/graphics.h"
41 #include "wx/msw/wrapgdip.h"
42 #include "wx/msw/dc.h"
43 #include "wx/msw/enhmeta.h"
44 #include "wx/dcgraph.h"
46 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
48 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
54 WX_DECLARE_STACK(GraphicsState
, GraphicsStates
);
59 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
63 const double RAD2DEG
= 180.0 / M_PI
;
65 //-----------------------------------------------------------------------------
67 //-----------------------------------------------------------------------------
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
; }
72 inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
73 inline double RadToDeg(double deg
) { return (deg
* 180.0) / M_PI
; }
75 // translate a wxColour to a Color
76 inline Color
wxColourToColor(const wxColour
& col
)
78 return Color(col
.Alpha(), col
.Red(), col
.Green(), col
.Blue());
81 } // anonymous namespace
83 //-----------------------------------------------------------------------------
84 // device context implementation
86 // more and more of the dc functionality should be implemented by calling
87 // the appropricate wxGDIPlusContext, but we will have to do that step by step
88 // also coordinate conversions should be moved to native matrix ops
89 //-----------------------------------------------------------------------------
91 // we always stock two context states, one at entry, to be able to preserve the
92 // state we were called with, the other one after changing to HI Graphics orientation
93 // (this one is used for getting back clippings etc)
95 //-----------------------------------------------------------------------------
96 // wxGraphicsPath implementation
97 //-----------------------------------------------------------------------------
99 class wxGDIPlusPathData
: public wxGraphicsPathData
102 wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
= NULL
);
103 ~wxGDIPlusPathData();
105 virtual wxGraphicsObjectRefData
*Clone() const;
108 // These are the path primitives from which everything else can be constructed
111 // begins a new subpath at (x,y)
112 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
114 // adds a straight line from the current point to (x,y)
115 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
117 // adds a cubic Bezier curve from the current point, using two control points and an end point
118 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
121 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
122 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
124 // gets the last point of the current path, (0,0) if not yet set
125 virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const;
128 virtual void AddPath( const wxGraphicsPathData
* path
);
130 // closes the current sub-path
131 virtual void CloseSubpath();
134 // These are convenience functions which - if not available natively will be assembled
135 // using the primitives from above
138 // appends a rectangle as a new closed subpath
139 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
142 // appends an ellipsis as a new closed subpath fitting the passed rectangle
143 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
145 // 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)
146 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
149 // returns the native path
150 virtual void * GetNativePath() const { return m_path
; }
152 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
153 virtual void UnGetNativePath(void * WXUNUSED(path
)) const {}
155 // transforms each point of this path by the matrix
156 virtual void Transform( const wxGraphicsMatrixData
* matrix
) ;
158 // gets the bounding box enclosing all points (possibly including control points)
159 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const;
161 virtual bool Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
) const;
164 GraphicsPath
* m_path
;
167 class wxGDIPlusMatrixData
: public wxGraphicsMatrixData
170 wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
= NULL
) ;
171 virtual ~wxGDIPlusMatrixData() ;
173 virtual wxGraphicsObjectRefData
* Clone() const ;
175 // concatenates the matrix
176 virtual void Concat( const wxGraphicsMatrixData
*t
);
178 // sets the matrix to the respective values
179 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
180 wxDouble tx
=0.0, wxDouble ty
=0.0);
182 // gets the component valuess of the matrix
183 virtual void Get(wxDouble
* a
=NULL
, wxDouble
* b
=NULL
, wxDouble
* c
=NULL
,
184 wxDouble
* d
=NULL
, wxDouble
* tx
=NULL
, wxDouble
* ty
=NULL
) const;
186 // makes this the inverse matrix
187 virtual void Invert();
189 // returns true if the elements of the transformation matrix are equal ?
190 virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ;
192 // return true if this is the identity matrix
193 virtual bool IsIdentity() const;
199 // add the translation to this matrix
200 virtual void Translate( wxDouble dx
, wxDouble dy
);
202 // add the scale to this matrix
203 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
205 // add the rotation to this matrix (radians)
206 virtual void Rotate( wxDouble angle
);
209 // apply the transforms
212 // applies that matrix to the point
213 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
) const;
215 // applies the matrix except for translations
216 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const;
218 // returns the native representation
219 virtual void * GetNativeMatrix() const;
224 class wxGDIPlusPenData
: public wxGraphicsObjectRefData
227 wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
232 virtual wxDouble
GetWidth() { return m_width
; }
233 virtual Pen
* GetGDIPlusPen() { return m_pen
; }
243 class wxGDIPlusBrushData
: public wxGraphicsObjectRefData
246 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
);
247 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
248 ~wxGDIPlusBrushData ();
250 void CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
251 wxDouble x2
, wxDouble y2
,
252 const wxGraphicsGradientStops
& stops
);
253 void CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
254 wxDouble xc
, wxDouble yc
,
256 const wxGraphicsGradientStops
& stops
);
258 virtual Brush
* GetGDIPlusBrush() { return m_brush
; }
264 // common part of Create{Linear,Radial}GradientBrush()
265 template <typename T
>
266 void SetGradientStops(T
*brush
, const wxGraphicsGradientStops
& stops
);
270 GraphicsPath
* m_brushPath
;
273 class WXDLLIMPEXP_CORE wxGDIPlusBitmapData
: public wxGraphicsObjectRefData
276 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
);
277 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, const wxBitmap
&bmp
);
278 ~wxGDIPlusBitmapData ();
280 virtual Bitmap
* GetGDIPlusBitmap() { return m_bitmap
; }
287 class wxGDIPlusFontData
: public wxGraphicsObjectRefData
290 wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
, const wxColour
& col
);
291 ~wxGDIPlusFontData();
293 virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; }
294 virtual Font
* GetGDIPlusFont() { return m_font
; }
300 class wxGDIPlusContext
: public wxGraphicsContext
303 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
);
304 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
);
305 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
);
308 virtual ~wxGDIPlusContext();
310 virtual void Clip( const wxRegion
®ion
);
311 // clips drawings to the rect
312 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
314 // resets the clipping to original extent
315 virtual void ResetClip();
317 virtual void * GetNativeContext();
319 virtual void StrokePath( const wxGraphicsPath
& p
);
320 virtual void FillPath( const wxGraphicsPath
& p
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
322 // stroke lines connecting each of the points
323 virtual void StrokeLines( size_t n
, const wxPoint2DDouble
*points
);
326 virtual void DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
328 virtual bool SetAntialiasMode(wxAntialiasMode antialias
);
330 virtual bool SetCompositionMode(wxCompositionMode op
);
332 virtual void BeginLayer(wxDouble opacity
);
334 virtual void EndLayer();
336 virtual void Translate( wxDouble dx
, wxDouble dy
);
337 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
338 virtual void Rotate( wxDouble angle
);
340 // concatenates this transform with the current transform of this context
341 virtual void ConcatTransform( const wxGraphicsMatrix
& matrix
);
343 // sets the transform of this context
344 virtual void SetTransform( const wxGraphicsMatrix
& matrix
);
346 // gets the matrix of this context
347 virtual wxGraphicsMatrix
GetTransform() const;
349 virtual void DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
350 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
351 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
352 virtual void PushState();
353 virtual void PopState();
355 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
356 wxDouble
*descent
, wxDouble
*externalLeading
) const;
357 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
358 virtual bool ShouldOffset() const;
359 virtual void GetSize( wxDouble
* width
, wxDouble
*height
);
365 virtual void DoDrawText(const wxString
& str
, wxDouble x
, wxDouble y
)
366 { DoDrawFilledText(str
, x
, y
, wxNullGraphicsBrush
); }
367 virtual void DoDrawFilledText(const wxString
& str
, wxDouble x
, wxDouble y
,
368 const wxGraphicsBrush
& backgroundBrush
);
371 GraphicsStates m_stateStack
;
372 GraphicsState m_state1
;
373 GraphicsState m_state2
;
378 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext
)
381 class wxGDIPlusMeasuringContext
: public wxGDIPlusContext
384 wxGDIPlusMeasuringContext( wxGraphicsRenderer
* renderer
) : wxGDIPlusContext( renderer
, m_hdc
= GetDC(NULL
), 1000, 1000 )
387 wxGDIPlusMeasuringContext()
391 virtual ~wxGDIPlusMeasuringContext()
393 ReleaseDC( NULL
, m_hdc
);
398 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMeasuringContext
)
401 //-----------------------------------------------------------------------------
402 // wxGDIPlusPen implementation
403 //-----------------------------------------------------------------------------
405 wxGDIPlusPenData::~wxGDIPlusPenData()
412 void wxGDIPlusPenData::Init()
419 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
420 : wxGraphicsObjectRefData(renderer
)
423 m_width
= pen
.GetWidth();
427 m_pen
= new Pen(wxColourToColor(pen
.GetColour()), m_width
);
430 switch ( pen
.GetCap() )
436 case wxCAP_PROJECTING
:
441 cap
= LineCapFlat
; // TODO verify
448 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
451 switch ( pen
.GetJoin() )
454 join
= LineJoinBevel
;
458 join
= LineJoinMiter
;
462 join
= LineJoinRound
;
466 join
= LineJoinMiter
;
470 m_pen
->SetLineJoin(join
);
472 m_pen
->SetDashStyle(DashStyleSolid
);
474 DashStyle dashStyle
= DashStyleSolid
;
475 switch ( pen
.GetStyle() )
481 dashStyle
= DashStyleDot
;
485 dashStyle
= DashStyleDash
; // TODO verify
489 dashStyle
= DashStyleDash
;
493 dashStyle
= DashStyleDashDot
;
497 dashStyle
= DashStyleCustom
;
499 int count
= pen
.GetDashes( &dashes
);
500 if ((dashes
!= NULL
) && (count
> 0))
502 REAL
*userLengths
= new REAL
[count
];
503 for ( int i
= 0; i
< count
; ++i
)
505 userLengths
[i
] = dashes
[i
];
507 m_pen
->SetDashPattern( userLengths
, count
);
508 delete[] userLengths
;
514 wxBitmap
* bmp
= pen
.GetStipple();
515 if ( bmp
&& bmp
->Ok() )
517 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
518 m_penBrush
= new TextureBrush(m_penImage
);
519 m_pen
->SetBrush( m_penBrush
);
525 if ( pen
.GetStyle() >= wxFIRST_HATCH
&& pen
.GetStyle() <= wxLAST_HATCH
)
527 HatchStyle style
= HatchStyleHorizontal
;
528 switch( pen
.GetStyle() )
530 case wxBDIAGONAL_HATCH
:
531 style
= HatchStyleBackwardDiagonal
;
533 case wxCROSSDIAG_HATCH
:
534 style
= HatchStyleDiagonalCross
;
536 case wxFDIAGONAL_HATCH
:
537 style
= HatchStyleForwardDiagonal
;
540 style
= HatchStyleCross
;
542 case wxHORIZONTAL_HATCH
:
543 style
= HatchStyleHorizontal
;
545 case wxVERTICAL_HATCH
:
546 style
= HatchStyleVertical
;
550 m_penBrush
= new HatchBrush
553 wxColourToColor(pen
.GetColour()),
556 m_pen
->SetBrush( m_penBrush
);
560 if ( dashStyle
!= DashStyleSolid
)
561 m_pen
->SetDashStyle(dashStyle
);
564 //-----------------------------------------------------------------------------
565 // wxGDIPlusBrush implementation
566 //-----------------------------------------------------------------------------
568 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
)
569 : wxGraphicsObjectRefData(renderer
)
574 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
575 : wxGraphicsObjectRefData(renderer
)
578 if ( brush
.GetStyle() == wxSOLID
)
580 m_brush
= new SolidBrush(wxColourToColor( brush
.GetColour()));
582 else if ( brush
.IsHatch() )
584 HatchStyle style
= HatchStyleHorizontal
;
585 switch( brush
.GetStyle() )
587 case wxBDIAGONAL_HATCH
:
588 style
= HatchStyleBackwardDiagonal
;
590 case wxCROSSDIAG_HATCH
:
591 style
= HatchStyleDiagonalCross
;
593 case wxFDIAGONAL_HATCH
:
594 style
= HatchStyleForwardDiagonal
;
597 style
= HatchStyleCross
;
599 case wxHORIZONTAL_HATCH
:
600 style
= HatchStyleHorizontal
;
602 case wxVERTICAL_HATCH
:
603 style
= HatchStyleVertical
;
607 m_brush
= new HatchBrush
610 wxColourToColor(brush
.GetColour()),
616 wxBitmap
* bmp
= brush
.GetStipple();
617 if ( bmp
&& bmp
->Ok() )
619 wxDELETE( m_brushImage
);
620 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
621 m_brush
= new TextureBrush(m_brushImage
);
626 wxGDIPlusBrushData::~wxGDIPlusBrushData()
633 void wxGDIPlusBrushData::Init()
640 template <typename T
>
642 wxGDIPlusBrushData::SetGradientStops(T
*brush
,
643 const wxGraphicsGradientStops
& stops
)
645 const unsigned numStops
= stops
.GetCount();
648 // initial and final colours are set during the brush creation, nothing
653 wxVector
<Color
> colors(numStops
);
654 wxVector
<REAL
> positions(numStops
);
656 for ( unsigned i
= 0; i
< numStops
; i
++ )
658 wxGraphicsGradientStop stop
= stops
.Item(i
);
660 colors
[i
] = wxColourToColor(stop
.GetColour());
661 positions
[i
] = stop
.GetPosition();
664 brush
->SetInterpolationColors(&colors
[0], &positions
[0], numStops
);
668 wxGDIPlusBrushData::CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
669 wxDouble x2
, wxDouble y2
,
670 const wxGraphicsGradientStops
& stops
)
672 LinearGradientBrush
* const
673 brush
= new LinearGradientBrush(PointF(x1
, y1
) , PointF(x2
, y2
),
674 wxColourToColor(stops
.GetStartColour()),
675 wxColourToColor(stops
.GetEndColour()));
678 SetGradientStops(brush
, stops
);
682 wxGDIPlusBrushData::CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
683 wxDouble xc
, wxDouble yc
,
685 const wxGraphicsGradientStops
& stops
)
687 m_brushPath
= new GraphicsPath();
688 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
),
689 (REAL
)(2*radius
), (REAL
)(2*radius
));
691 PathGradientBrush
* const brush
= new PathGradientBrush(m_brushPath
);
693 brush
->SetCenterPoint(PointF(xo
, yo
));
694 brush
->SetCenterColor(wxColourToColor(stops
.GetStartColour()));
696 const Color
col(wxColourToColor(stops
.GetEndColour()));
698 brush
->SetSurroundColors(&col
, &count
);
700 SetGradientStops(brush
, stops
);
703 //-----------------------------------------------------------------------------
704 // wxGDIPlusFont implementation
705 //-----------------------------------------------------------------------------
707 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
,
708 const wxColour
& col
) : wxGraphicsObjectRefData( renderer
)
713 wxWCharBuffer s
= font
.GetFaceName().wc_str( *wxConvUI
);
714 int size
= font
.GetPointSize();
715 int style
= FontStyleRegular
;
716 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
717 style
|= FontStyleItalic
;
718 if ( font
.GetUnderlined() )
719 style
|= FontStyleUnderline
;
720 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
721 style
|= FontStyleBold
;
722 m_font
= new Font( s
, size
, style
);
723 m_textBrush
= new SolidBrush(wxColourToColor(col
));
726 wxGDIPlusFontData::~wxGDIPlusFontData()
732 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
733 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
734 // bytes as parameter, since there is no real copying of the data going in, only references are stored
735 // m_helper has to be kept alive as well
737 //-----------------------------------------------------------------------------
738 // wxGDIPlusBitmapData implementation
739 //-----------------------------------------------------------------------------
741 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
) :
742 wxGraphicsObjectRefData( renderer
), m_bitmap( bitmap
)
747 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
,
748 const wxBitmap
&bmp
) : wxGraphicsObjectRefData( renderer
)
753 Bitmap
* image
= NULL
;
756 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ;
758 size_t width
= interim
.GetWidth();
759 size_t height
= interim
.GetHeight();
760 Rect
bounds(0,0,width
,height
);
762 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
764 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
765 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
767 BitmapData dataMask
;
768 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
769 interimMask
.GetPixelFormat(),&dataMask
);
772 BitmapData imageData
;
773 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
775 BYTE maskPattern
= 0 ;
779 for ( size_t y
= 0 ; y
< height
; ++y
)
782 for( size_t x
= 0 ; x
< width
; ++x
)
787 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
791 maskPattern
= maskPattern
>> 1;
793 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
794 if ( (maskByte
& maskPattern
) == 0 )
799 interim
.GetPixel(x
,y
,&c
) ;
800 *dest
= (c
.GetValue() | Color::AlphaMask
);
805 image
->UnlockBits(&imageData
);
807 interimMask
.UnlockBits(&dataMask
);
808 interim
.UnlockBits(&dataMask
);
812 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE());
813 if ( bmp
.HasAlpha() && GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
815 size_t width
= image
->GetWidth();
816 size_t height
= image
->GetHeight();
817 Rect
bounds(0,0,width
,height
);
818 static BitmapData data
;
822 m_helper
->LockBits(&bounds
, ImageLockModeRead
,
823 m_helper
->GetPixelFormat(),&data
);
825 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
826 PixelFormat32bppPARGB
, (BYTE
*) data
.Scan0
);
828 m_helper
->UnlockBits(&data
);
835 wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
841 //-----------------------------------------------------------------------------
842 // wxGDIPlusPath implementation
843 //-----------------------------------------------------------------------------
845 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
) : wxGraphicsPathData(renderer
)
850 m_path
= new GraphicsPath();
853 wxGDIPlusPathData::~wxGDIPlusPathData()
858 wxGraphicsObjectRefData
* wxGDIPlusPathData::Clone() const
860 return new wxGDIPlusPathData( GetRenderer() , m_path
->Clone());
867 void wxGDIPlusPathData::MoveToPoint( wxDouble x
, wxDouble y
)
869 m_path
->StartFigure();
870 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
873 void wxGDIPlusPathData::AddLineToPoint( wxDouble x
, wxDouble y
)
875 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
878 void wxGDIPlusPathData::CloseSubpath()
880 m_path
->CloseFigure();
883 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
889 m_path
->GetLastPoint(&start
);
890 m_path
->AddBezier(start
,c1
,c2
,end
);
893 // gets the last point of the current path, (0,0) if not yet set
894 void wxGDIPlusPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const
897 m_path
->GetLastPoint(&start
);
902 void wxGDIPlusPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
904 double sweepAngle
= endAngle
- startAngle
;
905 if( fabs(sweepAngle
) >= 2*M_PI
)
907 sweepAngle
= 2 * M_PI
;
914 sweepAngle
+= 2 * M_PI
;
919 sweepAngle
-= 2 * M_PI
;
923 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
926 void wxGDIPlusPathData::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
928 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
931 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData
* path
)
933 m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
);
937 // transforms each point of this path by the matrix
938 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData
* matrix
)
940 m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() );
943 // gets the bounding box enclosing all points (possibly including control points)
944 void wxGDIPlusPathData::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const
947 m_path
->GetBounds( &bounds
, NULL
, NULL
) ;
954 bool wxGDIPlusPathData::Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
) const
956 m_path
->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
957 return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE
;
960 //-----------------------------------------------------------------------------
961 // wxGDIPlusMatrixData implementation
962 //-----------------------------------------------------------------------------
964 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
)
965 : wxGraphicsMatrixData(renderer
)
970 m_matrix
= new Matrix();
973 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
978 wxGraphicsObjectRefData
*wxGDIPlusMatrixData::Clone() const
980 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix
->Clone());
983 // concatenates the matrix
984 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData
*t
)
986 m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix());
989 // sets the matrix to the respective values
990 void wxGDIPlusMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
991 wxDouble tx
, wxDouble ty
)
993 m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
);
996 // gets the component valuess of the matrix
997 void wxGDIPlusMatrixData::Get(wxDouble
* a
, wxDouble
* b
, wxDouble
* c
,
998 wxDouble
* d
, wxDouble
* tx
, wxDouble
* ty
) const
1001 m_matrix
->GetElements(elements
);
1002 if (a
) *a
= elements
[0];
1003 if (b
) *b
= elements
[1];
1004 if (c
) *c
= elements
[2];
1005 if (d
) *d
= elements
[3];
1006 if (tx
) *tx
= elements
[4];
1007 if (ty
) *ty
= elements
[5];
1010 // makes this the inverse matrix
1011 void wxGDIPlusMatrixData::Invert()
1016 // returns true if the elements of the transformation matrix are equal ?
1017 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const
1019 return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE
;
1022 // return true if this is the identity matrix
1023 bool wxGDIPlusMatrixData::IsIdentity() const
1025 return m_matrix
->IsIdentity() == TRUE
;
1032 // add the translation to this matrix
1033 void wxGDIPlusMatrixData::Translate( wxDouble dx
, wxDouble dy
)
1035 m_matrix
->Translate(dx
,dy
);
1038 // add the scale to this matrix
1039 void wxGDIPlusMatrixData::Scale( wxDouble xScale
, wxDouble yScale
)
1041 m_matrix
->Scale(xScale
,yScale
);
1044 // add the rotation to this matrix (radians)
1045 void wxGDIPlusMatrixData::Rotate( wxDouble angle
)
1047 m_matrix
->Rotate( RadToDeg(angle
) );
1051 // apply the transforms
1054 // applies that matrix to the point
1055 void wxGDIPlusMatrixData::TransformPoint( wxDouble
*x
, wxDouble
*y
) const
1058 m_matrix
->TransformPoints(&pt
);
1063 // applies the matrix except for translations
1064 void wxGDIPlusMatrixData::TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const
1067 m_matrix
->TransformVectors(&pt
);
1072 // returns the native representation
1073 void * wxGDIPlusMatrixData::GetNativeMatrix() const
1078 //-----------------------------------------------------------------------------
1079 // wxGDIPlusContext implementation
1080 //-----------------------------------------------------------------------------
1082 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext
,wxGraphicsContext
)
1083 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMeasuringContext
,wxGDIPlusContext
)
1085 class wxGDIPlusOffsetHelper
1088 wxGDIPlusOffsetHelper( Graphics
* gr
, bool offset
)
1093 m_gr
->TranslateTransform( 0.5, 0.5 );
1095 ~wxGDIPlusOffsetHelper( )
1098 m_gr
->TranslateTransform( -0.5, -0.5 );
1105 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
)
1106 : wxGraphicsContext(renderer
)
1109 m_context
= new Graphics( hdc
);
1115 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
)
1116 : wxGraphicsContext(renderer
)
1119 m_context
= new Graphics( hwnd
);
1120 RECT rect
= wxGetWindowRect(hwnd
);
1121 m_width
= rect
.right
- rect
.left
;
1122 m_height
= rect
.bottom
- rect
.top
;
1126 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
)
1127 : wxGraphicsContext(renderer
)
1134 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL
)
1139 void wxGDIPlusContext::Init()
1148 void wxGDIPlusContext::SetDefaults()
1150 m_context
->SetTextRenderingHint(TextRenderingHintSystemDefault
);
1151 m_context
->SetPixelOffsetMode(PixelOffsetModeHalf
);
1152 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
1153 m_state1
= m_context
->Save();
1154 m_state2
= m_context
->Save();
1156 // Setup page scale, based on DPI ratio.
1157 // Antecedent should be 100dpi when the default page unit (UnitDisplay)
1158 // is used. Page unit UnitDocument would require 300dpi instead.
1159 // Note that calling SetPageScale() does not have effect on non-printing
1160 // DCs (that is, any other than wxPrinterDC or wxEnhMetaFileDC).
1161 REAL dpiRatio
= 100.0 / m_context
->GetDpiY();
1162 m_context
->SetPageScale(dpiRatio
);
1165 wxGDIPlusContext::~wxGDIPlusContext()
1169 m_context
->Restore( m_state2
);
1170 m_context
->Restore( m_state1
);
1176 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
1178 Region
rgn((HRGN
)region
.GetHRGN());
1179 m_context
->SetClip(&rgn
,CombineModeIntersect
);
1182 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1184 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
1187 void wxGDIPlusContext::ResetClip()
1189 m_context
->ResetClip();
1192 void wxGDIPlusContext::StrokeLines( size_t n
, const wxPoint2DDouble
*points
)
1194 if (m_composition
== wxCOMPOSITION_DEST
)
1197 if ( !m_pen
.IsNull() )
1199 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1200 Point
*cpoints
= new Point
[n
];
1201 for (size_t i
= 0; i
< n
; i
++)
1203 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1204 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1206 } // for (size_t i = 0; i < n; i++)
1207 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1212 void wxGDIPlusContext::DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode
WXUNUSED(fillStyle
) )
1214 if (m_composition
== wxCOMPOSITION_DEST
)
1217 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1218 Point
*cpoints
= new Point
[n
];
1219 for (size_t i
= 0; i
< n
; i
++)
1221 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1222 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1224 } // for (int i = 0; i < n; i++)
1225 if ( !m_brush
.IsNull() )
1226 m_context
->FillPolygon( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() , cpoints
, n
) ;
1227 if ( !m_pen
.IsNull() )
1228 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1232 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
& path
)
1234 if (m_composition
== wxCOMPOSITION_DEST
)
1237 if ( !m_pen
.IsNull() )
1239 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1240 m_context
->DrawPath( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath
*) path
.GetNativePath() );
1244 void wxGDIPlusContext::FillPath( const wxGraphicsPath
& path
, wxPolygonFillMode fillStyle
)
1246 if (m_composition
== wxCOMPOSITION_DEST
)
1249 if ( !m_brush
.IsNull() )
1251 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1252 ((GraphicsPath
*) path
.GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1253 m_context
->FillPath( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() ,
1254 (GraphicsPath
*) path
.GetNativePath());
1258 bool wxGDIPlusContext::SetAntialiasMode(wxAntialiasMode antialias
)
1260 if (m_antialias
== antialias
)
1263 m_antialias
= antialias
;
1265 SmoothingMode antialiasMode
;
1268 case wxANTIALIAS_DEFAULT
:
1269 antialiasMode
= SmoothingModeHighQuality
;
1271 case wxANTIALIAS_NONE
:
1272 antialiasMode
= SmoothingModeNone
;
1277 m_context
->SetSmoothingMode(antialiasMode
);
1281 bool wxGDIPlusContext::SetCompositionMode(wxCompositionMode op
)
1283 if ( m_composition
== op
)
1288 if (m_composition
== wxCOMPOSITION_DEST
)
1291 CompositingMode cop
;
1294 case wxCOMPOSITION_SOURCE
:
1295 cop
= CompositingModeSourceCopy
;
1297 case wxCOMPOSITION_OVER
:
1298 cop
= CompositingModeSourceOver
;
1304 m_context
->SetCompositingMode(cop
);
1308 void wxGDIPlusContext::BeginLayer(wxDouble
/* opacity */)
1313 void wxGDIPlusContext::EndLayer()
1318 void wxGDIPlusContext::Rotate( wxDouble angle
)
1320 m_context
->RotateTransform( RadToDeg(angle
) );
1323 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
1325 m_context
->TranslateTransform( dx
, dy
);
1328 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
1330 m_context
->ScaleTransform(xScale
,yScale
);
1333 void wxGDIPlusContext::PushState()
1335 GraphicsState state
= m_context
->Save();
1336 m_stateStack
.push(state
);
1339 void wxGDIPlusContext::PopState()
1341 GraphicsState state
= m_stateStack
.top();
1343 m_context
->Restore(state
);
1346 void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1348 if (m_composition
== wxCOMPOSITION_DEST
)
1351 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bmp
.GetRefData())->GetGDIPlusBitmap();
1354 if( image
->GetWidth() != (UINT
) w
|| image
->GetHeight() != (UINT
) h
)
1356 Rect
drawRect((REAL
) x
, (REAL
)y
, (REAL
)w
, (REAL
)h
);
1357 m_context
->SetPixelOffsetMode( PixelOffsetModeNone
);
1358 m_context
->DrawImage(image
, drawRect
, 0 , 0 , image
->GetWidth()-1, image
->GetHeight()-1, UnitPixel
) ;
1359 m_context
->SetPixelOffsetMode( PixelOffsetModeHalf
);
1362 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1366 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1368 wxGraphicsBitmap bitmap
= GetRenderer()->CreateBitmap(bmp
);
1369 DrawBitmap(bitmap
, x
, y
, w
, h
);
1372 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1374 if (m_composition
== wxCOMPOSITION_DEST
)
1377 // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
1378 // find out by looking at the bitmap data whether there really was alpha in it
1379 HICON hIcon
= (HICON
)icon
.GetHICON();
1381 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1382 if (!GetIconInfo(hIcon
,&iconInfo
))
1385 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
1387 Bitmap
* image
= NULL
;
1389 // if it's not 32 bit, it doesn't have an alpha channel, note that since the conversion doesn't
1390 // work correctly, asking IsAlphaPixelFormat at this point fails as well
1391 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
1393 image
= Bitmap::FromHICON(hIcon
);
1397 size_t width
= interim
.GetWidth();
1398 size_t height
= interim
.GetHeight();
1399 Rect
bounds(0,0,width
,height
);
1402 interim
.LockBits(&bounds
, ImageLockModeRead
,
1403 interim
.GetPixelFormat(),&data
);
1405 bool hasAlpha
= false;
1406 for ( size_t y
= 0 ; y
< height
&& !hasAlpha
; ++y
)
1408 for( size_t x
= 0 ; x
< width
&& !hasAlpha
; ++x
)
1410 ARGB
*dest
= (ARGB
*)((BYTE
*)data
.Scan0
+ data
.Stride
*y
+ x
*4);
1411 if ( ( *dest
& Color::AlphaMask
) != 0 )
1418 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1419 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1423 image
= Bitmap::FromHICON(hIcon
);
1426 interim
.UnlockBits(&data
);
1429 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1432 DeleteObject(iconInfo
.hbmColor
);
1433 DeleteObject(iconInfo
.hbmMask
);
1436 void wxGDIPlusContext::DoDrawFilledText(const wxString
& str
,
1437 wxDouble x
, wxDouble y
,
1438 const wxGraphicsBrush
& brush
)
1440 if (m_composition
== wxCOMPOSITION_DEST
)
1443 wxCHECK_RET( !m_font
.IsNull(),
1444 wxT("wxGDIPlusContext::DrawText - no valid font set") );
1449 wxGDIPlusFontData
* const
1450 fontData
= (wxGDIPlusFontData
*)m_font
.GetRefData();
1451 wxGDIPlusBrushData
* const
1452 brushData
= (wxGDIPlusBrushData
*)brush
.GetRefData();
1454 m_context
->DrawString
1456 str
.wc_str(*wxConvUI
), // string to draw, always Unicode
1457 -1, // length: string is NUL-terminated
1458 fontData
->GetGDIPlusFont(),
1460 StringFormat::GenericTypographic(),
1461 brushData
? brushData
->GetGDIPlusBrush()
1462 : fontData
->GetGDIPlusBrush()
1466 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1467 wxDouble
*descent
, wxDouble
*externalLeading
) const
1469 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1471 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1472 FontFamily ffamily
;
1473 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1475 f
->GetFamily(&ffamily
) ;
1477 REAL factorY
= m_context
->GetDpiY() / 72.0 ;
1479 REAL rDescent
= ffamily
.GetCellDescent(FontStyleRegular
) *
1480 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1481 REAL rAscent
= ffamily
.GetCellAscent(FontStyleRegular
) *
1482 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1483 REAL rHeight
= ffamily
.GetLineSpacing(FontStyleRegular
) *
1484 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1487 *height
= rHeight
* factorY
;
1489 *descent
= rDescent
* factorY
;
1490 if ( externalLeading
)
1491 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
;
1492 // measuring empty strings is not guaranteed, so do it by hand
1500 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1501 StringFormat
strFormat( StringFormat::GenericTypographic() );
1502 strFormat
.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces
| strFormat
.GetFormatFlags() );
1505 m_context
->MeasureString((const wchar_t *) s
, wcslen(s
) , f
, layoutRect
, &strFormat
, &bounds
) ;
1507 *width
= bounds
.Width
;
1509 *height
= bounds
.Height
;
1513 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1516 widths
.Add(0, text
.length());
1518 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1523 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1524 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
1525 size_t len
= wcslen( ws
) ;
1526 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1528 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1529 StringFormat
strFormat( StringFormat::GenericTypographic() );
1531 size_t startPosition
= 0;
1532 size_t remainder
= len
;
1533 const size_t maxSpan
= 32;
1534 CharacterRange
* ranges
= new CharacterRange
[maxSpan
] ;
1535 Region
* regions
= new Region
[maxSpan
];
1537 while( remainder
> 0 )
1539 size_t span
= wxMin( maxSpan
, remainder
);
1541 for( size_t i
= 0 ; i
< span
; ++i
)
1543 ranges
[i
].First
= 0 ;
1544 ranges
[i
].Length
= startPosition
+i
+1 ;
1546 strFormat
.SetMeasurableCharacterRanges(span
,ranges
);
1547 strFormat
.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces
| strFormat
.GetFormatFlags() );
1548 m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,span
,regions
) ;
1551 for ( size_t i
= 0 ; i
< span
; ++i
)
1553 regions
[i
].GetBounds(&bbox
,m_context
);
1554 widths
[startPosition
+i
] = bbox
.Width
;
1557 startPosition
+= span
;
1564 bool wxGDIPlusContext::ShouldOffset() const
1567 if ( !m_pen
.IsNull() )
1569 penwidth
= (int)((wxGDIPlusPenData
*)m_pen
.GetRefData())->GetWidth();
1570 if ( penwidth
== 0 )
1573 return ( penwidth
% 2 ) == 1;
1576 void* wxGDIPlusContext::GetNativeContext()
1581 // concatenates this transform with the current transform of this context
1582 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
& matrix
)
1584 m_context
->MultiplyTransform((Matrix
*) matrix
.GetNativeMatrix());
1587 // sets the transform of this context
1588 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
& matrix
)
1590 m_context
->SetTransform((Matrix
*) matrix
.GetNativeMatrix());
1593 // gets the matrix of this context
1594 wxGraphicsMatrix
wxGDIPlusContext::GetTransform() const
1596 wxGraphicsMatrix matrix
= CreateMatrix();
1597 m_context
->GetTransform((Matrix
*) matrix
.GetNativeMatrix());
1601 void wxGDIPlusContext::GetSize( wxDouble
* width
, wxDouble
*height
)
1606 //-----------------------------------------------------------------------------
1607 // wxGDIPlusRenderer declaration
1608 //-----------------------------------------------------------------------------
1610 class wxGDIPlusRenderer
: public wxGraphicsRenderer
1619 virtual ~wxGDIPlusRenderer()
1621 if ( m_loaded
== 1 )
1629 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
1631 virtual wxGraphicsContext
* CreateContext( const wxMemoryDC
& dc
);
1633 virtual wxGraphicsContext
* CreateContext( const wxPrinterDC
& dc
);
1635 virtual wxGraphicsContext
* CreateContext( const wxEnhMetaFileDC
& dc
);
1637 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
1639 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
1641 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
1643 virtual wxGraphicsContext
* CreateMeasuringContext();
1647 virtual wxGraphicsPath
CreatePath();
1651 virtual wxGraphicsMatrix
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
1652 wxDouble tx
=0.0, wxDouble ty
=0.0);
1655 virtual wxGraphicsPen
CreatePen(const wxPen
& pen
) ;
1657 virtual wxGraphicsBrush
CreateBrush(const wxBrush
& brush
) ;
1659 virtual wxGraphicsBrush
1660 CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
1661 wxDouble x2
, wxDouble y2
,
1662 const wxGraphicsGradientStops
& stops
);
1664 virtual wxGraphicsBrush
1665 CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
1666 wxDouble xc
, wxDouble yc
,
1668 const wxGraphicsGradientStops
& stops
);
1670 virtual wxGraphicsFont
CreateFont( const wxFont
&font
, const wxColour
&col
= *wxBLACK
) ;
1672 // create a native bitmap representation
1673 virtual wxGraphicsBitmap
CreateBitmap( const wxBitmap
&bitmap
);
1675 // create a graphics bitmap from a native bitmap
1676 virtual wxGraphicsBitmap
CreateBitmapFromNativeBitmap( void* bitmap
);
1678 // create a subimage from a native image representation
1679 virtual wxGraphicsBitmap
CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
1682 bool EnsureIsLoaded();
1685 friend class wxGDIPlusRendererModule
;
1689 ULONG_PTR m_gditoken
;
1691 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
)
1694 //-----------------------------------------------------------------------------
1695 // wxGDIPlusRenderer implementation
1696 //-----------------------------------------------------------------------------
1698 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
)
1700 static wxGDIPlusRenderer gs_GDIPlusRenderer
;
1702 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1704 return &gs_GDIPlusRenderer
;
1707 bool wxGDIPlusRenderer::EnsureIsLoaded()
1709 // load gdiplus.dll if not yet loaded, but don't bother doing it again
1710 // if we already tried and failed (we don't want to spend lot of time
1711 // returning NULL from wxGraphicsContext::Create(), which may be called
1712 // relatively frequently):
1713 if ( m_loaded
== -1 )
1718 return m_loaded
== 1;
1721 // call EnsureIsLoaded() and return returnOnFail value if it fails
1722 #define ENSURE_LOADED_OR_RETURN(returnOnFail) \
1723 if ( !EnsureIsLoaded() ) \
1724 return (returnOnFail)
1727 void wxGDIPlusRenderer::Load()
1729 GdiplusStartupInput input
;
1730 GdiplusStartupOutput output
;
1731 if ( GdiplusStartup(&m_gditoken
,&input
,&output
) == Gdiplus::Ok
)
1733 wxLogTrace("gdiplus", "successfully initialized GDI+");
1738 wxLogTrace("gdiplus", "failed to initialize GDI+, missing gdiplus.dll?");
1743 void wxGDIPlusRenderer::Unload()
1747 GdiplusShutdown(m_gditoken
);
1750 m_loaded
= -1; // next Load() will try again
1753 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
)
1755 ENSURE_LOADED_OR_RETURN(NULL
);
1756 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1757 wxSize sz
= dc
.GetSize();
1758 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1761 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxPrinterDC
& dc
)
1763 ENSURE_LOADED_OR_RETURN(NULL
);
1764 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1765 wxSize sz
= dc
.GetSize();
1766 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1769 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxEnhMetaFileDC
& dc
)
1771 ENSURE_LOADED_OR_RETURN(NULL
);
1772 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1773 wxSize sz
= dc
.GetSize();
1774 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1777 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxMemoryDC
& dc
)
1779 ENSURE_LOADED_OR_RETURN(NULL
);
1780 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1781 wxSize sz
= dc
.GetSize();
1782 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1785 wxGraphicsContext
* wxGDIPlusRenderer::CreateMeasuringContext()
1787 ENSURE_LOADED_OR_RETURN(NULL
);
1788 return new wxGDIPlusMeasuringContext(this);
1791 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context
)
1793 ENSURE_LOADED_OR_RETURN(NULL
);
1794 return new wxGDIPlusContext(this,(Graphics
*) context
);
1798 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window
)
1800 ENSURE_LOADED_OR_RETURN(NULL
);
1801 return new wxGDIPlusContext(this,(HWND
) window
);
1804 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( wxWindow
* window
)
1806 ENSURE_LOADED_OR_RETURN(NULL
);
1807 return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() );
1812 wxGraphicsPath
wxGDIPlusRenderer::CreatePath()
1814 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath
);
1816 m
.SetRefData( new wxGDIPlusPathData(this));
1823 wxGraphicsMatrix
wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1824 wxDouble tx
, wxDouble ty
)
1827 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix
);
1829 wxGDIPlusMatrixData
* data
= new wxGDIPlusMatrixData( this );
1830 data
->Set( a
,b
,c
,d
,tx
,ty
) ;
1835 wxGraphicsPen
wxGDIPlusRenderer::CreatePen(const wxPen
& pen
)
1837 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen
);
1838 if ( !pen
.Ok() || pen
.GetStyle() == wxTRANSPARENT
)
1839 return wxNullGraphicsPen
;
1843 p
.SetRefData(new wxGDIPlusPenData( this, pen
));
1848 wxGraphicsBrush
wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush
)
1850 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
1851 if ( !brush
.Ok() || brush
.GetStyle() == wxTRANSPARENT
)
1852 return wxNullGraphicsBrush
;
1856 p
.SetRefData(new wxGDIPlusBrushData( this, brush
));
1862 wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
1863 wxDouble x2
, wxDouble y2
,
1864 const wxGraphicsGradientStops
& stops
)
1866 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
1868 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
1869 d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, stops
);
1875 wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
1876 wxDouble xc
, wxDouble yc
,
1878 const wxGraphicsGradientStops
& stops
)
1880 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
1882 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
1883 d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,stops
);
1889 wxGraphicsFont
wxGDIPlusRenderer::CreateFont( const wxFont
&font
, const wxColour
&col
)
1891 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont
);
1895 p
.SetRefData(new wxGDIPlusFontData( this , font
, col
));
1899 return wxNullGraphicsFont
;
1902 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmap( const wxBitmap
&bitmap
)
1904 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
1908 p
.SetRefData(new wxGDIPlusBitmapData( this , bitmap
));
1912 return wxNullGraphicsBitmap
;
1915 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmapFromNativeBitmap( void *bitmap
)
1917 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
1918 if ( bitmap
!= NULL
)
1921 p
.SetRefData(new wxGDIPlusBitmapData( this , (Bitmap
*) bitmap
));
1925 return wxNullGraphicsBitmap
;
1928 wxGraphicsBitmap
wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1930 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
1931 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bitmap
.GetRefData())->GetGDIPlusBitmap();
1935 p
.SetRefData(new wxGDIPlusBitmapData( this , image
->Clone( (REAL
) x
, (REAL
) y
, (REAL
) w
, (REAL
) h
, PixelFormat32bppPARGB
) ));
1939 return wxNullGraphicsBitmap
;
1942 // Shutdown GDI+ at app exit, before possible dll unload
1943 class wxGDIPlusRendererModule
: public wxModule
1946 virtual bool OnInit() { return true; }
1947 virtual void OnExit() { gs_GDIPlusRenderer
.Unload(); }
1950 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule
)
1953 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule
, wxModule
)
1955 // ----------------------------------------------------------------------------
1956 // wxMSW-specific parts of wxGCDC
1957 // ----------------------------------------------------------------------------
1959 WXHDC
wxGCDC::AcquireHDC()
1961 wxGraphicsContext
* const gc
= GetGraphicsContext();
1965 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
1966 return g
? g
->GetHDC() : NULL
;
1969 void wxGCDC::ReleaseHDC(WXHDC hdc
)
1974 wxGraphicsContext
* const gc
= GetGraphicsContext();
1975 wxCHECK_RET( gc
, "can't release HDC because there is no wxGraphicsContext" );
1977 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
1978 wxCHECK_RET( g
, "can't release HDC because there is no Graphics" );
1980 g
->ReleaseHDC((HDC
)hdc
);
1983 #endif // wxUSE_GRAPHICS_CONTEXT