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" 
  21 #include "wx/msw/wrapcdlg.h" 
  23 #include "wx/window.h" 
  26 #include "wx/dialog.h" 
  28 #include "wx/bitmap.h" 
  29 #include "wx/dcmemory.h" 
  32 #include "wx/dcprint.h" 
  33 #include "wx/module.h" 
  36 #include "wx/graphics.h" 
  38 #if wxUSE_GRAPHICS_CONTEXT 
  44 //----------------------------------------------------------------------------- 
  46 //----------------------------------------------------------------------------- 
  48 const double RAD2DEG 
= 180.0 / M_PI
; 
  50 //----------------------------------------------------------------------------- 
  52 //----------------------------------------------------------------------------- 
  54 static inline double dmin(double a
, double b
) { return a 
< b 
? a 
: b
; } 
  55 static inline double dmax(double a
, double b
) { return a 
> b 
? a 
: b
; } 
  57 static inline double DegToRad(double deg
) { return (deg 
* M_PI
) / 180.0; } 
  58 static inline double RadToDeg(double deg
) { return (deg 
* 180.0) / M_PI
; } 
  60 //----------------------------------------------------------------------------- 
  61 // device context implementation 
  63 // more and more of the dc functionality should be implemented by calling 
  64 // the appropricate wxGDIPlusContext, but we will have to do that step by step 
  65 // also coordinate conversions should be moved to native matrix ops 
  66 //----------------------------------------------------------------------------- 
  68 // we always stock two context states, one at entry, to be able to preserve the 
  69 // state we were called with, the other one after changing to HI Graphics orientation 
  70 // (this one is used for getting back clippings etc) 
  72 //----------------------------------------------------------------------------- 
  73 // wxGraphicsPath implementation 
  74 //----------------------------------------------------------------------------- 
  76 #include "wx/msw/private.h" // needs to be before #include <commdlg.h> 
  78 #if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__) 
  82 // TODO remove this dependency (gdiplus needs the macros) 
  85 #define max(a,b)            (((a) > (b)) ? (a) : (b)) 
  89 #define min(a,b)            (((a) < (b)) ? (a) : (b)) 
  93 using namespace Gdiplus
; 
 111     void EnsureIsLoaded() 
 120         GdiplusStartupInput input
; 
 121         GdiplusStartupOutput output
; 
 122         GdiplusStartup(&m_gditoken
,&input
,&output
); 
 128             GdiplusShutdown(m_gditoken
); 
 136 static GDILoader gGDILoader
; 
 138 class WXDLLEXPORT wxGDIPlusPath 
: public wxGraphicsPath
 
 140     DECLARE_NO_COPY_CLASS(wxGDIPlusPath
) 
 147     // These are the path primitives from which everything else can be constructed 
 150     // begins a new subpath at (x,y) 
 151     virtual void MoveToPoint( wxDouble x
, wxDouble y 
); 
 153     // adds a straight line from the current point to (x,y)  
 154     virtual void AddLineToPoint( wxDouble x
, wxDouble y 
); 
 156     // adds a cubic Bezier curve from the current point, using two control points and an end point 
 157     virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y 
); 
 160     // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle  
 161     virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise 
) ; 
 163     // gets the last point of the current path, (0,0) if not yet set 
 164     virtual void GetCurrentPoint( wxDouble
& x
, wxDouble
&y
) ; 
 166     // closes the current sub-path 
 167     virtual void CloseSubpath(); 
 170     // These are convenience functions which - if not available natively will be assembled  
 171     // using the primitives from above 
 174     // appends a rectangle as a new closed subpath  
 175     virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) ; 
 178     // appends an ellipsis as a new closed subpath fitting the passed rectangle 
 179     virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ; 
 181     // 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) 
 182     virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )  ; 
 185     GraphicsPath
* GetPath() const; 
 187     GraphicsPath
* m_path
; 
 190 class WXDLLEXPORT wxGDIPlusContext 
: public wxGraphicsContext
 
 192     DECLARE_NO_COPY_CLASS(wxGDIPlusContext
) 
 195     wxGDIPlusContext( WXHDC hdc 
); 
 197     virtual ~wxGDIPlusContext(); 
 199     virtual void Clip( const wxRegion 
®ion 
); 
 200     // clips drawings to the rect 
 201     virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
); 
 203         // resets the clipping to original extent 
 204         virtual void ResetClip(); 
 206         virtual void * GetNativeContext(); 
 208     virtual void StrokePath( const wxGraphicsPath 
*p 
); 
 209     virtual void FillPath( const wxGraphicsPath 
*p 
, int fillStyle 
= wxWINDING_RULE 
); 
 211     virtual wxGraphicsPath
* CreatePath(); 
 212     virtual void SetPen( const wxPen 
&pen 
); 
 213     virtual void SetBrush( const wxBrush 
&brush 
); 
 214     virtual void SetLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
) ; 
 215     virtual void SetRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
, 
 216         const wxColour 
&oColor
, const wxColour 
&cColor
); 
 218     virtual void Translate( wxDouble dx 
, wxDouble dy 
);     
 219     virtual void Scale( wxDouble xScale 
, wxDouble yScale 
);     
 220     virtual void Rotate( wxDouble angle 
);     
 222     virtual void DrawBitmap( const wxBitmap 
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
); 
 223     virtual void DrawIcon( const wxIcon 
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
); 
 224     virtual void PushState();     
 225     virtual void PopState(); 
 227     virtual void SetFont( const wxFont 
&font 
); 
 228     virtual void SetTextColor( const wxColour 
&col 
);     
 229     virtual void DrawText( const wxString 
&str
, wxDouble x
, wxDouble y
); 
 230     virtual void GetTextExtent( const wxString 
&str
, wxDouble 
*width
, wxDouble 
*height
, 
 231         wxDouble 
*descent
, wxDouble 
*externalLeading 
) const; 
 232     virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const; 
 236     vector
<GraphicsState
> m_stateStack
; 
 237     GraphicsState m_state1
; 
 238     GraphicsState m_state2
; 
 241     bool m_penTransparent
; 
 246     bool m_brushTransparent
; 
 248     GraphicsPath
* m_brushPath
; 
 256 wxGDIPlusPath::wxGDIPlusPath() 
 258     m_path 
= new GraphicsPath(); 
 261 wxGDIPlusPath::~wxGDIPlusPath() 
 266 GraphicsPath
* wxGDIPlusPath::GetPath() const 
 275 void wxGDIPlusPath::MoveToPoint( wxDouble x 
, wxDouble y 
) 
 277     m_path
->StartFigure(); 
 278     m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
); 
 281 void wxGDIPlusPath::AddLineToPoint( wxDouble x 
, wxDouble y 
) 
 283     m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
); 
 286 void wxGDIPlusPath::CloseSubpath() 
 288     m_path
->CloseFigure(); 
 291 void wxGDIPlusPath::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y 
) 
 297     m_path
->GetLastPoint(&start
); 
 298     m_path
->AddBezier(start
,c1
,c2
,end
); 
 301 // gets the last point of the current path, (0,0) if not yet set 
 302 void wxGDIPlusPath::GetCurrentPoint( wxDouble
& x
, wxDouble
&y
)  
 305     m_path
->GetLastPoint(&start
); 
 310 void wxGDIPlusPath::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise 
)  
 312     double sweepAngle 
= endAngle 
- startAngle 
; 
 313     if( abs(sweepAngle
) >= 2*M_PI
) 
 315         sweepAngle 
= 2 * M_PI
; 
 322                 sweepAngle 
+= 2 * M_PI
; 
 327                 sweepAngle 
-= 2 * M_PI
; 
 331    m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
));  
 334 void wxGDIPlusPath::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) 
 336     m_path
->AddRectangle(RectF(x
,y
,w
,h
)); 
 343 // closes the current subpath 
 344 void wxGDIPlusPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )  
 346 //    CGPathAddArcToPoint( m_path, NULL , x1, y1, x2, y2, r);  
 351 //----------------------------------------------------------------------------- 
 352 // wxGDIPlusContext implementation 
 353 //----------------------------------------------------------------------------- 
 355 wxGDIPlusContext::wxGDIPlusContext( WXHDC hdc  
) 
 357     gGDILoader
.EnsureIsLoaded(); 
 358     m_context 
= new Graphics( (HDC
) hdc
); 
 359     m_context
->SetSmoothingMode(SmoothingModeHighQuality
); 
 360     m_state1 
= m_context
->Save(); 
 361     m_state2 
= m_context
->Save(); 
 365     m_penTransparent 
= false; 
 366     m_pen 
= new Pen((ARGB
)Color::Black
); 
 370     m_brushTransparent 
= false; 
 371     m_brush 
= new SolidBrush((ARGB
)Color::White
); 
 374     m_textBrush 
= new SolidBrush((ARGB
)Color::Black
); 
 375     m_font 
= new Font( L
"Arial" , 9 , FontStyleRegular 
); 
 378 wxGDIPlusContext::~wxGDIPlusContext() 
 382         m_context
->Restore( m_state2 
); 
 383         m_context
->Restore( m_state1 
); 
 397 void wxGDIPlusContext::Clip( const wxRegion 
& WXUNUSED(region
) ) 
 402 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) 
 407 void wxGDIPlusContext::ResetClip() 
 412 void wxGDIPlusContext::StrokePath( const wxGraphicsPath 
*p 
) 
 414     if ( m_penTransparent 
) 
 417     const wxGDIPlusPath
* path 
= dynamic_cast< const wxGDIPlusPath
*>( p 
); 
 418     m_context
->DrawPath( m_pen 
, path
->GetPath() ); 
 421 void wxGDIPlusContext::FillPath( const wxGraphicsPath 
*p 
, int fillStyle 
) 
 423     if ( !m_brushTransparent 
) 
 425         const wxGDIPlusPath
* path 
= dynamic_cast< const wxGDIPlusPath
*>( p 
); 
 426         path
->GetPath()->SetFillMode( fillStyle 
== wxODDEVEN_RULE 
? FillModeAlternate 
: FillModeWinding
); 
 427         m_context
->FillPath( m_brush 
, path
->GetPath() ); 
 431 wxGraphicsPath
* wxGDIPlusContext::CreatePath() 
 433     return new wxGDIPlusPath(); 
 436 void wxGDIPlusContext::Rotate( wxDouble angle 
)  
 438     m_context
->RotateTransform( RadToDeg(angle
) ); 
 441 void wxGDIPlusContext::Translate( wxDouble dx 
, wxDouble dy 
)  
 443     m_context
->TranslateTransform( dx 
, dy 
); 
 446 void wxGDIPlusContext::Scale( wxDouble xScale 
, wxDouble yScale 
) 
 448     m_context
->ScaleTransform(xScale
,yScale
); 
 451 void wxGDIPlusContext::PushState() 
 453     GraphicsState state 
= m_context
->Save(); 
 454     m_stateStack
.push_back(state
); 
 457 void wxGDIPlusContext::PopState()  
 459     GraphicsState state 
= m_stateStack
.back(); 
 460     m_stateStack
.pop_back(); 
 461     m_context
->Restore(state
); 
 464 void wxGDIPlusContext::SetTextColor( const wxColour 
&col 
)  
 467     m_textBrush 
= new SolidBrush( Color( col
.Alpha() , col
.Red() , 
 468         col
.Green() , col
.Blue() )); 
 471 void wxGDIPlusContext::SetPen( const wxPen 
&pen 
) 
 473     m_penTransparent 
= pen
.GetStyle() == wxTRANSPARENT
; 
 474     if ( m_penTransparent 
) 
 477     m_pen
->SetColor( Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() , 
 478         pen
.GetColour().Green() , pen
.GetColour().Blue() ) ); 
 480     // TODO: * m_dc->m_scaleX 
 481     double penWidth 
= pen
.GetWidth(); 
 485     m_pen
->SetWidth(penWidth
); 
 488     switch ( pen
.GetCap() ) 
 494     case wxCAP_PROJECTING 
: 
 499         cap 
= LineCapFlat
; // TODO verify 
 506     m_pen
->SetLineCap(cap
,cap
, DashCapFlat
); 
 509     switch ( pen
.GetJoin() ) 
 512         join 
= LineJoinBevel
; 
 516         join 
= LineJoinMiter
; 
 520         join 
= LineJoinRound
; 
 524         join 
= LineJoinMiter
; 
 528     m_pen
->SetLineJoin(join
); 
 530     m_pen
->SetDashStyle(DashStyleSolid
); 
 532     DashStyle dashStyle 
= DashStyleSolid
; 
 533     switch ( pen
.GetStyle() ) 
 539         dashStyle 
= DashStyleDot
; 
 543         dashStyle 
= DashStyleDash
; // TODO verify 
 547         dashStyle 
= DashStyleDash
; 
 551         dashStyle 
= DashStyleDashDot
; 
 555             dashStyle 
= DashStyleCustom
; 
 557             int count 
= pen
.GetDashes( &dashes 
); 
 558             if ((dashes 
!= NULL
) && (count 
> 0)) 
 560                 REAL 
*userLengths 
= new REAL
[count
]; 
 561                 for ( int i 
= 0; i 
< count
; ++i 
) 
 563                     userLengths
[i
] = dashes
[i
]; 
 565                 m_pen
->SetDashPattern( userLengths
, count
); 
 566                 delete[] userLengths
; 
 572             wxBitmap
* bmp 
= pen
.GetStipple(); 
 573             if ( bmp 
&& bmp
->Ok() ) 
 575                 wxDELETE( m_penImage 
); 
 576                 wxDELETE( m_penBrush 
); 
 577                 m_penImage 
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE()); 
 578                 m_penBrush 
= new TextureBrush(m_penImage
); 
 579                 m_pen
->SetBrush( m_penBrush 
); 
 585         if ( pen
.GetStyle() >= wxFIRST_HATCH 
&& pen
.GetStyle() <= wxLAST_HATCH 
) 
 587             wxDELETE( m_penBrush 
); 
 588             HatchStyle style 
= HatchStyleHorizontal
; 
 589             switch( pen
.GetStyle() ) 
 591             case wxBDIAGONAL_HATCH 
: 
 592                 style 
= HatchStyleBackwardDiagonal
; 
 594             case wxCROSSDIAG_HATCH 
: 
 595                 style 
= HatchStyleDiagonalCross
; 
 597             case wxFDIAGONAL_HATCH 
: 
 598                 style 
= HatchStyleForwardDiagonal
; 
 601                 style 
= HatchStyleCross
; 
 603             case wxHORIZONTAL_HATCH 
: 
 604                 style 
= HatchStyleHorizontal
; 
 606             case wxVERTICAL_HATCH 
: 
 607                 style 
= HatchStyleVertical
; 
 611             m_penBrush 
= new HatchBrush(style
,Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() , 
 612                 pen
.GetColour().Green() , pen
.GetColour().Blue() ), Color::Transparent 
); 
 613             m_pen
->SetBrush( m_penBrush 
); 
 617     if ( dashStyle 
!= DashStyleSolid 
) 
 618         m_pen
->SetDashStyle(dashStyle
); 
 621 void wxGDIPlusContext::SetBrush( const wxBrush 
&brush 
) 
 624     if ( m_context 
== NULL 
) 
 627     m_brushTransparent 
= brush
.GetStyle() == wxTRANSPARENT
; 
 629     if ( m_brushTransparent 
) 
 634     if ( brush
.GetStyle() == wxSOLID
) 
 636         m_brush 
= new SolidBrush( Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() , 
 637             brush
.GetColour().Green() , brush
.GetColour().Blue() ) ); 
 639     else if ( brush
.IsHatch() ) 
 641         HatchStyle style 
= HatchStyleHorizontal
; 
 642         switch( brush
.GetStyle() ) 
 644         case wxBDIAGONAL_HATCH 
: 
 645             style 
= HatchStyleBackwardDiagonal
; 
 647         case wxCROSSDIAG_HATCH 
: 
 648             style 
= HatchStyleDiagonalCross
; 
 650         case wxFDIAGONAL_HATCH 
: 
 651             style 
= HatchStyleForwardDiagonal
; 
 654             style 
= HatchStyleCross
; 
 656         case wxHORIZONTAL_HATCH 
: 
 657             style 
= HatchStyleHorizontal
; 
 659         case wxVERTICAL_HATCH 
: 
 660             style 
= HatchStyleVertical
; 
 664         m_brush 
= new HatchBrush(style
,Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() , 
 665             brush
.GetColour().Green() , brush
.GetColour().Blue() ), Color::Transparent 
); 
 669         wxBitmap
* bmp 
= brush
.GetStipple(); 
 670         if ( bmp 
&& bmp
->Ok() ) 
 672             wxDELETE( m_brushImage 
); 
 673             m_brushImage 
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE()); 
 674             m_brush 
= new TextureBrush(m_brushImage
); 
 679 void wxGDIPlusContext::SetLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
)  
 681     m_brushTransparent 
= false ; 
 685     m_brush 
= new LinearGradientBrush( PointF( x1
,y1
) , PointF( x2
,y2
), 
 686         Color( c1
.Alpha(), c1
.Red(),c1
.Green() , c1
.Blue() ), 
 687         Color( c2
.Alpha(), c2
.Red(),c2
.Green() , c2
.Blue() )); 
 690 void wxGDIPlusContext::SetRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
, 
 691                                     const wxColour 
&oColor
, const wxColour 
&cColor
) 
 693     m_brushTransparent 
= false ; 
 696     wxDELETE(m_brushPath
); 
 698     // Create a path that consists of a single circle. 
 699     m_brushPath 
= new GraphicsPath(); 
 700     m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
), (REAL
)(2*radius
), (REAL
)(2*radius
)); 
 702     PathGradientBrush 
*b 
= new PathGradientBrush(m_brushPath
); 
 704     b
->SetCenterPoint( PointF(xo
,yo
)); 
 705     b
->SetCenterColor(Color( oColor
.Alpha(), oColor
.Red(),oColor
.Green() , oColor
.Blue() )); 
 707     Color colors
[] = {Color( cColor
.Alpha(), cColor
.Red(),cColor
.Green() , cColor
.Blue() )}; 
 709     b
->SetSurroundColors(colors
, &count
); 
 712 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the  
 713 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied  
 714 // bytes as parameter 
 716 void wxGDIPlusContext::DrawBitmap( const wxBitmap 
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
)  
 718     Bitmap
* image 
= NULL
; 
 719     Bitmap
* helper 
= NULL
; 
 722         Bitmap 
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ; 
 724         size_t width 
= interim
.GetWidth(); 
 725         size_t height 
= interim
.GetHeight(); 
 726         Rect 
bounds(0,0,width
,height
); 
 728         image 
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ; 
 730         Bitmap 
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
); 
 731         wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
); 
 733         BitmapData dataMask 
; 
 734         interimMask
.LockBits(&bounds
,ImageLockModeRead
,  
 735             interimMask
.GetPixelFormat(),&dataMask
); 
 738         BitmapData imageData 
; 
 739         image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
); 
 741         BYTE maskPattern 
= 0 ; 
 745         for ( size_t y 
= 0 ; y 
< height 
; ++y
) 
 748             for( size_t x 
= 0 ; x 
< width
; ++x
) 
 753                     maskByte 
= *((BYTE
*)dataMask
.Scan0 
+ dataMask
.Stride
*y 
+ maskIndex
); 
 757                     maskPattern 
= maskPattern 
>> 1; 
 759                 ARGB 
*dest 
= (ARGB
*)((BYTE
*)imageData
.Scan0 
+ imageData
.Stride
*y 
+ x
*4); 
 760                 if ( (maskByte 
& maskPattern
) == 0 ) 
 765                     interim
.GetPixel(x
,y
,&c
) ; 
 766                     *dest 
= (c
.GetValue() | Color::AlphaMask
); 
 771         image
->UnlockBits(&imageData
); 
 773         interimMask
.UnlockBits(&dataMask
); 
 774         interim
.UnlockBits(&dataMask
); 
 778         image 
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE());         
 779         if ( GetPixelFormatSize(image
->GetPixelFormat()) == 32 ) 
 781             size_t width 
= image
->GetWidth(); 
 782             size_t height 
= image
->GetHeight(); 
 783             Rect 
bounds(0,0,width
,height
); 
 788             helper
->LockBits(&bounds
, ImageLockModeRead
, 
 789                 helper
->GetPixelFormat(),&data
); 
 791             image 
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,  
 792                 PixelFormat32bppARGB 
, (BYTE
*) data
.Scan0
); 
 794             helper
->UnlockBits(&data
); 
 798         m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ; 
 803 void wxGDIPlusContext::DrawIcon( const wxIcon 
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
)  
 805     HICON hIcon 
= (HICON
)icon
.GetHICON(); 
 807     // IconInfo creates the bitmaps for color and mask, we must dispose of them after use 
 808     if (!GetIconInfo(hIcon
,&iconInfo
)) 
 812     GetObject(iconInfo
.hbmColor
,sizeof(BITMAP
),&iconBmpData
); 
 813     Bitmap 
interim(iconInfo
.hbmColor
,NULL
); 
 815     Bitmap
* image 
= NULL 
; 
 817     if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 ) 
 819         image 
= Bitmap::FromHICON(hIcon
); 
 823         size_t width 
= interim
.GetWidth(); 
 824         size_t height 
= interim
.GetHeight(); 
 825         Rect 
bounds(0,0,width
,height
); 
 828         interim
.LockBits(&bounds
, ImageLockModeRead
, 
 829             interim
.GetPixelFormat(),&data
); 
 830         image 
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
,  
 831             PixelFormat32bppARGB 
, (BYTE
*) data
.Scan0
); 
 832         interim
.UnlockBits(&data
); 
 835     m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ; 
 838     DeleteObject(iconInfo
.hbmColor
); 
 839     DeleteObject(iconInfo
.hbmMask
); 
 843 void wxGDIPlusContext::DrawText( const wxString 
&str
, wxDouble x
, wxDouble y 
)  
 848     wxWCharBuffer s 
= str
.wc_str( *wxConvUI 
); 
 849     m_context
->DrawString( s 
, -1 , m_font 
, PointF( x 
, y 
) , m_textBrush 
); 
 850     // TODO m_backgroundMode == wxSOLID 
 853 void wxGDIPlusContext::GetTextExtent( const wxString 
&str
, wxDouble 
*width
, wxDouble 
*height
, 
 854                                      wxDouble 
*descent
, wxDouble 
*externalLeading 
) const 
 856     wxWCharBuffer s 
= str
.wc_str( *wxConvUI 
); 
 859     m_font
->GetFamily(&ffamily
) ; 
 861     REAL factorY 
= m_context
->GetDpiY() / 72.0 ; 
 863     REAL rDescent 
= ffamily
.GetCellDescent(FontStyleRegular
) * 
 864         m_font
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
); 
 865     REAL rAscent 
= ffamily
.GetCellAscent(FontStyleRegular
) * 
 866         m_font
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
); 
 867     REAL rHeight 
= ffamily
.GetLineSpacing(FontStyleRegular
) * 
 868         m_font
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
); 
 871         *height 
= rHeight 
* factorY 
+ 0.5 ; 
 873         *descent 
= rDescent 
* factorY 
+ 0.5 ; 
 874     if ( externalLeading 
) 
 875         *externalLeading 
= (rHeight 
- rAscent 
- rDescent
) * factorY 
+ 0.5 ; 
 876     // measuring empty strings is not guaranteed, so do it by hand 
 884         // MeasureString does return a rectangle that is way too large, so it is 
 886         RectF 
layoutRect(0,0, 100000.0f
, 100000.0f
); 
 887         StringFormat strFormat
; 
 888         CharacterRange 
strRange(0,wcslen(s
)); 
 889         strFormat
.SetMeasurableCharacterRanges(1,&strRange
); 
 891         m_context
->MeasureCharacterRanges(s
, -1 , m_font
,layoutRect
, &strFormat
,1,®ion
) ; 
 893         region
.GetBounds(&bbox
,m_context
); 
 895             *width 
= bbox
.GetRight()-bbox
.GetLeft()+0.5; 
 899 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const  
 902     widths
.Add(0, text
.length()); 
 907     wxWCharBuffer ws 
= text
.wc_str( *wxConvUI 
); 
 908     size_t len 
= wcslen( ws 
) ; 
 909     wxASSERT_MSG(text
.length() == len 
, wxT("GetPartialTextExtents not yet implemented for multichar situations")); 
 911     RectF 
layoutRect(0,0, 100000.0f
, 100000.0f
); 
 912     StringFormat strFormat
; 
 914     CharacterRange
* ranges 
= new CharacterRange
[len
] ; 
 915     Region
* regions 
= new Region
[len
]; 
 916     for( size_t i 
= 0 ; i 
< len 
; ++i
) 
 918         ranges
[i
].First 
= i 
; 
 919         ranges
[i
].Length 
= 1 ; 
 921     strFormat
.SetMeasurableCharacterRanges(len
,ranges
); 
 922     m_context
->MeasureCharacterRanges(ws
, -1 , m_font
,layoutRect
, &strFormat
,1,regions
) ; 
 925     for ( size_t i 
= 0 ; i 
< len 
; ++i
) 
 927         regions
[i
].GetBounds(&bbox
,m_context
); 
 928         widths
[i
] = bbox
.GetRight()-bbox
.GetLeft(); 
 932 void wxGDIPlusContext::SetFont( const wxFont 
&font 
)  
 934     wxASSERT( font
.Ok()); 
 936     wxWCharBuffer s 
= font
.GetFaceName().wc_str( *wxConvUI 
); 
 937     int size 
= font
.GetPointSize(); 
 938     int style 
= FontStyleRegular
; 
 939     if ( font
.GetStyle() == wxFONTSTYLE_ITALIC 
) 
 940         style 
|= FontStyleItalic
; 
 941     if ( font
.GetUnderlined() ) 
 942         style 
|= FontStyleUnderline
; 
 943     if ( font
.GetWeight() == wxFONTWEIGHT_BOLD 
) 
 944         style 
|= FontStyleBold
; 
 945     m_font 
= new Font( s 
, size 
, style 
); 
 948 void* wxGDIPlusContext::GetNativeContext()  
 953 wxGraphicsContext
* wxGraphicsContext::Create( const wxWindowDC
& dc
) 
 955     return new wxGDIPlusContext( (HDC
) dc
.GetHDC() ); 
 958 wxGraphicsContext
* wxGraphicsContext::Create( wxWindow 
* window 
) 
 963 wxGraphicsContext
* wxGraphicsContext::CreateFromNative( void * context 
) 
 970 #endif  // wxUSE_GRAPHICS_CONTEXT