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"
42 #include "wx/private/graphics.h"
43 #include "wx/msw/wrapgdip.h"
44 #include "wx/msw/dc.h"
45 #if wxUSE_ENH_METAFILE
46 #include "wx/msw/enhmeta.h"
48 #include "wx/dcgraph.h"
50 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
52 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
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 wxGDIPlusContext
;
101 class wxGDIPlusPathData
: public wxGraphicsPathData
104 wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
= NULL
);
105 ~wxGDIPlusPathData();
107 virtual wxGraphicsObjectRefData
*Clone() const;
110 // These are the path primitives from which everything else can be constructed
113 // begins a new subpath at (x,y)
114 virtual void MoveToPoint( wxDouble x
, wxDouble y
);
116 // adds a straight line from the current point to (x,y)
117 virtual void AddLineToPoint( wxDouble x
, wxDouble y
);
119 // adds a cubic Bezier curve from the current point, using two control points and an end point
120 virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
);
123 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
124 virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise
) ;
126 // gets the last point of the current path, (0,0) if not yet set
127 virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const;
130 virtual void AddPath( const wxGraphicsPathData
* path
);
132 // closes the current sub-path
133 virtual void CloseSubpath();
136 // These are convenience functions which - if not available natively will be assembled
137 // using the primitives from above
140 // appends a rectangle as a new closed subpath
141 virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
) ;
144 // appends an ellipsis as a new closed subpath fitting the passed rectangle
145 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
147 // 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)
148 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
151 // returns the native path
152 virtual void * GetNativePath() const { return m_path
; }
154 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
155 virtual void UnGetNativePath(void * WXUNUSED(path
)) const {}
157 // transforms each point of this path by the matrix
158 virtual void Transform( const wxGraphicsMatrixData
* matrix
) ;
160 // gets the bounding box enclosing all points (possibly including control points)
161 virtual void GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const;
163 virtual bool Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
) const;
166 GraphicsPath
* m_path
;
169 class wxGDIPlusMatrixData
: public wxGraphicsMatrixData
172 wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
= NULL
) ;
173 virtual ~wxGDIPlusMatrixData() ;
175 virtual wxGraphicsObjectRefData
* Clone() const ;
177 // concatenates the matrix
178 virtual void Concat( const wxGraphicsMatrixData
*t
);
180 // sets the matrix to the respective values
181 virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
182 wxDouble tx
=0.0, wxDouble ty
=0.0);
184 // gets the component valuess of the matrix
185 virtual void Get(wxDouble
* a
=NULL
, wxDouble
* b
=NULL
, wxDouble
* c
=NULL
,
186 wxDouble
* d
=NULL
, wxDouble
* tx
=NULL
, wxDouble
* ty
=NULL
) const;
188 // makes this the inverse matrix
189 virtual void Invert();
191 // returns true if the elements of the transformation matrix are equal ?
192 virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ;
194 // return true if this is the identity matrix
195 virtual bool IsIdentity() const;
201 // add the translation to this matrix
202 virtual void Translate( wxDouble dx
, wxDouble dy
);
204 // add the scale to this matrix
205 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
207 // add the rotation to this matrix (radians)
208 virtual void Rotate( wxDouble angle
);
211 // apply the transforms
214 // applies that matrix to the point
215 virtual void TransformPoint( wxDouble
*x
, wxDouble
*y
) const;
217 // applies the matrix except for translations
218 virtual void TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const;
220 // returns the native representation
221 virtual void * GetNativeMatrix() const;
226 class wxGDIPlusPenData
: public wxGraphicsObjectRefData
229 wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
);
234 virtual wxDouble
GetWidth() { return m_width
; }
235 virtual Pen
* GetGDIPlusPen() { return m_pen
; }
245 class wxGDIPlusBrushData
: public wxGraphicsObjectRefData
248 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
);
249 wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
);
250 ~wxGDIPlusBrushData ();
252 void CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
253 wxDouble x2
, wxDouble y2
,
254 const wxGraphicsGradientStops
& stops
);
255 void CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
256 wxDouble xc
, wxDouble yc
,
258 const wxGraphicsGradientStops
& stops
);
260 virtual Brush
* GetGDIPlusBrush() { return m_brush
; }
266 // common part of Create{Linear,Radial}GradientBrush()
267 template <typename T
>
268 void SetGradientStops(T
*brush
, const wxGraphicsGradientStops
& stops
);
272 GraphicsPath
* m_brushPath
;
275 class WXDLLIMPEXP_CORE wxGDIPlusBitmapData
: public wxGraphicsObjectRefData
278 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
);
279 wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, const wxBitmap
&bmp
);
280 ~wxGDIPlusBitmapData ();
282 virtual Bitmap
* GetGDIPlusBitmap() { return m_bitmap
; }
285 wxImage
ConvertToImage() const;
286 #endif // wxUSE_IMAGE
293 class wxGDIPlusFontData
: public wxGraphicsObjectRefData
296 wxGDIPlusFontData( wxGraphicsRenderer
* renderer
,
297 const wxGDIPlusContext
* gc
,
299 const wxColour
& col
);
300 ~wxGDIPlusFontData();
302 virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; }
303 virtual Font
* GetGDIPlusFont() { return m_font
; }
306 // Common part of all ctors, flags here is a combination of values of
307 // FontStyle GDI+ enum.
308 void Init(const wxString
& name
,
312 Unit fontUnit
= UnitPixel
);
318 class wxGDIPlusContext
: public wxGraphicsContext
321 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, const wxDC
& dc
);
322 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
);
323 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
);
324 wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
);
325 wxGDIPlusContext(wxGraphicsRenderer
* renderer
);
327 virtual ~wxGDIPlusContext();
329 virtual void Clip( const wxRegion
®ion
);
330 // clips drawings to the rect
331 virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
333 // resets the clipping to original extent
334 virtual void ResetClip();
336 virtual void * GetNativeContext();
338 virtual void StrokePath( const wxGraphicsPath
& p
);
339 virtual void FillPath( const wxGraphicsPath
& p
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
341 virtual void DrawRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
343 // stroke lines connecting each of the points
344 virtual void StrokeLines( size_t n
, const wxPoint2DDouble
*points
);
347 virtual void DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode fillStyle
= wxODDEVEN_RULE
);
349 virtual bool SetAntialiasMode(wxAntialiasMode antialias
);
351 virtual bool SetInterpolationQuality(wxInterpolationQuality interpolation
);
353 virtual bool SetCompositionMode(wxCompositionMode op
);
355 virtual void BeginLayer(wxDouble opacity
);
357 virtual void EndLayer();
359 virtual void Translate( wxDouble dx
, wxDouble dy
);
360 virtual void Scale( wxDouble xScale
, wxDouble yScale
);
361 virtual void Rotate( wxDouble angle
);
363 // concatenates this transform with the current transform of this context
364 virtual void ConcatTransform( const wxGraphicsMatrix
& matrix
);
366 // sets the transform of this context
367 virtual void SetTransform( const wxGraphicsMatrix
& matrix
);
369 // gets the matrix of this context
370 virtual wxGraphicsMatrix
GetTransform() const;
372 virtual void DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
373 virtual void DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
374 virtual void DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
375 virtual void PushState();
376 virtual void PopState();
378 // sets the font of this context
379 virtual wxGraphicsFont
CreateFont( const wxFont
&font
, const wxColour
&col
= *wxBLACK
) const;
381 virtual void GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
382 wxDouble
*descent
, wxDouble
*externalLeading
) const;
383 virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const;
384 virtual bool ShouldOffset() const;
385 virtual void GetSize( wxDouble
* width
, wxDouble
*height
);
387 Graphics
* GetGraphics() const { return m_context
; }
391 wxDouble m_fontScaleRatio
;
393 // Used from ctors (including those in the derived classes) and takes
394 // ownership of the graphics pointer that must be non-NULL.
395 void Init(Graphics
* graphics
, int width
, int height
);
398 virtual void DoDrawText(const wxString
& str
, wxDouble x
, wxDouble y
)
399 { DoDrawFilledText(str
, x
, y
, wxNullGraphicsBrush
); }
400 virtual void DoDrawFilledText(const wxString
& str
, wxDouble x
, wxDouble y
,
401 const wxGraphicsBrush
& backgroundBrush
);
404 wxStack
<GraphicsState
> m_stateStack
;
405 GraphicsState m_state1
;
406 GraphicsState m_state2
;
408 wxDECLARE_NO_COPY_CLASS(wxGDIPlusContext
);
413 class wxGDIPlusImageContext
: public wxGDIPlusContext
416 wxGDIPlusImageContext(wxGraphicsRenderer
* renderer
, wxImage
& image
) :
417 wxGDIPlusContext(renderer
),
419 m_bitmap(renderer
, image
)
423 new Graphics(m_bitmap
.GetGDIPlusBitmap()),
429 virtual ~wxGDIPlusImageContext()
431 m_image
= m_bitmap
.ConvertToImage();
436 wxGDIPlusBitmapData m_bitmap
;
438 wxDECLARE_NO_COPY_CLASS(wxGDIPlusImageContext
);
441 #endif // wxUSE_IMAGE
443 class wxGDIPlusMeasuringContext
: public wxGDIPlusContext
446 wxGDIPlusMeasuringContext( wxGraphicsRenderer
* renderer
) : wxGDIPlusContext( renderer
, m_hdc
= GetDC(NULL
), 1000, 1000 )
450 virtual ~wxGDIPlusMeasuringContext()
452 ReleaseDC( NULL
, m_hdc
);
459 class wxGDIPlusPrintingContext
: public wxGDIPlusContext
462 wxGDIPlusPrintingContext( wxGraphicsRenderer
* renderer
, const wxDC
& dc
);
463 virtual ~wxGDIPlusPrintingContext() { }
467 //-----------------------------------------------------------------------------
468 // wxGDIPlusRenderer declaration
469 //-----------------------------------------------------------------------------
471 class wxGDIPlusRenderer
: public wxGraphicsRenderer
480 virtual ~wxGDIPlusRenderer()
490 virtual wxGraphicsContext
* CreateContext( const wxWindowDC
& dc
);
492 virtual wxGraphicsContext
* CreateContext( const wxMemoryDC
& dc
);
494 #if wxUSE_PRINTING_ARCHITECTURE
495 virtual wxGraphicsContext
* CreateContext( const wxPrinterDC
& dc
);
498 #if wxUSE_ENH_METAFILE
499 virtual wxGraphicsContext
* CreateContext( const wxEnhMetaFileDC
& dc
);
502 virtual wxGraphicsContext
* CreateContextFromNativeContext( void * context
);
504 virtual wxGraphicsContext
* CreateContextFromNativeWindow( void * window
);
506 virtual wxGraphicsContext
* CreateContext( wxWindow
* window
);
509 virtual wxGraphicsContext
* CreateContextFromImage(wxImage
& image
);
510 #endif // wxUSE_IMAGE
512 virtual wxGraphicsContext
* CreateMeasuringContext();
516 virtual wxGraphicsPath
CreatePath();
520 virtual wxGraphicsMatrix
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0,
521 wxDouble tx
=0.0, wxDouble ty
=0.0);
524 virtual wxGraphicsPen
CreatePen(const wxPen
& pen
) ;
526 virtual wxGraphicsBrush
CreateBrush(const wxBrush
& brush
) ;
528 virtual wxGraphicsBrush
529 CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
530 wxDouble x2
, wxDouble y2
,
531 const wxGraphicsGradientStops
& stops
);
533 virtual wxGraphicsBrush
534 CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
535 wxDouble xc
, wxDouble yc
,
537 const wxGraphicsGradientStops
& stops
);
539 // create a native bitmap representation
540 virtual wxGraphicsBitmap
CreateBitmap( const wxBitmap
&bitmap
);
542 virtual wxGraphicsBitmap
CreateBitmapFromImage(const wxImage
& image
);
543 #endif // wxUSE_IMAGE
545 // stub: should not be called directly
546 virtual wxGraphicsFont
CreateFont( const wxFont
& WXUNUSED(font
),
547 const wxColour
& WXUNUSED(col
) )
548 { wxFAIL
; return wxNullGraphicsFont
; }
550 // this is used to really create the font
551 wxGraphicsFont
CreateGDIPlusFont( const wxGDIPlusContext
* gc
,
553 const wxColour
&col
);
555 // create a graphics bitmap from a native bitmap
556 virtual wxGraphicsBitmap
CreateBitmapFromNativeBitmap( void* bitmap
);
558 // create a subimage from a native image representation
559 virtual wxGraphicsBitmap
CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
);
562 bool EnsureIsLoaded();
565 friend class wxGDIPlusRendererModule
;
569 ULONG_PTR m_gditoken
;
571 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
)
574 //-----------------------------------------------------------------------------
575 // wxGDIPlusPen implementation
576 //-----------------------------------------------------------------------------
578 wxGDIPlusPenData::~wxGDIPlusPenData()
585 void wxGDIPlusPenData::Init()
592 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen
&pen
)
593 : wxGraphicsObjectRefData(renderer
)
596 m_width
= pen
.GetWidth();
600 m_pen
= new Pen(wxColourToColor(pen
.GetColour()), m_width
);
603 switch ( pen
.GetCap() )
609 case wxCAP_PROJECTING
:
614 cap
= LineCapFlat
; // TODO verify
621 m_pen
->SetLineCap(cap
,cap
, DashCapFlat
);
624 switch ( pen
.GetJoin() )
627 join
= LineJoinBevel
;
631 join
= LineJoinMiter
;
635 join
= LineJoinRound
;
639 join
= LineJoinMiter
;
643 m_pen
->SetLineJoin(join
);
645 m_pen
->SetDashStyle(DashStyleSolid
);
647 DashStyle dashStyle
= DashStyleSolid
;
648 switch ( pen
.GetStyle() )
650 case wxPENSTYLE_SOLID
:
653 case wxPENSTYLE_DOT
:
654 dashStyle
= DashStyleDot
;
657 case wxPENSTYLE_LONG_DASH
:
658 dashStyle
= DashStyleDash
; // TODO verify
661 case wxPENSTYLE_SHORT_DASH
:
662 dashStyle
= DashStyleDash
;
665 case wxPENSTYLE_DOT_DASH
:
666 dashStyle
= DashStyleDashDot
;
668 case wxPENSTYLE_USER_DASH
:
670 dashStyle
= DashStyleCustom
;
672 int count
= pen
.GetDashes( &dashes
);
673 if ((dashes
!= NULL
) && (count
> 0))
675 REAL
*userLengths
= new REAL
[count
];
676 for ( int i
= 0; i
< count
; ++i
)
678 userLengths
[i
] = dashes
[i
];
680 m_pen
->SetDashPattern( userLengths
, count
);
681 delete[] userLengths
;
685 case wxPENSTYLE_STIPPLE
:
687 wxBitmap
* bmp
= pen
.GetStipple();
688 if ( bmp
&& bmp
->IsOk() )
690 m_penImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),
692 (HPALETTE
)bmp
->GetPalette()->GetHPALETTE()
697 m_penBrush
= new TextureBrush(m_penImage
);
698 m_pen
->SetBrush( m_penBrush
);
704 if ( pen
.GetStyle() >= wxPENSTYLE_FIRST_HATCH
&&
705 pen
.GetStyle() <= wxPENSTYLE_LAST_HATCH
)
708 switch( pen
.GetStyle() )
710 case wxPENSTYLE_BDIAGONAL_HATCH
:
711 style
= HatchStyleBackwardDiagonal
;
713 case wxPENSTYLE_CROSSDIAG_HATCH
:
714 style
= HatchStyleDiagonalCross
;
716 case wxPENSTYLE_FDIAGONAL_HATCH
:
717 style
= HatchStyleForwardDiagonal
;
719 case wxPENSTYLE_CROSS_HATCH
:
720 style
= HatchStyleCross
;
722 case wxPENSTYLE_HORIZONTAL_HATCH
:
723 style
= HatchStyleHorizontal
;
725 case wxPENSTYLE_VERTICAL_HATCH
:
726 style
= HatchStyleVertical
;
729 style
= HatchStyleHorizontal
;
731 m_penBrush
= new HatchBrush
734 wxColourToColor(pen
.GetColour()),
737 m_pen
->SetBrush( m_penBrush
);
741 if ( dashStyle
!= DashStyleSolid
)
742 m_pen
->SetDashStyle(dashStyle
);
745 //-----------------------------------------------------------------------------
746 // wxGDIPlusBrush implementation
747 //-----------------------------------------------------------------------------
749 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
)
750 : wxGraphicsObjectRefData(renderer
)
755 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush
&brush
)
756 : wxGraphicsObjectRefData(renderer
)
759 if ( brush
.GetStyle() == wxSOLID
)
761 m_brush
= new SolidBrush(wxColourToColor( brush
.GetColour()));
763 else if ( brush
.IsHatch() )
766 switch( brush
.GetStyle() )
768 case wxBRUSHSTYLE_BDIAGONAL_HATCH
:
769 style
= HatchStyleBackwardDiagonal
;
771 case wxBRUSHSTYLE_CROSSDIAG_HATCH
:
772 style
= HatchStyleDiagonalCross
;
774 case wxBRUSHSTYLE_FDIAGONAL_HATCH
:
775 style
= HatchStyleForwardDiagonal
;
777 case wxBRUSHSTYLE_CROSS_HATCH
:
778 style
= HatchStyleCross
;
780 case wxBRUSHSTYLE_HORIZONTAL_HATCH
:
781 style
= HatchStyleHorizontal
;
783 case wxBRUSHSTYLE_VERTICAL_HATCH
:
784 style
= HatchStyleVertical
;
787 style
= HatchStyleHorizontal
;
789 m_brush
= new HatchBrush
792 wxColourToColor(brush
.GetColour()),
798 wxBitmap
* bmp
= brush
.GetStipple();
799 if ( bmp
&& bmp
->IsOk() )
801 wxDELETE( m_brushImage
);
802 m_brushImage
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),
804 (HPALETTE
)bmp
->GetPalette()->GetHPALETTE()
809 m_brush
= new TextureBrush(m_brushImage
);
814 wxGDIPlusBrushData::~wxGDIPlusBrushData()
821 void wxGDIPlusBrushData::Init()
828 template <typename T
>
830 wxGDIPlusBrushData::SetGradientStops(T
*brush
,
831 const wxGraphicsGradientStops
& stops
)
833 const unsigned numStops
= stops
.GetCount();
836 // initial and final colours are set during the brush creation, nothing
841 wxVector
<Color
> colors(numStops
);
842 wxVector
<REAL
> positions(numStops
);
844 for ( unsigned i
= 0; i
< numStops
; i
++ )
846 wxGraphicsGradientStop stop
= stops
.Item(i
);
848 colors
[i
] = wxColourToColor(stop
.GetColour());
849 positions
[i
] = stop
.GetPosition();
852 brush
->SetInterpolationColors(&colors
[0], &positions
[0], numStops
);
856 wxGDIPlusBrushData::CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
857 wxDouble x2
, wxDouble y2
,
858 const wxGraphicsGradientStops
& stops
)
860 LinearGradientBrush
* const
861 brush
= new LinearGradientBrush(PointF(x1
, y1
) , PointF(x2
, y2
),
862 wxColourToColor(stops
.GetStartColour()),
863 wxColourToColor(stops
.GetEndColour()));
866 SetGradientStops(brush
, stops
);
870 wxGDIPlusBrushData::CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
871 wxDouble xc
, wxDouble yc
,
873 const wxGraphicsGradientStops
& stops
)
875 m_brushPath
= new GraphicsPath();
876 m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
),
877 (REAL
)(2*radius
), (REAL
)(2*radius
));
879 PathGradientBrush
* const brush
= new PathGradientBrush(m_brushPath
);
881 brush
->SetCenterPoint(PointF(xo
, yo
));
882 brush
->SetCenterColor(wxColourToColor(stops
.GetStartColour()));
884 const Color
col(wxColourToColor(stops
.GetEndColour()));
886 brush
->SetSurroundColors(&col
, &count
);
888 SetGradientStops(brush
, stops
);
891 //-----------------------------------------------------------------------------
892 // wxGDIPlusFont implementation
893 //-----------------------------------------------------------------------------
896 wxGDIPlusFontData::Init(const wxString
& name
,
902 // This scaling is needed when we use unit other than the
903 // default UnitPoint. It works for both display and printing.
904 size
*= 100.0f
/ 72.0f
;
906 m_font
= new Font(name
, size
, style
, fontUnit
);
908 m_textBrush
= new SolidBrush(wxColourToColor(col
));
911 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer
* renderer
,
912 const wxGDIPlusContext
* gc
,
914 const wxColour
& col
)
915 : wxGraphicsObjectRefData( renderer
)
917 int style
= FontStyleRegular
;
918 if ( font
.GetStyle() == wxFONTSTYLE_ITALIC
)
919 style
|= FontStyleItalic
;
920 if ( font
.GetUnderlined() )
921 style
|= FontStyleUnderline
;
922 if ( font
.GetWeight() == wxFONTWEIGHT_BOLD
)
923 style
|= FontStyleBold
;
925 Graphics
* context
= gc
->GetGraphics();
927 Unit fontUnit
= context
->GetPageUnit();
928 // if fontUnit is UnitDisplay, then specify UnitPixel, otherwise
929 // you'll get a "InvalidParameter" from GDI+
930 if ( fontUnit
== UnitDisplay
)
931 fontUnit
= UnitPixel
;
933 // NB: font unit should match context's unit. We can use UnitPixel,
934 // as that is what the print context should use.
935 Init(font
.GetFaceName(), font
.GetPointSize(), style
, col
, fontUnit
);
938 wxGDIPlusFontData::~wxGDIPlusFontData()
944 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
945 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
946 // bytes as parameter, since there is no real copying of the data going in, only references are stored
947 // m_helper has to be kept alive as well
949 //-----------------------------------------------------------------------------
950 // wxGDIPlusBitmapData implementation
951 //-----------------------------------------------------------------------------
953 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
, Bitmap
* bitmap
) :
954 wxGraphicsObjectRefData( renderer
), m_bitmap( bitmap
)
959 wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer
* renderer
,
960 const wxBitmap
&bmp
) : wxGraphicsObjectRefData( renderer
)
965 Bitmap
* image
= NULL
;
968 Bitmap
interim((HBITMAP
)bmp
.GetHBITMAP(),
970 (HPALETTE
)bmp
.GetPalette()->GetHPALETTE()
976 size_t width
= interim
.GetWidth();
977 size_t height
= interim
.GetHeight();
978 Rect
bounds(0,0,width
,height
);
980 image
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ;
982 Bitmap
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
);
983 wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
);
985 BitmapData dataMask
;
986 interimMask
.LockBits(&bounds
,ImageLockModeRead
,
987 interimMask
.GetPixelFormat(),&dataMask
);
990 BitmapData imageData
;
991 image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
);
993 BYTE maskPattern
= 0 ;
997 for ( size_t y
= 0 ; y
< height
; ++y
)
1000 for( size_t x
= 0 ; x
< width
; ++x
)
1005 maskByte
= *((BYTE
*)dataMask
.Scan0
+ dataMask
.Stride
*y
+ maskIndex
);
1009 maskPattern
= maskPattern
>> 1;
1011 ARGB
*dest
= (ARGB
*)((BYTE
*)imageData
.Scan0
+ imageData
.Stride
*y
+ x
*4);
1012 if ( (maskByte
& maskPattern
) == 0 )
1017 interim
.GetPixel(x
,y
,&c
) ;
1018 *dest
= (c
.GetValue() | Color::AlphaMask
);
1023 image
->UnlockBits(&imageData
);
1025 interimMask
.UnlockBits(&dataMask
);
1026 interim
.UnlockBits(&dataMask
);
1030 image
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),
1032 (HPALETTE
)bmp
.GetPalette()->GetHPALETTE()
1037 if ( bmp
.HasAlpha() && GetPixelFormatSize(image
->GetPixelFormat()) == 32 )
1039 size_t width
= image
->GetWidth();
1040 size_t height
= image
->GetHeight();
1041 Rect
bounds(0,0,width
,height
);
1042 static BitmapData data
;
1046 m_helper
->LockBits(&bounds
, ImageLockModeRead
,
1047 m_helper
->GetPixelFormat(),&data
);
1049 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1050 PixelFormat32bppPARGB
, (BYTE
*) data
.Scan0
);
1052 m_helper
->UnlockBits(&data
);
1061 wxImage
wxGDIPlusBitmapData::ConvertToImage() const
1063 // We could use Bitmap::LockBits() and convert to wxImage directly but
1064 // passing by wxBitmap is easier. It would be nice to measure performance
1065 // of the two methods but for this the second one would need to be written
1068 if ( m_bitmap
->GetHBITMAP(Color(0xffffffff), &hbmp
) != Gdiplus::Ok
)
1072 bmp
.SetWidth(m_bitmap
->GetWidth());
1073 bmp
.SetHeight(m_bitmap
->GetHeight());
1074 bmp
.SetHBITMAP(hbmp
);
1075 bmp
.SetDepth(IsAlphaPixelFormat(m_bitmap
->GetPixelFormat()) ? 32 : 24);
1076 return bmp
.ConvertToImage();
1079 #endif // wxUSE_IMAGE
1081 wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
1087 // ----------------------------------------------------------------------------
1088 // wxGraphicsBitmap implementation
1089 // ----------------------------------------------------------------------------
1093 wxImage
wxGraphicsBitmap::ConvertToImage() const
1095 const wxGDIPlusBitmapData
* const
1096 data
= static_cast<wxGDIPlusBitmapData
*>(GetGraphicsData());
1098 return data
? data
->ConvertToImage() : wxNullImage
;
1101 #endif // wxUSE_IMAGE
1103 //-----------------------------------------------------------------------------
1104 // wxGDIPlusPath implementation
1105 //-----------------------------------------------------------------------------
1107 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path
) : wxGraphicsPathData(renderer
)
1112 m_path
= new GraphicsPath();
1115 wxGDIPlusPathData::~wxGDIPlusPathData()
1120 wxGraphicsObjectRefData
* wxGDIPlusPathData::Clone() const
1122 return new wxGDIPlusPathData( GetRenderer() , m_path
->Clone());
1129 void wxGDIPlusPathData::MoveToPoint( wxDouble x
, wxDouble y
)
1131 m_path
->StartFigure();
1132 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
1135 void wxGDIPlusPathData::AddLineToPoint( wxDouble x
, wxDouble y
)
1137 m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
);
1140 void wxGDIPlusPathData::CloseSubpath()
1142 m_path
->CloseFigure();
1145 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y
)
1151 m_path
->GetLastPoint(&start
);
1152 m_path
->AddBezier(start
,c1
,c2
,end
);
1155 // gets the last point of the current path, (0,0) if not yet set
1156 void wxGDIPlusPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const
1159 m_path
->GetLastPoint(&start
);
1164 void wxGDIPlusPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise
)
1166 double sweepAngle
= endAngle
- startAngle
;
1167 if( fabs(sweepAngle
) >= 2*M_PI
)
1169 sweepAngle
= 2 * M_PI
;
1175 if( sweepAngle
< 0 )
1176 sweepAngle
+= 2 * M_PI
;
1180 if( sweepAngle
> 0 )
1181 sweepAngle
-= 2 * M_PI
;
1185 m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));
1188 void wxGDIPlusPathData::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1190 m_path
->AddRectangle(RectF(x
,y
,w
,h
));
1193 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData
* path
)
1195 m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
);
1199 // transforms each point of this path by the matrix
1200 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData
* matrix
)
1202 m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() );
1205 // gets the bounding box enclosing all points (possibly including control points)
1206 void wxGDIPlusPathData::GetBox(wxDouble
*x
, wxDouble
*y
, wxDouble
*w
, wxDouble
*h
) const
1209 m_path
->GetBounds( &bounds
, NULL
, NULL
) ;
1216 bool wxGDIPlusPathData::Contains( wxDouble x
, wxDouble y
, wxPolygonFillMode fillStyle
) const
1218 m_path
->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1219 return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE
;
1222 //-----------------------------------------------------------------------------
1223 // wxGDIPlusMatrixData implementation
1224 //-----------------------------------------------------------------------------
1226 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix
)
1227 : wxGraphicsMatrixData(renderer
)
1232 m_matrix
= new Matrix();
1235 wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
1240 wxGraphicsObjectRefData
*wxGDIPlusMatrixData::Clone() const
1242 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix
->Clone());
1245 // concatenates the matrix
1246 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData
*t
)
1248 m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix());
1251 // sets the matrix to the respective values
1252 void wxGDIPlusMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
1253 wxDouble tx
, wxDouble ty
)
1255 m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
);
1258 // gets the component valuess of the matrix
1259 void wxGDIPlusMatrixData::Get(wxDouble
* a
, wxDouble
* b
, wxDouble
* c
,
1260 wxDouble
* d
, wxDouble
* tx
, wxDouble
* ty
) const
1263 m_matrix
->GetElements(elements
);
1264 if (a
) *a
= elements
[0];
1265 if (b
) *b
= elements
[1];
1266 if (c
) *c
= elements
[2];
1267 if (d
) *d
= elements
[3];
1268 if (tx
) *tx
= elements
[4];
1269 if (ty
) *ty
= elements
[5];
1272 // makes this the inverse matrix
1273 void wxGDIPlusMatrixData::Invert()
1278 // returns true if the elements of the transformation matrix are equal ?
1279 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const
1281 return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE
;
1284 // return true if this is the identity matrix
1285 bool wxGDIPlusMatrixData::IsIdentity() const
1287 return m_matrix
->IsIdentity() == TRUE
;
1294 // add the translation to this matrix
1295 void wxGDIPlusMatrixData::Translate( wxDouble dx
, wxDouble dy
)
1297 m_matrix
->Translate(dx
,dy
);
1300 // add the scale to this matrix
1301 void wxGDIPlusMatrixData::Scale( wxDouble xScale
, wxDouble yScale
)
1303 m_matrix
->Scale(xScale
,yScale
);
1306 // add the rotation to this matrix (radians)
1307 void wxGDIPlusMatrixData::Rotate( wxDouble angle
)
1309 m_matrix
->Rotate( RadToDeg(angle
) );
1313 // apply the transforms
1316 // applies that matrix to the point
1317 void wxGDIPlusMatrixData::TransformPoint( wxDouble
*x
, wxDouble
*y
) const
1320 m_matrix
->TransformPoints(&pt
);
1325 // applies the matrix except for translations
1326 void wxGDIPlusMatrixData::TransformDistance( wxDouble
*dx
, wxDouble
*dy
) const
1329 m_matrix
->TransformVectors(&pt
);
1334 // returns the native representation
1335 void * wxGDIPlusMatrixData::GetNativeMatrix() const
1340 //-----------------------------------------------------------------------------
1341 // wxGDIPlusContext implementation
1342 //-----------------------------------------------------------------------------
1344 class wxGDIPlusOffsetHelper
1347 wxGDIPlusOffsetHelper( Graphics
* gr
, bool offset
)
1352 m_gr
->TranslateTransform( 0.5, 0.5 );
1354 ~wxGDIPlusOffsetHelper( )
1357 m_gr
->TranslateTransform( -0.5, -0.5 );
1364 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc
, wxDouble width
, wxDouble height
)
1365 : wxGraphicsContext(renderer
)
1367 Init(new Graphics(hdc
), width
, height
);
1370 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, const wxDC
& dc
)
1371 : wxGraphicsContext(renderer
)
1373 wxMSWDCImpl
*msw
= wxDynamicCast( dc
.GetImpl() , wxMSWDCImpl
);
1374 HDC hdc
= (HDC
) msw
->GetHDC();
1375 wxSize sz
= dc
.GetSize();
1377 Init(new Graphics(hdc
), sz
.x
, sz
.y
);
1380 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd
)
1381 : wxGraphicsContext(renderer
)
1383 RECT rect
= wxGetWindowRect(hwnd
);
1384 Init(new Graphics(hwnd
), rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
1385 m_enableOffset
= true;
1388 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
)
1389 : wxGraphicsContext(renderer
)
1394 wxGDIPlusContext::wxGDIPlusContext(wxGraphicsRenderer
* renderer
)
1395 : wxGraphicsContext(renderer
)
1397 // Derived class must call Init() later but just set m_context to NULL for
1398 // safety to avoid crashing in our dtor if Init() ends up not being called.
1402 void wxGDIPlusContext::Init(Graphics
* graphics
, int width
, int height
)
1404 m_context
= graphics
;
1409 m_fontScaleRatio
= 1.0;
1411 m_context
->SetTextRenderingHint(TextRenderingHintSystemDefault
);
1412 m_context
->SetPixelOffsetMode(PixelOffsetModeHalf
);
1413 m_context
->SetSmoothingMode(SmoothingModeHighQuality
);
1414 m_state1
= m_context
->Save();
1415 m_state2
= m_context
->Save();
1418 wxGDIPlusContext::~wxGDIPlusContext()
1422 m_context
->Restore( m_state2
);
1423 m_context
->Restore( m_state1
);
1429 void wxGDIPlusContext::Clip( const wxRegion
®ion
)
1431 Region
rgn((HRGN
)region
.GetHRGN());
1432 m_context
->SetClip(&rgn
,CombineModeIntersect
);
1435 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1437 m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
);
1440 void wxGDIPlusContext::ResetClip()
1442 m_context
->ResetClip();
1445 void wxGDIPlusContext::DrawRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1447 if (m_composition
== wxCOMPOSITION_DEST
)
1450 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1451 Brush
*brush
= m_brush
.IsNull() ? NULL
: ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush();
1452 Pen
*pen
= m_pen
.IsNull() ? NULL
: ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen();
1456 // the offset is used to fill only the inside of the rectangle and not paint underneath
1457 // its border which may influence a transparent Pen
1460 offset
= pen
->GetWidth();
1461 m_context
->FillRectangle( brush
, (REAL
)x
+ offset
/2, (REAL
)y
+ offset
/2, (REAL
)w
- offset
, (REAL
)h
- offset
);
1466 m_context
->DrawRectangle( pen
, (REAL
)x
, (REAL
)y
, (REAL
)w
, (REAL
)h
);
1470 void wxGDIPlusContext::StrokeLines( size_t n
, const wxPoint2DDouble
*points
)
1472 if (m_composition
== wxCOMPOSITION_DEST
)
1475 if ( !m_pen
.IsNull() )
1477 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1478 Point
*cpoints
= new Point
[n
];
1479 for (size_t i
= 0; i
< n
; i
++)
1481 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1482 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1484 } // for (size_t i = 0; i < n; i++)
1485 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1490 void wxGDIPlusContext::DrawLines( size_t n
, const wxPoint2DDouble
*points
, wxPolygonFillMode
WXUNUSED(fillStyle
) )
1492 if (m_composition
== wxCOMPOSITION_DEST
)
1495 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1496 Point
*cpoints
= new Point
[n
];
1497 for (size_t i
= 0; i
< n
; i
++)
1499 cpoints
[i
].X
= (int)(points
[i
].m_x
);
1500 cpoints
[i
].Y
= (int)(points
[i
].m_y
);
1502 } // for (int i = 0; i < n; i++)
1503 if ( !m_brush
.IsNull() )
1504 m_context
->FillPolygon( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() , cpoints
, n
) ;
1505 if ( !m_pen
.IsNull() )
1506 m_context
->DrawLines( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , cpoints
, n
) ;
1510 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
& path
)
1512 if (m_composition
== wxCOMPOSITION_DEST
)
1515 if ( !m_pen
.IsNull() )
1517 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1518 m_context
->DrawPath( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath
*) path
.GetNativePath() );
1522 void wxGDIPlusContext::FillPath( const wxGraphicsPath
& path
, wxPolygonFillMode fillStyle
)
1524 if (m_composition
== wxCOMPOSITION_DEST
)
1527 if ( !m_brush
.IsNull() )
1529 wxGDIPlusOffsetHelper
helper( m_context
, ShouldOffset() );
1530 ((GraphicsPath
*) path
.GetNativePath())->SetFillMode( fillStyle
== wxODDEVEN_RULE
? FillModeAlternate
: FillModeWinding
);
1531 m_context
->FillPath( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() ,
1532 (GraphicsPath
*) path
.GetNativePath());
1536 bool wxGDIPlusContext::SetAntialiasMode(wxAntialiasMode antialias
)
1538 if (m_antialias
== antialias
)
1541 m_antialias
= antialias
;
1543 SmoothingMode antialiasMode
;
1546 case wxANTIALIAS_DEFAULT
:
1547 antialiasMode
= SmoothingModeHighQuality
;
1549 case wxANTIALIAS_NONE
:
1550 antialiasMode
= SmoothingModeNone
;
1555 m_context
->SetSmoothingMode(antialiasMode
);
1559 bool wxGDIPlusContext::SetInterpolationQuality(wxInterpolationQuality
WXUNUSED(interpolation
))
1565 bool wxGDIPlusContext::SetCompositionMode(wxCompositionMode op
)
1567 if ( m_composition
== op
)
1572 if (m_composition
== wxCOMPOSITION_DEST
)
1575 CompositingMode cop
;
1578 case wxCOMPOSITION_SOURCE
:
1579 cop
= CompositingModeSourceCopy
;
1581 case wxCOMPOSITION_OVER
:
1582 cop
= CompositingModeSourceOver
;
1588 m_context
->SetCompositingMode(cop
);
1592 void wxGDIPlusContext::BeginLayer(wxDouble
/* opacity */)
1597 void wxGDIPlusContext::EndLayer()
1602 void wxGDIPlusContext::Rotate( wxDouble angle
)
1604 m_context
->RotateTransform( RadToDeg(angle
) );
1607 void wxGDIPlusContext::Translate( wxDouble dx
, wxDouble dy
)
1609 m_context
->TranslateTransform( dx
, dy
);
1612 void wxGDIPlusContext::Scale( wxDouble xScale
, wxDouble yScale
)
1614 m_context
->ScaleTransform(xScale
,yScale
);
1617 void wxGDIPlusContext::PushState()
1619 GraphicsState state
= m_context
->Save();
1620 m_stateStack
.push(state
);
1623 void wxGDIPlusContext::PopState()
1625 wxCHECK_RET( !m_stateStack
.empty(), wxT("No state to pop") );
1627 GraphicsState state
= m_stateStack
.top();
1629 m_context
->Restore(state
);
1632 void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1634 if (m_composition
== wxCOMPOSITION_DEST
)
1637 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bmp
.GetRefData())->GetGDIPlusBitmap();
1640 if( image
->GetWidth() != (UINT
) w
|| image
->GetHeight() != (UINT
) h
)
1642 Rect
drawRect((REAL
) x
, (REAL
)y
, (REAL
)w
, (REAL
)h
);
1643 m_context
->SetPixelOffsetMode( PixelOffsetModeNone
);
1644 m_context
->DrawImage(image
, drawRect
, 0 , 0 , image
->GetWidth(), image
->GetHeight(), UnitPixel
) ;
1645 m_context
->SetPixelOffsetMode( PixelOffsetModeHalf
);
1648 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1652 void wxGDIPlusContext::DrawBitmap( const wxBitmap
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1654 wxGraphicsBitmap bitmap
= GetRenderer()->CreateBitmap(bmp
);
1655 DrawBitmap(bitmap
, x
, y
, w
, h
);
1658 void wxGDIPlusContext::DrawIcon( const wxIcon
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
1660 if (m_composition
== wxCOMPOSITION_DEST
)
1663 // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
1664 // find out by looking at the bitmap data whether there really was alpha in it
1665 HICON hIcon
= (HICON
)icon
.GetHICON();
1667 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1668 if (!GetIconInfo(hIcon
,&iconInfo
))
1671 Bitmap
interim(iconInfo
.hbmColor
,NULL
);
1673 Bitmap
* image
= NULL
;
1675 // if it's not 32 bit, it doesn't have an alpha channel, note that since the conversion doesn't
1676 // work correctly, asking IsAlphaPixelFormat at this point fails as well
1677 if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 )
1679 image
= Bitmap::FromHICON(hIcon
);
1683 size_t width
= interim
.GetWidth();
1684 size_t height
= interim
.GetHeight();
1685 Rect
bounds(0,0,width
,height
);
1688 interim
.LockBits(&bounds
, ImageLockModeRead
,
1689 interim
.GetPixelFormat(),&data
);
1691 bool hasAlpha
= false;
1692 for ( size_t y
= 0 ; y
< height
&& !hasAlpha
; ++y
)
1694 for( size_t x
= 0 ; x
< width
&& !hasAlpha
; ++x
)
1696 ARGB
*dest
= (ARGB
*)((BYTE
*)data
.Scan0
+ data
.Stride
*y
+ x
*4);
1697 if ( ( *dest
& Color::AlphaMask
) != 0 )
1704 image
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,
1705 PixelFormat32bppARGB
, (BYTE
*) data
.Scan0
);
1709 image
= Bitmap::FromHICON(hIcon
);
1712 interim
.UnlockBits(&data
);
1715 m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ;
1718 DeleteObject(iconInfo
.hbmColor
);
1719 DeleteObject(iconInfo
.hbmMask
);
1722 wxGraphicsFont
wxGDIPlusContext::CreateFont( const wxFont
&font
,
1723 const wxColour
&col
) const
1725 wxGDIPlusRenderer
* renderer
=
1726 static_cast<wxGDIPlusRenderer
*>(GetRenderer());
1727 return renderer
->CreateGDIPlusFont(this, font
, col
);
1730 void wxGDIPlusContext::DoDrawFilledText(const wxString
& str
,
1731 wxDouble x
, wxDouble y
,
1732 const wxGraphicsBrush
& brush
)
1734 if (m_composition
== wxCOMPOSITION_DEST
)
1737 wxCHECK_RET( !m_font
.IsNull(),
1738 wxT("wxGDIPlusContext::DrawText - no valid font set") );
1743 wxGDIPlusFontData
* const
1744 fontData
= (wxGDIPlusFontData
*)m_font
.GetRefData();
1745 wxGDIPlusBrushData
* const
1746 brushData
= (wxGDIPlusBrushData
*)brush
.GetRefData();
1748 m_context
->DrawString
1750 str
.wc_str(*wxConvUI
), // string to draw, always Unicode
1751 -1, // length: string is NUL-terminated
1752 fontData
->GetGDIPlusFont(),
1754 StringFormat::GenericTypographic(),
1755 brushData
? brushData
->GetGDIPlusBrush()
1756 : fontData
->GetGDIPlusBrush()
1760 void wxGDIPlusContext::GetTextExtent( const wxString
&str
, wxDouble
*width
, wxDouble
*height
,
1761 wxDouble
*descent
, wxDouble
*externalLeading
) const
1763 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1765 wxWCharBuffer s
= str
.wc_str( *wxConvUI
);
1766 FontFamily ffamily
;
1767 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1769 f
->GetFamily(&ffamily
) ;
1771 REAL factorY
= m_fontScaleRatio
;
1773 REAL rDescent
= ffamily
.GetCellDescent(FontStyleRegular
) *
1774 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1775 REAL rAscent
= ffamily
.GetCellAscent(FontStyleRegular
) *
1776 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1777 REAL rHeight
= ffamily
.GetLineSpacing(FontStyleRegular
) *
1778 f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
);
1781 *height
= rHeight
* factorY
;
1783 *descent
= rDescent
* factorY
;
1784 if ( externalLeading
)
1785 *externalLeading
= (rHeight
- rAscent
- rDescent
) * factorY
;
1786 // measuring empty strings is not guaranteed, so do it by hand
1794 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1795 StringFormat
strFormat( StringFormat::GenericTypographic() );
1796 strFormat
.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces
| strFormat
.GetFormatFlags() );
1799 m_context
->MeasureString((const wchar_t *) s
, wcslen(s
) , f
, layoutRect
, &strFormat
, &bounds
) ;
1801 *width
= bounds
.Width
;
1803 *height
= bounds
.Height
;
1807 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const
1810 widths
.Add(0, text
.length());
1812 wxCHECK_RET( !m_font
.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1817 Font
* f
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont();
1818 wxWCharBuffer ws
= text
.wc_str( *wxConvUI
);
1819 size_t len
= wcslen( ws
) ;
1820 wxASSERT_MSG(text
.length() == len
, wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1822 RectF
layoutRect(0,0, 100000.0f
, 100000.0f
);
1823 StringFormat
strFormat( StringFormat::GenericTypographic() );
1825 size_t startPosition
= 0;
1826 size_t remainder
= len
;
1827 const size_t maxSpan
= 32;
1828 CharacterRange
* ranges
= new CharacterRange
[maxSpan
] ;
1829 Region
* regions
= new Region
[maxSpan
];
1831 while( remainder
> 0 )
1833 size_t span
= wxMin( maxSpan
, remainder
);
1835 for( size_t i
= 0 ; i
< span
; ++i
)
1837 ranges
[i
].First
= 0 ;
1838 ranges
[i
].Length
= startPosition
+i
+1 ;
1840 strFormat
.SetMeasurableCharacterRanges(span
,ranges
);
1841 strFormat
.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces
| strFormat
.GetFormatFlags() );
1842 m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,span
,regions
) ;
1845 for ( size_t i
= 0 ; i
< span
; ++i
)
1847 regions
[i
].GetBounds(&bbox
,m_context
);
1848 widths
[startPosition
+i
] = bbox
.Width
;
1851 startPosition
+= span
;
1858 bool wxGDIPlusContext::ShouldOffset() const
1860 if ( !m_enableOffset
)
1864 if ( !m_pen
.IsNull() )
1866 penwidth
= (int)((wxGDIPlusPenData
*)m_pen
.GetRefData())->GetWidth();
1867 if ( penwidth
== 0 )
1870 return ( penwidth
% 2 ) == 1;
1873 void* wxGDIPlusContext::GetNativeContext()
1878 // concatenates this transform with the current transform of this context
1879 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
& matrix
)
1881 m_context
->MultiplyTransform((Matrix
*) matrix
.GetNativeMatrix());
1884 // sets the transform of this context
1885 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
& matrix
)
1887 m_context
->SetTransform((Matrix
*) matrix
.GetNativeMatrix());
1890 // gets the matrix of this context
1891 wxGraphicsMatrix
wxGDIPlusContext::GetTransform() const
1893 wxGraphicsMatrix matrix
= CreateMatrix();
1894 m_context
->GetTransform((Matrix
*) matrix
.GetNativeMatrix());
1898 void wxGDIPlusContext::GetSize( wxDouble
* width
, wxDouble
*height
)
1904 //-----------------------------------------------------------------------------
1905 // wxGDIPlusPrintingContext implementation
1906 //-----------------------------------------------------------------------------
1908 wxGDIPlusPrintingContext::wxGDIPlusPrintingContext( wxGraphicsRenderer
* renderer
,
1910 : wxGDIPlusContext(renderer
, dc
)
1912 Graphics
* context
= GetGraphics();
1914 //m_context->SetPageUnit(UnitDocument);
1916 // Setup page scale, based on DPI ratio.
1917 // Antecedent should be 100dpi when the default page unit
1918 // (UnitDisplay) is used. Page unit UnitDocument would require 300dpi
1919 // instead. Note that calling SetPageScale() does not have effect on
1920 // non-printing DCs (that is, any other than wxPrinterDC or
1921 // wxEnhMetaFileDC).
1922 REAL dpiRatio
= 100.0 / context
->GetDpiY();
1923 context
->SetPageScale(dpiRatio
);
1925 // We use this modifier when measuring fonts. It is needed because the
1926 // page scale is modified above.
1927 m_fontScaleRatio
= context
->GetDpiY() / 72.0;
1930 //-----------------------------------------------------------------------------
1931 // wxGDIPlusRenderer implementation
1932 //-----------------------------------------------------------------------------
1934 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
)
1936 static wxGDIPlusRenderer gs_GDIPlusRenderer
;
1938 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer()
1940 return &gs_GDIPlusRenderer
;
1943 bool wxGDIPlusRenderer::EnsureIsLoaded()
1945 // load gdiplus.dll if not yet loaded, but don't bother doing it again
1946 // if we already tried and failed (we don't want to spend lot of time
1947 // returning NULL from wxGraphicsContext::Create(), which may be called
1948 // relatively frequently):
1949 if ( m_loaded
== -1 )
1954 return m_loaded
== 1;
1957 // call EnsureIsLoaded() and return returnOnFail value if it fails
1958 #define ENSURE_LOADED_OR_RETURN(returnOnFail) \
1959 if ( !EnsureIsLoaded() ) \
1960 return (returnOnFail)
1963 void wxGDIPlusRenderer::Load()
1965 GdiplusStartupInput input
;
1966 GdiplusStartupOutput output
;
1967 if ( GdiplusStartup(&m_gditoken
,&input
,&output
) == Gdiplus::Ok
)
1969 wxLogTrace("gdiplus", "successfully initialized GDI+");
1974 wxLogTrace("gdiplus", "failed to initialize GDI+, missing gdiplus.dll?");
1979 void wxGDIPlusRenderer::Unload()
1983 GdiplusShutdown(m_gditoken
);
1986 m_loaded
= -1; // next Load() will try again
1989 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
)
1991 ENSURE_LOADED_OR_RETURN(NULL
);
1992 wxGDIPlusContext
* context
= new wxGDIPlusContext(this, dc
);
1993 context
->EnableOffset(true);
1997 #if wxUSE_PRINTING_ARCHITECTURE
1998 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxPrinterDC
& dc
)
2000 ENSURE_LOADED_OR_RETURN(NULL
);
2001 wxGDIPlusContext
* context
= new wxGDIPlusPrintingContext(this, dc
);
2006 #if wxUSE_ENH_METAFILE
2007 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxEnhMetaFileDC
& dc
)
2009 ENSURE_LOADED_OR_RETURN(NULL
);
2010 wxGDIPlusContext
* context
= new wxGDIPlusPrintingContext(this, dc
);
2015 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( const wxMemoryDC
& dc
)
2017 ENSURE_LOADED_OR_RETURN(NULL
);
2018 wxGDIPlusContext
* context
= new wxGDIPlusContext(this, dc
);
2019 context
->EnableOffset(true);
2024 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromImage(wxImage
& image
)
2026 ENSURE_LOADED_OR_RETURN(NULL
);
2027 wxGDIPlusContext
* context
= new wxGDIPlusImageContext(this, image
);
2028 context
->EnableOffset(true);
2032 #endif // wxUSE_IMAGE
2034 wxGraphicsContext
* wxGDIPlusRenderer::CreateMeasuringContext()
2036 ENSURE_LOADED_OR_RETURN(NULL
);
2037 return new wxGDIPlusMeasuringContext(this);
2040 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context
)
2042 ENSURE_LOADED_OR_RETURN(NULL
);
2043 return new wxGDIPlusContext(this,(Graphics
*) context
);
2047 wxGraphicsContext
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window
)
2049 ENSURE_LOADED_OR_RETURN(NULL
);
2050 return new wxGDIPlusContext(this,(HWND
) window
);
2053 wxGraphicsContext
* wxGDIPlusRenderer::CreateContext( wxWindow
* window
)
2055 ENSURE_LOADED_OR_RETURN(NULL
);
2056 return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() );
2061 wxGraphicsPath
wxGDIPlusRenderer::CreatePath()
2063 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath
);
2065 m
.SetRefData( new wxGDIPlusPathData(this));
2072 wxGraphicsMatrix
wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
,
2073 wxDouble tx
, wxDouble ty
)
2076 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix
);
2078 wxGDIPlusMatrixData
* data
= new wxGDIPlusMatrixData( this );
2079 data
->Set( a
,b
,c
,d
,tx
,ty
) ;
2084 wxGraphicsPen
wxGDIPlusRenderer::CreatePen(const wxPen
& pen
)
2086 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen
);
2087 if ( !pen
.IsOk() || pen
.GetStyle() == wxTRANSPARENT
)
2088 return wxNullGraphicsPen
;
2092 p
.SetRefData(new wxGDIPlusPenData( this, pen
));
2097 wxGraphicsBrush
wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush
)
2099 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
2100 if ( !brush
.IsOk() || brush
.GetStyle() == wxTRANSPARENT
)
2101 return wxNullGraphicsBrush
;
2105 p
.SetRefData(new wxGDIPlusBrushData( this, brush
));
2111 wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1
, wxDouble y1
,
2112 wxDouble x2
, wxDouble y2
,
2113 const wxGraphicsGradientStops
& stops
)
2115 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
2117 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
2118 d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, stops
);
2124 wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo
, wxDouble yo
,
2125 wxDouble xc
, wxDouble yc
,
2127 const wxGraphicsGradientStops
& stops
)
2129 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush
);
2131 wxGDIPlusBrushData
* d
= new wxGDIPlusBrushData( this );
2132 d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,stops
);
2138 wxGDIPlusRenderer::CreateGDIPlusFont( const wxGDIPlusContext
* gc
,
2140 const wxColour
&col
)
2142 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont
);
2146 p
.SetRefData(new wxGDIPlusFontData( this, gc
, font
, col
));
2150 return wxNullGraphicsFont
;
2153 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmap( const wxBitmap
&bitmap
)
2155 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2156 if ( bitmap
.IsOk() )
2159 p
.SetRefData(new wxGDIPlusBitmapData( this , bitmap
));
2163 return wxNullGraphicsBitmap
;
2168 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmapFromImage(const wxImage
& image
)
2170 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2173 // Notice that we rely on conversion from wxImage to wxBitmap here but
2174 // we could probably do it more efficiently by converting from wxImage
2175 // to GDI+ Bitmap directly, i.e. copying wxImage pixels to the buffer
2176 // returned by Bitmap::LockBits(). However this would require writing
2177 // code specific for this task while like this we can reuse existing
2178 // code (see also wxGDIPlusBitmapData::ConvertToImage()).
2179 wxGraphicsBitmap gb
;
2180 gb
.SetRefData(new wxGDIPlusBitmapData(this, image
));
2184 return wxNullGraphicsBitmap
;
2187 #endif // wxUSE_IMAGE
2189 wxGraphicsBitmap
wxGDIPlusRenderer::CreateBitmapFromNativeBitmap( void *bitmap
)
2191 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2192 if ( bitmap
!= NULL
)
2195 p
.SetRefData(new wxGDIPlusBitmapData( this , (Bitmap
*) bitmap
));
2199 return wxNullGraphicsBitmap
;
2202 wxGraphicsBitmap
wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap
&bitmap
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h
)
2204 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap
);
2205 Bitmap
* image
= static_cast<wxGDIPlusBitmapData
*>(bitmap
.GetRefData())->GetGDIPlusBitmap();
2209 p
.SetRefData(new wxGDIPlusBitmapData( this , image
->Clone( (REAL
) x
, (REAL
) y
, (REAL
) w
, (REAL
) h
, PixelFormat32bppPARGB
) ));
2213 return wxNullGraphicsBitmap
;
2216 // Shutdown GDI+ at app exit, before possible dll unload
2217 class wxGDIPlusRendererModule
: public wxModule
2220 virtual bool OnInit() { return true; }
2221 virtual void OnExit() { gs_GDIPlusRenderer
.Unload(); }
2224 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule
)
2227 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule
, wxModule
)
2229 // ----------------------------------------------------------------------------
2230 // wxMSW-specific parts of wxGCDC
2231 // ----------------------------------------------------------------------------
2233 WXHDC
wxGCDC::AcquireHDC()
2235 wxGraphicsContext
* const gc
= GetGraphicsContext();
2240 // we can't get the HDC if it is not a GDI+ context
2241 wxGraphicsRenderer
* r1
= gc
->GetRenderer();
2242 wxGraphicsRenderer
* r2
= wxGraphicsRenderer::GetCairoRenderer();
2247 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
2248 return g
? g
->GetHDC() : NULL
;
2251 void wxGCDC::ReleaseHDC(WXHDC hdc
)
2256 wxGraphicsContext
* const gc
= GetGraphicsContext();
2257 wxCHECK_RET( gc
, "can't release HDC because there is no wxGraphicsContext" );
2260 // we can't get the HDC if it is not a GDI+ context
2261 wxGraphicsRenderer
* r1
= gc
->GetRenderer();
2262 wxGraphicsRenderer
* r2
= wxGraphicsRenderer::GetCairoRenderer();
2267 Graphics
* const g
= static_cast<Graphics
*>(gc
->GetNativeContext());
2268 wxCHECK_RET( g
, "can't release HDC because there is no Graphics" );
2270 g
->ReleaseHDC((HDC
)hdc
);
2273 #endif // wxUSE_GRAPHICS_CONTEXT