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/dcgraph.h"
47 WX_DECLARE_STACK(GraphicsState
, GraphicsStates
);
49 //-----------------------------------------------------------------------------
51 //-----------------------------------------------------------------------------
53 const double RAD2DEG
= 180.0 / M_PI
;
55 //-----------------------------------------------------------------------------
57 //-----------------------------------------------------------------------------
59 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
60 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
62 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
63 static inline double RadToDeg(double deg
) { return (deg
* 180.0) / M_PI
; }
65 //-----------------------------------------------------------------------------
66 // device context implementation
68 // more and more of the dc functionality should be implemented by calling
69 // the appropricate wxGDIPlusContext, but we will have to do that step by step
70 // also coordinate conversions should be moved to native matrix ops
71 //-----------------------------------------------------------------------------
73 // we always stock two context states, one at entry, to be able to preserve the
74 // state we were called with, the other one after changing to HI Graphics orientation
75 // (this one is used for getting back clippings etc)
77 //-----------------------------------------------------------------------------
78 // wxGraphicsPath implementation
79 //-----------------------------------------------------------------------------
81 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
83 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
87 class wxGDIPlusPathData
: public wxGraphicsPathData
90 wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
= NULL
);
93 virtual wxGraphicsObjectRefData
*Clone() const;
96 // These are the path primitives from which everything else can be constructed
99 // begins a new subpath at (x,y)
100 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
102 // adds a straight line from the current point to (x,y)
103 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
105 // adds a cubic Bezier curve from the current point, using two control points and an end point
106 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
109 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
110 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
112 // gets the last point of the current path, (0,0) if not yet set
113 virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const;
116 virtual void AddPath( const wxGraphicsPathData
* path
);
118 // closes the current sub-path
119 virtual void CloseSubpath();
122 // These are convenience functions which - if not available natively will be assembled
123 // using the primitives from above
126 // appends a rectangle as a new closed subpath
127 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
130 // appends an ellipsis as a new closed subpath fitting the passed rectangle
131 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
133 // 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)
134 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
137 // returns the native path
138 virtual void * GetNativePath() const { return m_path
; }
140 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
141 virtual void UnGetNativePath(void * WXUNUSED(path
)) const {}
143 // transforms each point of this path by the matrix
144 virtual void Transform( const wxGraphicsMatrixData
* matrix
) ;
146 // gets the bounding box enclosing all points (possibly including control points)
147 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const;
149 virtual bool Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
) const;
152 GraphicsPath
* m_path
;
155 class wxGDIPlusMatrixData
: public wxGraphicsMatrixData
158 wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
= NULL
) ;
159 virtual ~wxGDIPlusMatrixData() ;
161 virtual wxGraphicsObjectRefData
* Clone() const ;
163 // concatenates the matrix
164 virtual void Concat( const wxGraphicsMatrixData
*t
);
166 // sets the matrix to the respective values
167 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
168 wxDouble tx
=0.0, wxDouble ty
=0.0);
170 // gets the component valuess of the matrix
171 virtual void Get(wxDouble
* a
=NULL
, wxDouble
* b
=NULL
, wxDouble
* c
=NULL
,
172 wxDouble
* d
=NULL
, wxDouble
* tx
=NULL
, wxDouble
* ty
=NULL
) const;
174 // makes this the inverse matrix
175 virtual void Invert();
177 // returns true if the elements of the transformation matrix are equal ?
178 virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ;
180 // return true if this is the identity matrix
181 virtual bool IsIdentity() const;
187 // add the translation to this matrix
188 virtual void Translate( wxDouble dx
, wxDouble dy
);
190 // add the scale to this matrix
191 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
193 // add the rotation to this matrix (radians)
194 virtual void Rotate( wxDouble angle
);
197 // apply the transforms
200 // applies that matrix to the point
201 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
) const;
203 // applies the matrix except for translations
204 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const;
206 // returns the native representation
207 virtual void * GetNativeMatrix() const;
212 class wxGDIPlusPenData
: public wxGraphicsObjectRefData
215 wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
220 virtual wxDouble
GetWidth() { return m_width
; }
221 virtual Pen
* GetGDIPlusPen() { return m_pen
; }
231 class wxGDIPlusBrushData
: public wxGraphicsObjectRefData
234 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
);
235 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
236 ~wxGDIPlusBrushData ();
238 void CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
239 const wxColour
&c1
, const wxColour
&c2
);
240 void CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
241 const wxColour
&oColor
, const wxColour
&cColor
);
242 virtual Brush
* GetGDIPlusBrush() { return m_brush
; }
250 GraphicsPath
* m_brushPath
;
253 class WXDLLIMPEXP_CORE wxGDIPlusBitmapData
: public wxGraphicsObjectRefData
256 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
);
257 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, const wxBitmap
&bmp
);
258 ~wxGDIPlusBitmapData ();
260 virtual Bitmap
* GetGDIPlusBitmap() { return m_bitmap
; }
267 class wxGDIPlusFontData
: public wxGraphicsObjectRefData
270 wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
, const wxColour
& col
);
271 ~wxGDIPlusFontData();
273 virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; }
274 virtual Font
* GetGDIPlusFont() { return m_font
; }
280 class wxGDIPlusContext
: public wxGraphicsContext
283 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
);
284 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
);
285 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
);
288 virtual ~wxGDIPlusContext();
290 virtual void Clip( const wxRegion
®ion
);
291 // clips drawings to the rect
292 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
294 // resets the clipping to original extent
295 virtual void ResetClip();
297 virtual void * GetNativeContext();
299 virtual void StrokePath( const wxGraphicsPath
& p
);
300 virtual void FillPath( const wxGraphicsPath
& p
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
302 // stroke lines connecting each of the points
303 virtual void StrokeLines( size_t n
, const wxPoint2DDouble
*points
);
306 virtual void DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
308 virtual bool SetAntialiasMode(wxAntialiasMode antialias
);
310 virtual bool SetCompositionMode(wxCompositionMode op
);
312 virtual void BeginLayer(wxDouble opacity
);
314 virtual void EndLayer();
316 virtual void Translate( wxDouble dx
, wxDouble dy
);
317 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
318 virtual void Rotate( wxDouble angle
);
320 // concatenates this transform with the current transform of this context
321 virtual void ConcatTransform( const wxGraphicsMatrix
& matrix
);
323 // sets the transform of this context
324 virtual void SetTransform( const wxGraphicsMatrix
& matrix
);
326 // gets the matrix of this context
327 virtual wxGraphicsMatrix
GetTransform() const;
329 virtual void DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
330 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
331 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
332 virtual void PushState();
333 virtual void PopState();
335 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
336 wxDouble
*descent
, wxDouble
*externalLeading
) const;
337 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
338 virtual bool ShouldOffset() const;
339 virtual void GetSize( wxDouble
* width
, wxDouble
*height
);
345 virtual void DoDrawText(const wxString
& str
, wxDouble x
, wxDouble y
)
346 { DoDrawFilledText(str
, x
, y
, wxNullGraphicsBrush
); }
347 virtual void DoDrawFilledText(const wxString
& str
, wxDouble x
, wxDouble y
,
348 const wxGraphicsBrush
& backgroundBrush
);
351 GraphicsStates m_stateStack
;
352 GraphicsState m_state1
;
353 GraphicsState m_state2
;
358 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext
)
361 class wxGDIPlusMeasuringContext
: public wxGDIPlusContext
364 wxGDIPlusMeasuringContext( wxGraphicsRenderer
* renderer
) : wxGDIPlusContext( renderer
, m_hdc
= GetDC(NULL
), 1000, 1000 )
367 wxGDIPlusMeasuringContext()
371 virtual ~wxGDIPlusMeasuringContext()
373 ReleaseDC( NULL
, m_hdc
);
378 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMeasuringContext
)
381 //-----------------------------------------------------------------------------
382 // wxGDIPlusPen implementation
383 //-----------------------------------------------------------------------------
385 wxGDIPlusPenData::~wxGDIPlusPenData()
392 void wxGDIPlusPenData::Init()
399 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
400 : wxGraphicsObjectRefData(renderer
)
403 m_width
= pen
.GetWidth();
407 m_pen
= new Pen(Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
408 pen
.GetColour().Green() , pen
.GetColour().Blue() ), m_width
);
411 switch ( pen
.GetCap() )
417 case wxCAP_PROJECTING
:
422 cap
= LineCapFlat
; // TODO verify
429 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
432 switch ( pen
.GetJoin() )
435 join
= LineJoinBevel
;
439 join
= LineJoinMiter
;
443 join
= LineJoinRound
;
447 join
= LineJoinMiter
;
451 m_pen
->SetLineJoin(join
);
453 m_pen
->SetDashStyle(DashStyleSolid
);
455 DashStyle dashStyle
= DashStyleSolid
;
456 switch ( pen
.GetStyle() )
462 dashStyle
= DashStyleDot
;
466 dashStyle
= DashStyleDash
; // TODO verify
470 dashStyle
= DashStyleDash
;
474 dashStyle
= DashStyleDashDot
;
478 dashStyle
= DashStyleCustom
;
480 int count
= pen
.GetDashes( &dashes
);
481 if ((dashes
!= NULL
) && (count
> 0))
483 REAL
*userLengths
= new REAL
[count
];
484 for ( int i
= 0; i
< count
; ++i
)
486 userLengths
[i
] = dashes
[i
];
488 m_pen
->SetDashPattern( userLengths
, count
);
489 delete[] userLengths
;
495 wxBitmap
* bmp
= pen
.GetStipple();
496 if ( bmp
&& bmp
->Ok() )
498 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
499 m_penBrush
= new TextureBrush(m_penImage
);
500 m_pen
->SetBrush( m_penBrush
);
506 if ( pen
.GetStyle() >= wxFIRST_HATCH
&& pen
.GetStyle() <= wxLAST_HATCH
)
508 HatchStyle style
= HatchStyleHorizontal
;
509 switch( pen
.GetStyle() )
511 case wxBDIAGONAL_HATCH
:
512 style
= HatchStyleBackwardDiagonal
;
514 case wxCROSSDIAG_HATCH
:
515 style
= HatchStyleDiagonalCross
;
517 case wxFDIAGONAL_HATCH
:
518 style
= HatchStyleForwardDiagonal
;
521 style
= HatchStyleCross
;
523 case wxHORIZONTAL_HATCH
:
524 style
= HatchStyleHorizontal
;
526 case wxVERTICAL_HATCH
:
527 style
= HatchStyleVertical
;
531 m_penBrush
= new HatchBrush(style
,Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() ,
532 pen
.GetColour().Green() , pen
.GetColour().Blue() ), Color::Transparent
);
533 m_pen
->SetBrush( m_penBrush
);
537 if ( dashStyle
!= DashStyleSolid
)
538 m_pen
->SetDashStyle(dashStyle
);
541 //-----------------------------------------------------------------------------
542 // wxGDIPlusBrush implementation
543 //-----------------------------------------------------------------------------
545 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
)
546 : wxGraphicsObjectRefData(renderer
)
551 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
552 : wxGraphicsObjectRefData(renderer
)
555 if ( brush
.GetStyle() == wxSOLID
)
557 m_brush
= new SolidBrush( Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
558 brush
.GetColour().Green() , brush
.GetColour().Blue() ) );
560 else if ( brush
.IsHatch() )
562 HatchStyle style
= HatchStyleHorizontal
;
563 switch( brush
.GetStyle() )
565 case wxBDIAGONAL_HATCH
:
566 style
= HatchStyleBackwardDiagonal
;
568 case wxCROSSDIAG_HATCH
:
569 style
= HatchStyleDiagonalCross
;
571 case wxFDIAGONAL_HATCH
:
572 style
= HatchStyleForwardDiagonal
;
575 style
= HatchStyleCross
;
577 case wxHORIZONTAL_HATCH
:
578 style
= HatchStyleHorizontal
;
580 case wxVERTICAL_HATCH
:
581 style
= HatchStyleVertical
;
585 m_brush
= new HatchBrush(style
,Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() ,
586 brush
.GetColour().Green() , brush
.GetColour().Blue() ), Color::Transparent
);
590 wxBitmap
* bmp
= brush
.GetStipple();
591 if ( bmp
&& bmp
->Ok() )
593 wxDELETE( m_brushImage
);
594 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE());
595 m_brush
= new TextureBrush(m_brushImage
);
600 wxGDIPlusBrushData::~wxGDIPlusBrushData()
607 void wxGDIPlusBrushData::Init()
614 void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
)
616 m_brush
= new LinearGradientBrush( PointF( x1
,y1
) , PointF( x2
,y2
),
617 Color( c1
.Alpha(), c1
.Red(),c1
.Green() , c1
.Blue() ),
618 Color( c2
.Alpha(), c2
.Red(),c2
.Green() , c2
.Blue() ));
621 void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
622 const wxColour
&oColor
, const wxColour
&cColor
)
624 // Create a path that consists of a single circle.
625 m_brushPath
= new GraphicsPath();
626 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
), (REAL
)(2*radius
), (REAL
)(2*radius
));
628 PathGradientBrush
*b
= new PathGradientBrush(m_brushPath
);
630 b
->SetCenterPoint( PointF(xo
,yo
));
631 b
->SetCenterColor(Color( oColor
.Alpha(), oColor
.Red(),oColor
.Green() , oColor
.Blue() ));
633 Color colors
[] = {Color( cColor
.Alpha(), cColor
.Red(),cColor
.Green() , cColor
.Blue() )};
635 b
->SetSurroundColors(colors
, &count
);
638 //-----------------------------------------------------------------------------
639 // wxGDIPlusFont implementation
640 //-----------------------------------------------------------------------------
642 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont
&font
,
643 const wxColour
& col
) : wxGraphicsObjectRefData( renderer
)
648 wxWCharBuffer s
= font
.GetFaceName().wc_str( *wxConvUI
);
649 int size
= font
.GetPointSize();
650 int style
= FontStyleRegular
;
651 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
652 style
|= FontStyleItalic
;
653 if ( font
.GetUnderlined() )
654 style
|= FontStyleUnderline
;
655 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
656 style
|= FontStyleBold
;
657 m_font
= new Font( s
, size
, style
);
658 m_textBrush
= new SolidBrush( Color( col
.Alpha() , col
.Red() ,
659 col
.Green() , col
.Blue() ));
662 wxGDIPlusFontData::~wxGDIPlusFontData()
668 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
669 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
670 // bytes as parameter, since there is no real copying of the data going in, only references are stored
671 // m_helper has to be kept alive as well
673 //-----------------------------------------------------------------------------
674 // wxGDIPlusBitmapData implementation
675 //-----------------------------------------------------------------------------
677 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
) :
678 wxGraphicsObjectRefData( renderer
), m_bitmap( bitmap
)
683 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
,
684 const wxBitmap
&bmp
) : wxGraphicsObjectRefData( renderer
)
689 Bitmap
* image
= NULL
;
692 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ;
694 size_t width
= interim
.GetWidth();
695 size_t height
= interim
.GetHeight();
696 Rect
bounds(0,0,width
,height
);
698 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
700 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
701 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
703 BitmapData dataMask
;
704 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
705 interimMask
.GetPixelFormat(),&dataMask
);
708 BitmapData imageData
;
709 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
711 BYTE maskPattern
= 0 ;
715 for ( size_t y
= 0 ; y
< height
; ++y
)
718 for( size_t x
= 0 ; x
< width
; ++x
)
723 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
727 maskPattern
= maskPattern
>> 1;
729 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
730 if ( (maskByte
& maskPattern
) == 0 )
735 interim
.GetPixel(x
,y
,&c
) ;
736 *dest
= (c
.GetValue() | Color::AlphaMask
);
741 image
->UnlockBits(&imageData
);
743 interimMask
.UnlockBits(&dataMask
);
744 interim
.UnlockBits(&dataMask
);
748 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE());
749 if ( bmp
.HasAlpha() && GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
751 size_t width
= image
->GetWidth();
752 size_t height
= image
->GetHeight();
753 Rect
bounds(0,0,width
,height
);
754 static BitmapData data
;
758 m_helper
->LockBits(&bounds
, ImageLockModeRead
,
759 m_helper
->GetPixelFormat(),&data
);
761 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
762 PixelFormat32bppPARGB
, (BYTE
*) data
.Scan0
);
764 m_helper
->UnlockBits(&data
);
771 wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
777 //-----------------------------------------------------------------------------
778 // wxGDIPlusPath implementation
779 //-----------------------------------------------------------------------------
781 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
) : wxGraphicsPathData(renderer
)
786 m_path
= new GraphicsPath();
789 wxGDIPlusPathData::~wxGDIPlusPathData()
794 wxGraphicsObjectRefData
* wxGDIPlusPathData::Clone() const
796 return new wxGDIPlusPathData( GetRenderer() , m_path
->Clone());
803 void wxGDIPlusPathData::MoveToPoint( wxDouble x
, wxDouble y
)
805 m_path
->StartFigure();
806 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
809 void wxGDIPlusPathData::AddLineToPoint( wxDouble x
, wxDouble y
)
811 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
814 void wxGDIPlusPathData::CloseSubpath()
816 m_path
->CloseFigure();
819 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
825 m_path
->GetLastPoint(&start
);
826 m_path
->AddBezier(start
,c1
,c2
,end
);
829 // gets the last point of the current path, (0,0) if not yet set
830 void wxGDIPlusPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const
833 m_path
->GetLastPoint(&start
);
838 void wxGDIPlusPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
840 double sweepAngle
= endAngle
- startAngle
;
841 if( fabs(sweepAngle
) >= 2*M_PI
)
843 sweepAngle
= 2 * M_PI
;
850 sweepAngle
+= 2 * M_PI
;
855 sweepAngle
-= 2 * M_PI
;
859 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
862 void wxGDIPlusPathData::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
864 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
867 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData
* path
)
869 m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
);
873 // transforms each point of this path by the matrix
874 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData
* matrix
)
876 m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() );
879 // gets the bounding box enclosing all points (possibly including control points)
880 void wxGDIPlusPathData::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const
883 m_path
->GetBounds( &bounds
, NULL
, NULL
) ;
890 bool wxGDIPlusPathData::Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
) const
892 m_path
->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
893 return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE
;
896 //-----------------------------------------------------------------------------
897 // wxGDIPlusMatrixData implementation
898 //-----------------------------------------------------------------------------
900 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
)
901 : wxGraphicsMatrixData(renderer
)
906 m_matrix
= new Matrix();
909 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
914 wxGraphicsObjectRefData
*wxGDIPlusMatrixData::Clone() const
916 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix
->Clone());
919 // concatenates the matrix
920 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData
*t
)
922 m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix());
925 // sets the matrix to the respective values
926 void wxGDIPlusMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
927 wxDouble tx
, wxDouble ty
)
929 m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
);
932 // gets the component valuess of the matrix
933 void wxGDIPlusMatrixData::Get(wxDouble
* a
, wxDouble
* b
, wxDouble
* c
,
934 wxDouble
* d
, wxDouble
* tx
, wxDouble
* ty
) const
937 m_matrix
->GetElements(elements
);
938 if (a
) *a
= elements
[0];
939 if (b
) *b
= elements
[1];
940 if (c
) *c
= elements
[2];
941 if (d
) *d
= elements
[3];
942 if (tx
) *tx
= elements
[4];
943 if (ty
) *ty
= elements
[5];
946 // makes this the inverse matrix
947 void wxGDIPlusMatrixData::Invert()
952 // returns true if the elements of the transformation matrix are equal ?
953 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const
955 return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE
;
958 // return true if this is the identity matrix
959 bool wxGDIPlusMatrixData::IsIdentity() const
961 return m_matrix
->IsIdentity() == TRUE
;
968 // add the translation to this matrix
969 void wxGDIPlusMatrixData::Translate( wxDouble dx
, wxDouble dy
)
971 m_matrix
->Translate(dx
,dy
);
974 // add the scale to this matrix
975 void wxGDIPlusMatrixData::Scale( wxDouble xScale
, wxDouble yScale
)
977 m_matrix
->Scale(xScale
,yScale
);
980 // add the rotation to this matrix (radians)
981 void wxGDIPlusMatrixData::Rotate( wxDouble angle
)
983 m_matrix
->Rotate( angle
);
987 // apply the transforms
990 // applies that matrix to the point
991 void wxGDIPlusMatrixData::TransformPoint( wxDouble
*x
, wxDouble
*y
) const
994 m_matrix
->TransformPoints(&pt
);
999 // applies the matrix except for translations
1000 void wxGDIPlusMatrixData::TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const
1003 m_matrix
->TransformVectors(&pt
);
1008 // returns the native representation
1009 void * wxGDIPlusMatrixData::GetNativeMatrix() const
1014 //-----------------------------------------------------------------------------
1015 // wxGDIPlusContext implementation
1016 //-----------------------------------------------------------------------------
1018 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext
,wxGraphicsContext
)
1019 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMeasuringContext
,wxGDIPlusContext
)
1021 class wxGDIPlusOffsetHelper
1024 wxGDIPlusOffsetHelper( Graphics
* gr
, bool offset
)
1029 m_gr
->TranslateTransform( 0.5, 0.5 );
1031 ~wxGDIPlusOffsetHelper( )
1034 m_gr
->TranslateTransform( -0.5, -0.5 );
1041 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
)
1042 : wxGraphicsContext(renderer
)
1045 m_context
= new Graphics( hdc
);
1051 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
)
1052 : wxGraphicsContext(renderer
)
1055 m_context
= new Graphics( hwnd
);
1056 RECT rect
= wxGetWindowRect(hwnd
);
1057 m_width
= rect
.right
- rect
.left
;
1058 m_height
= rect
.bottom
- rect
.top
;
1062 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
)
1063 : wxGraphicsContext(renderer
)
1070 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL
)
1075 void wxGDIPlusContext::Init()
1084 void wxGDIPlusContext::SetDefaults()
1086 m_context
->SetTextRenderingHint(TextRenderingHintSystemDefault
);
1087 m_context
->SetPixelOffsetMode(PixelOffsetModeHalf
);
1088 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
1089 m_state1
= m_context
->Save();
1090 m_state2
= m_context
->Save();
1093 wxGDIPlusContext::~wxGDIPlusContext()
1097 m_context
->Restore( m_state2
);
1098 m_context
->Restore( m_state1
);
1104 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
1106 Region
rgn((HRGN
)region
.GetHRGN());
1107 m_context
->SetClip(&rgn
,CombineModeIntersect
);
1110 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1112 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
1115 void wxGDIPlusContext::ResetClip()
1117 m_context
->ResetClip();
1120 void wxGDIPlusContext::StrokeLines( size_t n
, const wxPoint2DDouble
*points
)
1122 if (m_composition
== wxCOMPOSITION_DEST
)
1125 if ( !m_pen
.IsNull() )
1127 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1128 Point
*cpoints
= new Point
[n
];
1129 for (size_t i
= 0; i
< n
; i
++)
1131 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1132 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1134 } // for (size_t i = 0; i < n; i++)
1135 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1140 void wxGDIPlusContext::DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode
WXUNUSED(fillStyle
) )
1142 if (m_composition
== wxCOMPOSITION_DEST
)
1145 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1146 Point
*cpoints
= new Point
[n
];
1147 for (size_t i
= 0; i
< n
; i
++)
1149 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1150 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1152 } // for (int i = 0; i < n; i++)
1153 if ( !m_brush
.IsNull() )
1154 m_context
->FillPolygon( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() , cpoints
, n
) ;
1155 if ( !m_pen
.IsNull() )
1156 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1160 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
& path
)
1162 if (m_composition
== wxCOMPOSITION_DEST
)
1165 if ( !m_pen
.IsNull() )
1167 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1168 m_context
->DrawPath( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath
*) path
.GetNativePath() );
1172 void wxGDIPlusContext::FillPath( const wxGraphicsPath
& path
, wxPolygonFillMode fillStyle
)
1174 if (m_composition
== wxCOMPOSITION_DEST
)
1177 if ( !m_brush
.IsNull() )
1179 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1180 ((GraphicsPath
*) path
.GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1181 m_context
->FillPath( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() ,
1182 (GraphicsPath
*) path
.GetNativePath());
1186 bool wxGDIPlusContext::SetAntialiasMode(wxAntialiasMode antialias
)
1188 if (m_antialias
== antialias
)
1191 m_antialias
= antialias
;
1193 SmoothingMode antialiasMode
;
1196 case wxANTIALIAS_DEFAULT
:
1197 antialiasMode
= SmoothingModeHighQuality
;
1199 case wxANTIALIAS_NONE
:
1200 antialiasMode
= SmoothingModeNone
;
1205 m_context
->SetSmoothingMode(antialiasMode
);
1209 bool wxGDIPlusContext::SetCompositionMode(wxCompositionMode op
)
1211 if ( m_composition
== op
)
1216 if (m_composition
== wxCOMPOSITION_DEST
)
1219 CompositingMode cop
;
1222 case wxCOMPOSITION_SOURCE
:
1223 cop
= CompositingModeSourceCopy
;
1225 case wxCOMPOSITION_OVER
:
1226 cop
= CompositingModeSourceOver
;
1232 m_context
->SetCompositingMode(cop
);
1236 void wxGDIPlusContext::BeginLayer(wxDouble
/* opacity */)
1241 void wxGDIPlusContext::EndLayer()
1246 void wxGDIPlusContext::Rotate( wxDouble angle
)
1248 m_context
->RotateTransform( RadToDeg(angle
) );
1251 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
1253 m_context
->TranslateTransform( dx
, dy
);
1256 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
1258 m_context
->ScaleTransform(xScale
,yScale
);
1261 void wxGDIPlusContext::PushState()
1263 GraphicsState state
= m_context
->Save();
1264 m_stateStack
.push(state
);
1267 void wxGDIPlusContext::PopState()
1269 GraphicsState state
= m_stateStack
.top();
1271 m_context
->Restore(state
);
1274 void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1276 if (m_composition
== wxCOMPOSITION_DEST
)
1279 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bmp
.GetRefData())->GetGDIPlusBitmap();
1282 if( image
->GetWidth() != (UINT
) w
|| image
->GetHeight() != (UINT
) h
)
1284 Rect
drawRect((REAL
) x
, (REAL
)y
, (REAL
)w
, (REAL
)h
);
1285 m_context
->SetPixelOffsetMode( PixelOffsetModeNone
);
1286 m_context
->DrawImage(image
, drawRect
, 0 , 0 , image
->GetWidth()-1, image
->GetHeight()-1, UnitPixel
) ;
1287 m_context
->SetPixelOffsetMode( PixelOffsetModeHalf
);
1290 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1294 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1296 wxGraphicsBitmap bitmap
= GetRenderer()->CreateBitmap(bmp
);
1297 DrawBitmap(bitmap
, x
, y
, w
, h
);
1300 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1302 if (m_composition
== wxCOMPOSITION_DEST
)
1305 // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
1306 // find out by looking at the bitmap data whether there really was alpha in it
1307 HICON hIcon
= (HICON
)icon
.GetHICON();
1309 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1310 if (!GetIconInfo(hIcon
,&iconInfo
))
1313 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
1315 Bitmap
* image
= NULL
;
1317 // if it's not 32 bit, it doesn't have an alpha channel, note that since the conversion doesn't
1318 // work correctly, asking IsAlphaPixelFormat at this point fails as well
1319 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
1321 image
= Bitmap::FromHICON(hIcon
);
1325 size_t width
= interim
.GetWidth();
1326 size_t height
= interim
.GetHeight();
1327 Rect
bounds(0,0,width
,height
);
1330 interim
.LockBits(&bounds
, ImageLockModeRead
,
1331 interim
.GetPixelFormat(),&data
);
1333 bool hasAlpha
= false;
1334 for ( size_t y
= 0 ; y
< height
&& !hasAlpha
; ++y
)
1336 for( size_t x
= 0 ; x
< width
&& !hasAlpha
; ++x
)
1338 ARGB
*dest
= (ARGB
*)((BYTE
*)data
.Scan0
+ data
.Stride
*y
+ x
*4);
1339 if ( ( *dest
& Color::AlphaMask
) != 0 )
1346 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1347 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1351 image
= Bitmap::FromHICON(hIcon
);
1354 interim
.UnlockBits(&data
);
1357 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1360 DeleteObject(iconInfo
.hbmColor
);
1361 DeleteObject(iconInfo
.hbmMask
);
1364 void wxGDIPlusContext::DoDrawFilledText(const wxString
& str
,
1365 wxDouble x
, wxDouble y
,
1366 const wxGraphicsBrush
& brush
)
1368 if (m_composition
== wxCOMPOSITION_DEST
)
1371 wxCHECK_RET( !m_font
.IsNull(),
1372 wxT("wxGDIPlusContext::DrawText - no valid font set") );
1377 wxGDIPlusFontData
* const
1378 fontData
= (wxGDIPlusFontData
*)m_font
.GetRefData();
1379 wxGDIPlusBrushData
* const
1380 brushData
= (wxGDIPlusBrushData
*)brush
.GetRefData();
1382 m_context
->DrawString
1384 str
.wc_str(*wxConvUI
), // string to draw, always Unicode
1385 -1, // length: string is NUL-terminated
1386 fontData
->GetGDIPlusFont(),
1388 StringFormat::GenericTypographic(),
1389 brushData
? brushData
->GetGDIPlusBrush()
1390 : fontData
->GetGDIPlusBrush()
1394 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1395 wxDouble
*descent
, wxDouble
*externalLeading
) const
1397 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1399 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1400 FontFamily ffamily
;
1401 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1403 f
->GetFamily(&ffamily
) ;
1405 REAL factorY
= m_context
->GetDpiY() / 72.0 ;
1407 REAL rDescent
= ffamily
.GetCellDescent(FontStyleRegular
) *
1408 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1409 REAL rAscent
= ffamily
.GetCellAscent(FontStyleRegular
) *
1410 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1411 REAL rHeight
= ffamily
.GetLineSpacing(FontStyleRegular
) *
1412 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1415 *height
= rHeight
* factorY
;
1417 *descent
= rDescent
* factorY
;
1418 if ( externalLeading
)
1419 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
;
1420 // measuring empty strings is not guaranteed, so do it by hand
1428 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1429 StringFormat
strFormat( StringFormat::GenericTypographic() );
1430 strFormat
.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces
| strFormat
.GetFormatFlags() );
1433 m_context
->MeasureString((const wchar_t *) s
, wcslen(s
) , f
, layoutRect
, &strFormat
, &bounds
) ;
1435 *width
= bounds
.Width
;
1439 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1442 widths
.Add(0, text
.length());
1444 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1449 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1450 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
1451 size_t len
= wcslen( ws
) ;
1452 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1454 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1455 StringFormat
strFormat( StringFormat::GenericTypographic() );
1457 size_t startPosition
= 0;
1458 size_t remainder
= len
;
1459 const size_t maxSpan
= 32;
1460 CharacterRange
* ranges
= new CharacterRange
[maxSpan
] ;
1461 Region
* regions
= new Region
[maxSpan
];
1463 while( remainder
> 0 )
1465 size_t span
= wxMin( maxSpan
, remainder
);
1467 for( size_t i
= 0 ; i
< span
; ++i
)
1469 ranges
[i
].First
= 0 ;
1470 ranges
[i
].Length
= startPosition
+i
+1 ;
1472 strFormat
.SetMeasurableCharacterRanges(span
,ranges
);
1473 strFormat
.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces
| strFormat
.GetFormatFlags() );
1474 m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,span
,regions
) ;
1477 for ( size_t i
= 0 ; i
< span
; ++i
)
1479 regions
[i
].GetBounds(&bbox
,m_context
);
1480 widths
[startPosition
+i
] = bbox
.Width
;
1483 startPosition
+= span
;
1490 bool wxGDIPlusContext::ShouldOffset() const
1493 if ( !m_pen
.IsNull() )
1495 penwidth
= (int)((wxGDIPlusPenData
*)m_pen
.GetRefData())->GetWidth();
1496 if ( penwidth
== 0 )
1499 return ( penwidth
% 2 ) == 1;
1502 void* wxGDIPlusContext::GetNativeContext()
1507 // concatenates this transform with the current transform of this context
1508 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
& matrix
)
1510 m_context
->MultiplyTransform((Matrix
*) matrix
.GetNativeMatrix());
1513 // sets the transform of this context
1514 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
& matrix
)
1516 m_context
->SetTransform((Matrix
*) matrix
.GetNativeMatrix());
1519 // gets the matrix of this context
1520 wxGraphicsMatrix
wxGDIPlusContext::GetTransform() const
1522 wxGraphicsMatrix matrix
= CreateMatrix();
1523 m_context
->GetTransform((Matrix
*) matrix
.GetNativeMatrix());
1527 void wxGDIPlusContext::GetSize( wxDouble
* width
, wxDouble
*height
)
1532 //-----------------------------------------------------------------------------
1533 // wxGDIPlusRenderer declaration
1534 //-----------------------------------------------------------------------------
1536 class wxGDIPlusRenderer
: public wxGraphicsRenderer
1545 virtual ~wxGDIPlusRenderer()
1547 if ( m_loaded
== 1 )
1555 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
1557 virtual wxGraphicsContext
* CreateContext( const wxMemoryDC
& dc
);
1559 virtual wxGraphicsContext
* CreateContext( const wxPrinterDC
& dc
);
1561 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
1563 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
1565 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
1567 virtual wxGraphicsContext
* CreateMeasuringContext();
1571 virtual wxGraphicsPath
CreatePath();
1575 virtual wxGraphicsMatrix
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
1576 wxDouble tx
=0.0, wxDouble ty
=0.0);
1579 virtual wxGraphicsPen
CreatePen(const wxPen
& pen
) ;
1581 virtual wxGraphicsBrush
CreateBrush(const wxBrush
& brush
) ;
1583 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1584 virtual wxGraphicsBrush
CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1585 const wxColour
&c1
, const wxColour
&c2
) ;
1587 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1588 // with radius r and color cColor
1589 virtual wxGraphicsBrush
CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1590 const wxColour
&oColor
, const wxColour
&cColor
) ;
1593 virtual wxGraphicsFont
CreateFont( const wxFont
&font
, const wxColour
&col
= *wxBLACK
) ;
1595 // create a native bitmap representation
1596 virtual wxGraphicsBitmap
CreateBitmap( const wxBitmap
&bitmap
);
1598 // create a graphics bitmap from a native bitmap
1599 virtual wxGraphicsBitmap
CreateBitmapFromNativeBitmap( void* bitmap
);
1601 // create a subimage from a native image representation
1602 virtual wxGraphicsBitmap
CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
1605 bool EnsureIsLoaded();
1608 friend class wxGDIPlusRendererModule
;
1612 ULONG_PTR m_gditoken
;
1614 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
)
1617 //-----------------------------------------------------------------------------
1618 // wxGDIPlusRenderer implementation
1619 //-----------------------------------------------------------------------------
1621 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
)
1623 static wxGDIPlusRenderer gs_GDIPlusRenderer
;
1625 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1627 return &gs_GDIPlusRenderer
;
1630 bool wxGDIPlusRenderer::EnsureIsLoaded()
1632 // load gdiplus.dll if not yet loaded, but don't bother doing it again
1633 // if we already tried and failed (we don't want to spend lot of time
1634 // returning NULL from wxGraphicsContext::Create(), which may be called
1635 // relatively frequently):
1636 if ( m_loaded
== -1 )
1641 return m_loaded
== 1;
1644 // call EnsureIsLoaded() and return returnOnFail value if it fails
1645 #define ENSURE_LOADED_OR_RETURN(returnOnFail) \
1646 if ( !EnsureIsLoaded() ) \
1647 return (returnOnFail)
1650 void wxGDIPlusRenderer::Load()
1652 GdiplusStartupInput input
;
1653 GdiplusStartupOutput output
;
1654 if ( GdiplusStartup(&m_gditoken
,&input
,&output
) == Gdiplus::Ok
)
1656 wxLogTrace("gdiplus", "successfully initialized GDI+");
1661 wxLogTrace("gdiplus", "failed to initialize GDI+, missing gdiplus.dll?");
1666 void wxGDIPlusRenderer::Unload()
1670 GdiplusShutdown(m_gditoken
);
1673 m_loaded
= -1; // next Load() will try again
1676 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
)
1678 ENSURE_LOADED_OR_RETURN(NULL
);
1679 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1680 wxSize sz
= dc
.GetSize();
1681 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1684 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxPrinterDC
& dc
)
1686 ENSURE_LOADED_OR_RETURN(NULL
);
1687 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1688 wxSize sz
= dc
.GetSize();
1689 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1692 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxMemoryDC
& dc
)
1694 ENSURE_LOADED_OR_RETURN(NULL
);
1695 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1696 wxSize sz
= dc
.GetSize();
1697 return new wxGDIPlusContext(this,(HDC
) msw
->GetHDC(), sz
.x
, sz
.y
);
1700 wxGraphicsContext
* wxGDIPlusRenderer::CreateMeasuringContext()
1702 ENSURE_LOADED_OR_RETURN(NULL
);
1703 return new wxGDIPlusMeasuringContext(this);
1706 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context
)
1708 ENSURE_LOADED_OR_RETURN(NULL
);
1709 return new wxGDIPlusContext(this,(Graphics
*) context
);
1713 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window
)
1715 ENSURE_LOADED_OR_RETURN(NULL
);
1716 return new wxGDIPlusContext(this,(HWND
) window
);
1719 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( wxWindow
* window
)
1721 ENSURE_LOADED_OR_RETURN(NULL
);
1722 return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() );
1727 wxGraphicsPath
wxGDIPlusRenderer::CreatePath()
1729 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath
);
1731 m
.SetRefData( new wxGDIPlusPathData(this));
1738 wxGraphicsMatrix
wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1739 wxDouble tx
, wxDouble ty
)
1742 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix
);
1744 wxGDIPlusMatrixData
* data
= new wxGDIPlusMatrixData( this );
1745 data
->Set( a
,b
,c
,d
,tx
,ty
) ;
1750 wxGraphicsPen
wxGDIPlusRenderer::CreatePen(const wxPen
& pen
)
1752 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen
);
1753 if ( !pen
.Ok() || pen
.GetStyle() == wxTRANSPARENT
)
1754 return wxNullGraphicsPen
;
1758 p
.SetRefData(new wxGDIPlusPenData( this, pen
));
1763 wxGraphicsBrush
wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush
)
1765 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
1766 if ( !brush
.Ok() || brush
.GetStyle() == wxTRANSPARENT
)
1767 return wxNullGraphicsBrush
;
1771 p
.SetRefData(new wxGDIPlusBrushData( this, brush
));
1776 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1777 wxGraphicsBrush
wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
,
1778 const wxColour
&c1
, const wxColour
&c2
)
1780 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
1782 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
1783 d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, c1
, c2
);
1788 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1789 // with radius r and color cColor
1790 wxGraphicsBrush
wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
,
1791 const wxColour
&oColor
, const wxColour
&cColor
)
1793 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
1795 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
1796 d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,oColor
,cColor
);
1802 wxGraphicsFont
wxGDIPlusRenderer::CreateFont( const wxFont
&font
, const wxColour
&col
)
1804 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont
);
1808 p
.SetRefData(new wxGDIPlusFontData( this , font
, col
));
1812 return wxNullGraphicsFont
;
1815 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmap( const wxBitmap
&bitmap
)
1817 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
1821 p
.SetRefData(new wxGDIPlusBitmapData( this , bitmap
));
1825 return wxNullGraphicsBitmap
;
1828 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmapFromNativeBitmap( void *bitmap
)
1830 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
1831 if ( bitmap
!= NULL
)
1834 p
.SetRefData(new wxGDIPlusBitmapData( this , (Bitmap
*) bitmap
));
1838 return wxNullGraphicsBitmap
;
1841 wxGraphicsBitmap
wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1843 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
1844 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bitmap
.GetRefData())->GetGDIPlusBitmap();
1848 p
.SetRefData(new wxGDIPlusBitmapData( this , image
->Clone( (REAL
) x
, (REAL
) y
, (REAL
) w
, (REAL
) h
, PixelFormat32bppPARGB
) ));
1852 return wxNullGraphicsBitmap
;
1855 // Shutdown GDI+ at app exit, before possible dll unload
1856 class wxGDIPlusRendererModule
: public wxModule
1859 virtual bool OnInit() { return true; }
1860 virtual void OnExit() { gs_GDIPlusRenderer
.Unload(); }
1863 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule
)
1866 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule
, wxModule
)
1868 // ----------------------------------------------------------------------------
1869 // wxMSW-specific parts of wxGCDC
1870 // ----------------------------------------------------------------------------
1872 WXHDC
wxGCDC::AcquireHDC()
1874 wxGraphicsContext
* const gc
= GetGraphicsContext();
1878 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
1879 return g
? g
->GetHDC() : NULL
;
1882 void wxGCDC::ReleaseHDC(WXHDC hdc
)
1887 wxGraphicsContext
* const gc
= GetGraphicsContext();
1888 wxCHECK_RET( gc
, "can't release HDC because there is no wxGraphicsContext" );
1890 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
1891 wxCHECK_RET( g
, "can't release HDC because there is no Graphics" );
1893 g
->ReleaseHDC((HDC
)hdc
);
1896 #endif // wxUSE_GRAPHICS_CONTEXT