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
; 
  95 class WXDLLIMPEXP_CORE wxGDIPlusPathData 
: public wxGraphicsPathData
 
  98     wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path 
= NULL
); 
 101     virtual wxGraphicsObjectRefData 
*Clone() const; 
 104     // These are the path primitives from which everything else can be constructed 
 107     // begins a new subpath at (x,y) 
 108     virtual void MoveToPoint( wxDouble x
, wxDouble y 
); 
 110     // adds a straight line from the current point to (x,y) 
 111     virtual void AddLineToPoint( wxDouble x
, wxDouble y 
); 
 113     // adds a cubic Bezier curve from the current point, using two control points and an end point 
 114     virtual void AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y 
); 
 117     // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle 
 118     virtual void AddArc( wxDouble x
, wxDouble y
, wxDouble r
, wxDouble startAngle
, wxDouble endAngle
, bool clockwise 
) ; 
 120     // gets the last point of the current path, (0,0) if not yet set 
 121     virtual void GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const; 
 124     virtual void AddPath( const wxGraphicsPathData
* path 
); 
 126     // closes the current sub-path 
 127     virtual void CloseSubpath(); 
 130     // These are convenience functions which - if not available natively will be assembled 
 131     // using the primitives from above 
 134     // appends a rectangle as a new closed subpath 
 135     virtual void AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) ; 
 138     // appends an ellipsis as a new closed subpath fitting the passed rectangle 
 139     virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ; 
 141     // 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) 
 142     virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )  ; 
 145     // returns the native path 
 146     virtual void * GetNativePath() const { return m_path
; } 
 148     // give the native path returned by GetNativePath() back (there might be some deallocations necessary) 
 149     virtual void UnGetNativePath(void * WXUNUSED(path
)) const {} 
 151     // transforms each point of this path by the matrix 
 152     virtual void Transform( const wxGraphicsMatrixData
* matrix 
) ; 
 154     // gets the bounding box enclosing all points (possibly including control points) 
 155     virtual void GetBox(wxDouble 
*x
, wxDouble 
*y
, wxDouble 
*w
, wxDouble 
*h
) const; 
 157     virtual bool Contains( wxDouble x
, wxDouble y
, int fillStyle 
= wxODDEVEN_RULE
) const; 
 160     GraphicsPath
* m_path
; 
 163 class WXDLLIMPEXP_CORE wxGDIPlusMatrixData 
: public wxGraphicsMatrixData
 
 166     wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix 
= NULL
) ; 
 167     virtual ~wxGDIPlusMatrixData() ; 
 169     virtual wxGraphicsObjectRefData
* Clone() const ; 
 171     // concatenates the matrix 
 172     virtual void Concat( const wxGraphicsMatrixData 
*t 
); 
 174     // sets the matrix to the respective values 
 175     virtual void Set(wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0, 
 176         wxDouble tx
=0.0, wxDouble ty
=0.0); 
 178     // makes this the inverse matrix 
 179     virtual void Invert(); 
 181     // returns true if the elements of the transformation matrix are equal ? 
 182     virtual bool IsEqual( const wxGraphicsMatrixData
* t
) const ; 
 184     // return true if this is the identity matrix 
 185     virtual bool IsIdentity() const; 
 191     // add the translation to this matrix 
 192     virtual void Translate( wxDouble dx 
, wxDouble dy 
); 
 194     // add the scale to this matrix 
 195     virtual void Scale( wxDouble xScale 
, wxDouble yScale 
); 
 197     // add the rotation to this matrix (radians) 
 198     virtual void Rotate( wxDouble angle 
); 
 201     // apply the transforms 
 204     // applies that matrix to the point 
 205     virtual void TransformPoint( wxDouble 
*x
, wxDouble 
*y 
) const; 
 207     // applies the matrix except for translations 
 208     virtual void TransformDistance( wxDouble 
*dx
, wxDouble 
*dy 
) const; 
 210     // returns the native representation 
 211     virtual void * GetNativeMatrix() const; 
 216 class WXDLLIMPEXP_CORE wxGDIPlusPenData 
: public wxGraphicsObjectRefData
 
 219     wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen 
&pen 
); 
 224     virtual wxDouble 
GetWidth() { return m_width
; } 
 225     virtual Pen
* GetGDIPlusPen() { return m_pen
; } 
 235 class WXDLLIMPEXP_CORE wxGDIPlusBrushData 
: public wxGraphicsObjectRefData
 
 238     wxGDIPlusBrushData( wxGraphicsRenderer
* renderer 
); 
 239     wxGDIPlusBrushData( wxGraphicsRenderer
* renderer
, const wxBrush 
&brush 
); 
 240     ~wxGDIPlusBrushData (); 
 242     void CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, 
 243         const wxColour
&c1
, const wxColour
&c2 
); 
 244     void CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
, 
 245         const wxColour 
&oColor
, const wxColour 
&cColor 
); 
 246     virtual Brush
* GetGDIPlusBrush() { return m_brush
; } 
 254     GraphicsPath
* m_brushPath
; 
 257 class WXDLLIMPEXP_CORE wxGDIPlusFontData 
: public wxGraphicsObjectRefData
 
 260     wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont 
&font
, const wxColour
& col 
); 
 261     ~wxGDIPlusFontData(); 
 263     virtual Brush
* GetGDIPlusBrush() { return m_textBrush
; } 
 264     virtual Font
* GetGDIPlusFont() { return m_font
; } 
 270 class WXDLLIMPEXP_CORE wxGDIPlusContext 
: public wxGraphicsContext
 
 273     wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc 
); 
 274     wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd 
); 
 275     wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr
); 
 278     virtual ~wxGDIPlusContext(); 
 280     virtual void Clip( const wxRegion 
®ion 
); 
 281     // clips drawings to the rect 
 282     virtual void Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
); 
 284     // resets the clipping to original extent 
 285     virtual void ResetClip(); 
 287     virtual void * GetNativeContext(); 
 289     virtual void StrokePath( const wxGraphicsPath
& p 
); 
 290     virtual void FillPath( const wxGraphicsPath
& p 
, int fillStyle 
= wxODDEVEN_RULE 
); 
 292     virtual void Translate( wxDouble dx 
, wxDouble dy 
); 
 293     virtual void Scale( wxDouble xScale 
, wxDouble yScale 
); 
 294     virtual void Rotate( wxDouble angle 
); 
 296     // concatenates this transform with the current transform of this context 
 297     virtual void ConcatTransform( const wxGraphicsMatrix
& matrix 
); 
 299     // sets the transform of this context 
 300     virtual void SetTransform( const wxGraphicsMatrix
& matrix 
); 
 302     // gets the matrix of this context 
 303     virtual wxGraphicsMatrix 
GetTransform() const; 
 305     virtual void DrawBitmap( const wxBitmap 
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
); 
 306     virtual void DrawIcon( const wxIcon 
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
); 
 307     virtual void PushState(); 
 308     virtual void PopState(); 
 310     virtual void DrawText( const wxString 
&str
, wxDouble x
, wxDouble y
); 
 311     virtual void GetTextExtent( const wxString 
&str
, wxDouble 
*width
, wxDouble 
*height
, 
 312         wxDouble 
*descent
, wxDouble 
*externalLeading 
) const; 
 313     virtual void GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const; 
 320     vector
<GraphicsState
> m_stateStack
; 
 321     GraphicsState m_state1
; 
 322     GraphicsState m_state2
; 
 324     DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext
) 
 327 //----------------------------------------------------------------------------- 
 328 // wxGDIPlusPen implementation 
 329 //----------------------------------------------------------------------------- 
 331 wxGDIPlusPenData::~wxGDIPlusPenData() 
 338 void wxGDIPlusPenData::Init() 
 345 wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer
* renderer
, const wxPen 
&pen 
) 
 346 : wxGraphicsObjectRefData(renderer
) 
 349     m_width 
= pen
.GetWidth(); 
 353     m_pen 
= new Pen(Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() , 
 354         pen
.GetColour().Green() , pen
.GetColour().Blue() ), m_width 
); 
 357     switch ( pen
.GetCap() ) 
 363     case wxCAP_PROJECTING 
: 
 368         cap 
= LineCapFlat
; // TODO verify 
 375     m_pen
->SetLineCap(cap
,cap
, DashCapFlat
); 
 378     switch ( pen
.GetJoin() ) 
 381         join 
= LineJoinBevel
; 
 385         join 
= LineJoinMiter
; 
 389         join 
= LineJoinRound
; 
 393         join 
= LineJoinMiter
; 
 397     m_pen
->SetLineJoin(join
); 
 399     m_pen
->SetDashStyle(DashStyleSolid
); 
 401     DashStyle dashStyle 
= DashStyleSolid
; 
 402     switch ( pen
.GetStyle() ) 
 408         dashStyle 
= DashStyleDot
; 
 412         dashStyle 
= DashStyleDash
; // TODO verify 
 416         dashStyle 
= DashStyleDash
; 
 420         dashStyle 
= DashStyleDashDot
; 
 424             dashStyle 
= DashStyleCustom
; 
 426             int count 
= pen
.GetDashes( &dashes 
); 
 427             if ((dashes 
!= NULL
) && (count 
> 0)) 
 429                 REAL 
*userLengths 
= new REAL
[count
]; 
 430                 for ( int i 
= 0; i 
< count
; ++i 
) 
 432                     userLengths
[i
] = dashes
[i
]; 
 434                 m_pen
->SetDashPattern( userLengths
, count
); 
 435                 delete[] userLengths
; 
 441             wxBitmap
* bmp 
= pen
.GetStipple(); 
 442             if ( bmp 
&& bmp
->Ok() ) 
 444                 m_penImage 
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE()); 
 445                 m_penBrush 
= new TextureBrush(m_penImage
); 
 446                 m_pen
->SetBrush( m_penBrush 
); 
 452         if ( pen
.GetStyle() >= wxFIRST_HATCH 
&& pen
.GetStyle() <= wxLAST_HATCH 
) 
 454             HatchStyle style 
= HatchStyleHorizontal
; 
 455             switch( pen
.GetStyle() ) 
 457             case wxBDIAGONAL_HATCH 
: 
 458                 style 
= HatchStyleBackwardDiagonal
; 
 460             case wxCROSSDIAG_HATCH 
: 
 461                 style 
= HatchStyleDiagonalCross
; 
 463             case wxFDIAGONAL_HATCH 
: 
 464                 style 
= HatchStyleForwardDiagonal
; 
 467                 style 
= HatchStyleCross
; 
 469             case wxHORIZONTAL_HATCH 
: 
 470                 style 
= HatchStyleHorizontal
; 
 472             case wxVERTICAL_HATCH 
: 
 473                 style 
= HatchStyleVertical
; 
 477             m_penBrush 
= new HatchBrush(style
,Color( pen
.GetColour().Alpha() , pen
.GetColour().Red() , 
 478                 pen
.GetColour().Green() , pen
.GetColour().Blue() ), Color::Transparent 
); 
 479             m_pen
->SetBrush( m_penBrush 
); 
 483     if ( dashStyle 
!= DashStyleSolid 
) 
 484         m_pen
->SetDashStyle(dashStyle
); 
 487 //----------------------------------------------------------------------------- 
 488 // wxGDIPlusBrush implementation 
 489 //----------------------------------------------------------------------------- 
 491 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer 
) 
 492 : wxGraphicsObjectRefData(renderer
) 
 497 wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer
* renderer 
, const wxBrush 
&brush 
) 
 498 : wxGraphicsObjectRefData(renderer
) 
 501     if ( brush
.GetStyle() == wxSOLID
) 
 503         m_brush 
= new SolidBrush( Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() , 
 504             brush
.GetColour().Green() , brush
.GetColour().Blue() ) ); 
 506     else if ( brush
.IsHatch() ) 
 508         HatchStyle style 
= HatchStyleHorizontal
; 
 509         switch( brush
.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_brush 
= new HatchBrush(style
,Color( brush
.GetColour().Alpha() , brush
.GetColour().Red() , 
 532             brush
.GetColour().Green() , brush
.GetColour().Blue() ), Color::Transparent 
); 
 536         wxBitmap
* bmp 
= brush
.GetStipple(); 
 537         if ( bmp 
&& bmp
->Ok() ) 
 539             wxDELETE( m_brushImage 
); 
 540             m_brushImage 
= Bitmap::FromHBITMAP((HBITMAP
)bmp
->GetHBITMAP(),(HPALETTE
)bmp
->GetPalette()->GetHPALETTE()); 
 541             m_brush 
= new TextureBrush(m_brushImage
); 
 546 wxGDIPlusBrushData::~wxGDIPlusBrushData() 
 553 void wxGDIPlusBrushData::Init() 
 560 void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, const wxColour
&c1
, const wxColour
&c2
) 
 562     m_brush 
= new LinearGradientBrush( PointF( x1
,y1
) , PointF( x2
,y2
), 
 563         Color( c1
.Alpha(), c1
.Red(),c1
.Green() , c1
.Blue() ), 
 564         Color( c2
.Alpha(), c2
.Red(),c2
.Green() , c2
.Blue() )); 
 567 void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
, 
 568                                                const wxColour 
&oColor
, const wxColour 
&cColor
) 
 570     // Create a path that consists of a single circle. 
 571     m_brushPath 
= new GraphicsPath(); 
 572     m_brushPath
->AddEllipse( (REAL
)(xc
-radius
), (REAL
)(yc
-radius
), (REAL
)(2*radius
), (REAL
)(2*radius
)); 
 574     PathGradientBrush 
*b 
= new PathGradientBrush(m_brushPath
); 
 576     b
->SetCenterPoint( PointF(xo
,yo
)); 
 577     b
->SetCenterColor(Color( oColor
.Alpha(), oColor
.Red(),oColor
.Green() , oColor
.Blue() )); 
 579     Color colors
[] = {Color( cColor
.Alpha(), cColor
.Red(),cColor
.Green() , cColor
.Blue() )}; 
 581     b
->SetSurroundColors(colors
, &count
); 
 584 //----------------------------------------------------------------------------- 
 585 // wxGDIPlusFont implementation 
 586 //----------------------------------------------------------------------------- 
 588 wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer
* renderer
, const wxFont 
&font
, 
 589                              const wxColour
& col 
) : wxGraphicsObjectRefData( renderer 
) 
 594     wxWCharBuffer s 
= font
.GetFaceName().wc_str( *wxConvUI 
); 
 595     int size 
= font
.GetPointSize(); 
 596     int style 
= FontStyleRegular
; 
 597     if ( font
.GetStyle() == wxFONTSTYLE_ITALIC 
) 
 598         style 
|= FontStyleItalic
; 
 599     if ( font
.GetUnderlined() ) 
 600         style 
|= FontStyleUnderline
; 
 601     if ( font
.GetWeight() == wxFONTWEIGHT_BOLD 
) 
 602         style 
|= FontStyleBold
; 
 603     m_font 
= new Font( s 
, size 
, style 
); 
 604     m_textBrush 
= new SolidBrush( Color( col
.Alpha() , col
.Red() , 
 605         col
.Green() , col
.Blue() )); 
 608 wxGDIPlusFontData::~wxGDIPlusFontData() 
 614 //----------------------------------------------------------------------------- 
 615 // wxGDIPlusPath implementation 
 616 //----------------------------------------------------------------------------- 
 618 wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer
* renderer
, GraphicsPath
* path 
) : wxGraphicsPathData(renderer
) 
 623         m_path 
= new GraphicsPath(); 
 626 wxGDIPlusPathData::~wxGDIPlusPathData() 
 631 wxGraphicsObjectRefData
* wxGDIPlusPathData::Clone() const 
 633     return new wxGDIPlusPathData( GetRenderer() , m_path
->Clone()); 
 640 void wxGDIPlusPathData::MoveToPoint( wxDouble x 
, wxDouble y 
) 
 642     m_path
->StartFigure(); 
 643     m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
); 
 646 void wxGDIPlusPathData::AddLineToPoint( wxDouble x 
, wxDouble y 
) 
 648     m_path
->AddLine((REAL
) x
,(REAL
) y
,(REAL
) x
,(REAL
) y
); 
 651 void wxGDIPlusPathData::CloseSubpath() 
 653     m_path
->CloseFigure(); 
 656 void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1
, wxDouble cy1
, wxDouble cx2
, wxDouble cy2
, wxDouble x
, wxDouble y 
) 
 662     m_path
->GetLastPoint(&start
); 
 663     m_path
->AddBezier(start
,c1
,c2
,end
); 
 666 // gets the last point of the current path, (0,0) if not yet set 
 667 void wxGDIPlusPathData::GetCurrentPoint( wxDouble
* x
, wxDouble
* y
) const 
 670     m_path
->GetLastPoint(&start
); 
 675 void wxGDIPlusPathData::AddArc( wxDouble x
, wxDouble y
, wxDouble r
, double startAngle
, double endAngle
, bool clockwise 
) 
 677     double sweepAngle 
= endAngle 
- startAngle 
; 
 678     if( abs(sweepAngle
) >= 2*M_PI
) 
 680         sweepAngle 
= 2 * M_PI
; 
 687                 sweepAngle 
+= 2 * M_PI
; 
 692                 sweepAngle 
-= 2 * M_PI
; 
 696    m_path
->AddArc((REAL
) (x
-r
),(REAL
) (y
-r
),(REAL
) (2*r
),(REAL
) (2*r
),RadToDeg(startAngle
),RadToDeg(sweepAngle
)); 
 699 void wxGDIPlusPathData::AddRectangle( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) 
 701     m_path
->AddRectangle(RectF(x
,y
,w
,h
)); 
 704 void wxGDIPlusPathData::AddPath( const wxGraphicsPathData
* path 
) 
 706     m_path
->AddPath( (GraphicsPath
*) path
->GetNativePath(), FALSE
); 
 710 // transforms each point of this path by the matrix 
 711 void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData
* matrix 
) 
 713     m_path
->Transform( (Matrix
*) matrix
->GetNativeMatrix() ); 
 716 // gets the bounding box enclosing all points (possibly including control points) 
 717 void wxGDIPlusPathData::GetBox(wxDouble 
*x
, wxDouble 
*y
, wxDouble 
*w
, wxDouble 
*h
) const 
 720     m_path
->GetBounds( &bounds
, NULL
, NULL
) ; 
 727 bool wxGDIPlusPathData::Contains( wxDouble x
, wxDouble y
, int fillStyle 
) const 
 729     m_path
->SetFillMode( fillStyle 
== wxODDEVEN_RULE 
? FillModeAlternate 
: FillModeWinding
); 
 730     return m_path
->IsVisible( (FLOAT
) x
,(FLOAT
) y
) == TRUE 
; 
 733 //----------------------------------------------------------------------------- 
 734 // wxGDIPlusMatrixData implementation 
 735 //----------------------------------------------------------------------------- 
 737 wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer
* renderer
, Matrix
* matrix 
) 
 738     : wxGraphicsMatrixData(renderer
) 
 743         m_matrix 
= new Matrix(); 
 746 wxGDIPlusMatrixData::~wxGDIPlusMatrixData() 
 751 wxGraphicsObjectRefData 
*wxGDIPlusMatrixData::Clone() const 
 753     return new wxGDIPlusMatrixData( GetRenderer(), m_matrix
->Clone()); 
 756 // concatenates the matrix 
 757 void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData 
*t 
) 
 759     m_matrix
->Multiply( (Matrix
*) t
->GetNativeMatrix()); 
 762 // sets the matrix to the respective values 
 763 void wxGDIPlusMatrixData::Set(wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
, 
 764                  wxDouble tx
, wxDouble ty
) 
 766     m_matrix
->SetElements(a
,b
,c
,d
,tx
,ty
); 
 769 // makes this the inverse matrix 
 770 void wxGDIPlusMatrixData::Invert() 
 775 // returns true if the elements of the transformation matrix are equal ? 
 776 bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData
* t
) const 
 778     return m_matrix
->Equals((Matrix
*) t
->GetNativeMatrix())== TRUE 
; 
 781 // return true if this is the identity matrix 
 782 bool wxGDIPlusMatrixData::IsIdentity() const 
 784     return m_matrix
->IsIdentity() == TRUE 
; 
 791 // add the translation to this matrix 
 792 void wxGDIPlusMatrixData::Translate( wxDouble dx 
, wxDouble dy 
) 
 794     m_matrix
->Translate(dx
,dy
); 
 797 // add the scale to this matrix 
 798 void wxGDIPlusMatrixData::Scale( wxDouble xScale 
, wxDouble yScale 
) 
 800     m_matrix
->Scale(xScale
,yScale
); 
 803 // add the rotation to this matrix (radians) 
 804 void wxGDIPlusMatrixData::Rotate( wxDouble angle 
) 
 806     m_matrix
->Rotate( angle 
); 
 810 // apply the transforms 
 813 // applies that matrix to the point 
 814 void wxGDIPlusMatrixData::TransformPoint( wxDouble 
*x
, wxDouble 
*y 
) const 
 817     m_matrix
->TransformPoints(&pt
); 
 822 // applies the matrix except for translations 
 823 void wxGDIPlusMatrixData::TransformDistance( wxDouble 
*dx
, wxDouble 
*dy 
) const 
 826     m_matrix
->TransformVectors(&pt
); 
 831 // returns the native representation 
 832 void * wxGDIPlusMatrixData::GetNativeMatrix() const 
 837 //----------------------------------------------------------------------------- 
 838 // wxGDIPlusContext implementation 
 839 //----------------------------------------------------------------------------- 
 841 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext
,wxGraphicsContext
) 
 843 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HDC hdc  
) 
 844     : wxGraphicsContext(renderer
) 
 847     m_context 
= new Graphics( hdc
); 
 851 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, HWND hwnd  
) 
 852     : wxGraphicsContext(renderer
) 
 855     m_context 
= new Graphics( hwnd
); 
 859 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer
* renderer
, Graphics
* gr  
) 
 860     : wxGraphicsContext(renderer
) 
 867 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL
) 
 872 void wxGDIPlusContext::Init() 
 879 void wxGDIPlusContext::SetDefaults() 
 881     m_context
->SetSmoothingMode(SmoothingModeHighQuality
); 
 882     m_state1 
= m_context
->Save(); 
 883     m_state2 
= m_context
->Save(); 
 886 wxGDIPlusContext::~wxGDIPlusContext() 
 890         m_context
->Restore( m_state2 
); 
 891         m_context
->Restore( m_state1 
); 
 897 void wxGDIPlusContext::Clip( const wxRegion 
®ion 
) 
 899     Region 
rgn((HRGN
)region
.GetHRGN()); 
 900     m_context
->SetClip(&rgn
,CombineModeIntersect
); 
 903 void wxGDIPlusContext::Clip( wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) 
 905     m_context
->SetClip(RectF(x
,y
,w
,h
),CombineModeIntersect
); 
 908 void wxGDIPlusContext::ResetClip() 
 910     m_context
->ResetClip(); 
 913 void wxGDIPlusContext::StrokePath( const wxGraphicsPath
& path 
) 
 915     if ( !m_pen
.IsNull() ) 
 917         m_context
->DrawPath( ((wxGDIPlusPenData
*)m_pen
.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath
*) path
.GetNativePath() ); 
 921 void wxGDIPlusContext::FillPath( const wxGraphicsPath
& path 
, int fillStyle 
) 
 923     if ( !m_brush
.IsNull() ) 
 925         ((GraphicsPath
*) path
.GetNativePath())->SetFillMode( fillStyle 
== wxODDEVEN_RULE 
? FillModeAlternate 
: FillModeWinding
); 
 926         m_context
->FillPath( ((wxGDIPlusBrushData
*)m_brush
.GetRefData())->GetGDIPlusBrush() , 
 927             (GraphicsPath
*) path
.GetNativePath()); 
 931 void wxGDIPlusContext::Rotate( wxDouble angle 
) 
 933     m_context
->RotateTransform( RadToDeg(angle
) ); 
 936 void wxGDIPlusContext::Translate( wxDouble dx 
, wxDouble dy 
) 
 938     m_context
->TranslateTransform( dx 
, dy 
); 
 941 void wxGDIPlusContext::Scale( wxDouble xScale 
, wxDouble yScale 
) 
 943     m_context
->ScaleTransform(xScale
,yScale
); 
 946 void wxGDIPlusContext::PushState() 
 948     GraphicsState state 
= m_context
->Save(); 
 949     m_stateStack
.push_back(state
); 
 952 void wxGDIPlusContext::PopState() 
 954     GraphicsState state 
= m_stateStack
.back(); 
 955     m_stateStack
.pop_back(); 
 956     m_context
->Restore(state
); 
 959 // the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the 
 960 // premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied 
 961 // bytes as parameter 
 963 void wxGDIPlusContext::DrawBitmap( const wxBitmap 
&bmp
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) 
 965     Bitmap
* image 
= NULL
; 
 966     Bitmap
* helper 
= NULL
; 
 969         Bitmap 
interim((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()) ; 
 971         size_t width 
= interim
.GetWidth(); 
 972         size_t height 
= interim
.GetHeight(); 
 973         Rect 
bounds(0,0,width
,height
); 
 975         image 
= new Bitmap(width
,height
,PixelFormat32bppPARGB
) ; 
 977         Bitmap 
interimMask((HBITMAP
)bmp
.GetMask()->GetMaskBitmap(),NULL
); 
 978         wxASSERT(interimMask
.GetPixelFormat() == PixelFormat1bppIndexed
); 
 980         BitmapData dataMask 
; 
 981         interimMask
.LockBits(&bounds
,ImageLockModeRead
, 
 982             interimMask
.GetPixelFormat(),&dataMask
); 
 985         BitmapData imageData 
; 
 986         image
->LockBits(&bounds
,ImageLockModeWrite
, PixelFormat32bppPARGB
, &imageData
); 
 988         BYTE maskPattern 
= 0 ; 
 992         for ( size_t y 
= 0 ; y 
< height 
; ++y
) 
 995             for( size_t x 
= 0 ; x 
< width
; ++x
) 
1000                     maskByte 
= *((BYTE
*)dataMask
.Scan0 
+ dataMask
.Stride
*y 
+ maskIndex
); 
1004                     maskPattern 
= maskPattern 
>> 1; 
1006                 ARGB 
*dest 
= (ARGB
*)((BYTE
*)imageData
.Scan0 
+ imageData
.Stride
*y 
+ x
*4); 
1007                 if ( (maskByte 
& maskPattern
) == 0 ) 
1012                     interim
.GetPixel(x
,y
,&c
) ; 
1013                     *dest 
= (c
.GetValue() | Color::AlphaMask
); 
1018         image
->UnlockBits(&imageData
); 
1020         interimMask
.UnlockBits(&dataMask
); 
1021         interim
.UnlockBits(&dataMask
); 
1025         image 
= Bitmap::FromHBITMAP((HBITMAP
)bmp
.GetHBITMAP(),(HPALETTE
)bmp
.GetPalette()->GetHPALETTE()); 
1026         if ( GetPixelFormatSize(image
->GetPixelFormat()) == 32 ) 
1028             size_t width 
= image
->GetWidth(); 
1029             size_t height 
= image
->GetHeight(); 
1030             Rect 
bounds(0,0,width
,height
); 
1035             helper
->LockBits(&bounds
, ImageLockModeRead
, 
1036                 helper
->GetPixelFormat(),&data
); 
1038             image 
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
, 
1039                 PixelFormat32bppARGB 
, (BYTE
*) data
.Scan0
); 
1041             helper
->UnlockBits(&data
); 
1045         m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ; 
1050 void wxGDIPlusContext::DrawIcon( const wxIcon 
&icon
, wxDouble x
, wxDouble y
, wxDouble w
, wxDouble h 
) 
1052     HICON hIcon 
= (HICON
)icon
.GetHICON(); 
1054     // IconInfo creates the bitmaps for color and mask, we must dispose of them after use 
1055     if (!GetIconInfo(hIcon
,&iconInfo
)) 
1058     BITMAP iconBmpData 
; 
1059     GetObject(iconInfo
.hbmColor
,sizeof(BITMAP
),&iconBmpData
); 
1060     Bitmap 
interim(iconInfo
.hbmColor
,NULL
); 
1062     Bitmap
* image 
= NULL 
; 
1064     if( GetPixelFormatSize(interim
.GetPixelFormat())!= 32 ) 
1066         image 
= Bitmap::FromHICON(hIcon
); 
1070         size_t width 
= interim
.GetWidth(); 
1071         size_t height 
= interim
.GetHeight(); 
1072         Rect 
bounds(0,0,width
,height
); 
1075         interim
.LockBits(&bounds
, ImageLockModeRead
, 
1076             interim
.GetPixelFormat(),&data
); 
1077         image 
= new Bitmap(data
.Width
, data
.Height
, data
.Stride
, 
1078             PixelFormat32bppARGB 
, (BYTE
*) data
.Scan0
); 
1079         interim
.UnlockBits(&data
); 
1082     m_context
->DrawImage(image
,(REAL
) x
,(REAL
) y
,(REAL
) w
,(REAL
) h
) ; 
1085     DeleteObject(iconInfo
.hbmColor
); 
1086     DeleteObject(iconInfo
.hbmMask
); 
1089 void wxGDIPlusContext::DrawText( const wxString 
&str
, wxDouble x
, wxDouble y 
) 
1091     if ( m_font
.IsNull() || str
.IsEmpty()) 
1094     wxWCharBuffer s 
= str
.wc_str( *wxConvUI 
); 
1095     m_context
->DrawString( s 
, -1 , ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont() , 
1096             PointF( x 
, y 
) , ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusBrush() ); 
1097     // TODO m_backgroundMode == wxSOLID 
1100 void wxGDIPlusContext::GetTextExtent( const wxString 
&str
, wxDouble 
*width
, wxDouble 
*height
, 
1101                                      wxDouble 
*descent
, wxDouble 
*externalLeading 
) const 
1103     wxWCharBuffer s 
= str
.wc_str( *wxConvUI 
); 
1104     FontFamily ffamily 
; 
1105     Font
* f 
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont(); 
1107     f
->GetFamily(&ffamily
) ; 
1109     REAL factorY 
= m_context
->GetDpiY() / 72.0 ; 
1111     REAL rDescent 
= ffamily
.GetCellDescent(FontStyleRegular
) * 
1112         f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
); 
1113     REAL rAscent 
= ffamily
.GetCellAscent(FontStyleRegular
) * 
1114         f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
); 
1115     REAL rHeight 
= ffamily
.GetLineSpacing(FontStyleRegular
) * 
1116         f
->GetSize() / ffamily
.GetEmHeight(FontStyleRegular
); 
1119         *height 
= rHeight 
* factorY 
+ 0.5 ; 
1121         *descent 
= rDescent 
* factorY 
+ 0.5 ; 
1122     if ( externalLeading 
) 
1123         *externalLeading 
= (rHeight 
- rAscent 
- rDescent
) * factorY 
+ 0.5 ; 
1124     // measuring empty strings is not guaranteed, so do it by hand 
1132         // MeasureString does return a rectangle that is way too large, so it is 
1134         RectF 
layoutRect(0,0, 100000.0f
, 100000.0f
); 
1135         StringFormat strFormat
; 
1136         CharacterRange 
strRange(0,wcslen(s
)); 
1137         strFormat
.SetMeasurableCharacterRanges(1,&strRange
); 
1139         m_context
->MeasureCharacterRanges(s
, -1 , f
,layoutRect
, &strFormat
,1,®ion
) ; 
1141         region
.GetBounds(&bbox
,m_context
); 
1143             *width 
= bbox
.GetRight()-bbox
.GetLeft()+0.5; 
1147 void wxGDIPlusContext::GetPartialTextExtents(const wxString
& text
, wxArrayDouble
& widths
) const 
1150     widths
.Add(0, text
.length()); 
1155     Font
* f 
= ((wxGDIPlusFontData
*)m_font
.GetRefData())->GetGDIPlusFont(); 
1156     wxWCharBuffer ws 
= text
.wc_str( *wxConvUI 
); 
1157     size_t len 
= wcslen( ws 
) ; 
1158     wxASSERT_MSG(text
.length() == len 
, wxT("GetPartialTextExtents not yet implemented for multichar situations")); 
1160     RectF 
layoutRect(0,0, 100000.0f
, 100000.0f
); 
1161     StringFormat strFormat
; 
1163     CharacterRange
* ranges 
= new CharacterRange
[len
] ; 
1164     Region
* regions 
= new Region
[len
]; 
1165     for( size_t i 
= 0 ; i 
< len 
; ++i
) 
1167         ranges
[i
].First 
= i 
; 
1168         ranges
[i
].Length 
= 1 ; 
1170     strFormat
.SetMeasurableCharacterRanges(len
,ranges
); 
1171     m_context
->MeasureCharacterRanges(ws
, -1 , f
,layoutRect
, &strFormat
,1,regions
) ; 
1174     for ( size_t i 
= 0 ; i 
< len 
; ++i
) 
1176         regions
[i
].GetBounds(&bbox
,m_context
); 
1177         widths
[i
] = bbox
.GetRight()-bbox
.GetLeft(); 
1181 void* wxGDIPlusContext::GetNativeContext() 
1186 // concatenates this transform with the current transform of this context 
1187 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix
& matrix 
) 
1189     m_context
->MultiplyTransform((Matrix
*) matrix
.GetNativeMatrix()); 
1192 // sets the transform of this context 
1193 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix
& matrix 
) 
1195     m_context
->SetTransform((Matrix
*) matrix
.GetNativeMatrix()); 
1198 // gets the matrix of this context 
1199 wxGraphicsMatrix 
wxGDIPlusContext::GetTransform() const 
1201     wxGraphicsMatrix matrix 
= CreateMatrix(); 
1202     m_context
->GetTransform((Matrix
*) matrix
.GetNativeMatrix()); 
1205 //----------------------------------------------------------------------------- 
1206 // wxGDIPlusRenderer declaration 
1207 //----------------------------------------------------------------------------- 
1209 class WXDLLIMPEXP_CORE wxGDIPlusRenderer 
: public wxGraphicsRenderer
 
1218     virtual ~wxGDIPlusRenderer() 
1228     virtual wxGraphicsContext 
* CreateContext( const wxWindowDC
& dc
); 
1230     virtual wxGraphicsContext 
* CreateContext( const wxMemoryDC
& dc
); 
1232     virtual wxGraphicsContext 
* CreateContextFromNativeContext( void * context 
); 
1234     virtual wxGraphicsContext 
* CreateContextFromNativeWindow( void * window 
); 
1236     virtual wxGraphicsContext 
* CreateContext( wxWindow
* window 
); 
1238     virtual wxGraphicsContext 
* CreateMeasuringContext(); 
1242     virtual wxGraphicsPath 
CreatePath(); 
1246     virtual wxGraphicsMatrix 
CreateMatrix( wxDouble a
=1.0, wxDouble b
=0.0, wxDouble c
=0.0, wxDouble d
=1.0, 
1247         wxDouble tx
=0.0, wxDouble ty
=0.0); 
1250     virtual wxGraphicsPen 
CreatePen(const wxPen
& pen
) ; 
1252     virtual wxGraphicsBrush 
CreateBrush(const wxBrush
& brush 
) ; 
1254     // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 
1255     virtual wxGraphicsBrush 
CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, 
1256         const wxColour
&c1
, const wxColour
&c2
) ; 
1258     // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) 
1259     // with radius r and color cColor 
1260     virtual wxGraphicsBrush 
CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
, 
1261         const wxColour 
&oColor
, const wxColour 
&cColor
) ; 
1264     virtual wxGraphicsFont 
CreateFont( const wxFont 
&font 
, const wxColour 
&col 
= *wxBLACK 
) ; 
1266     void EnsureIsLoaded(); 
1272     ULONG_PTR m_gditoken
; 
1274     DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer
) 
1277 //----------------------------------------------------------------------------- 
1278 // wxGDIPlusRenderer implementation 
1279 //----------------------------------------------------------------------------- 
1281 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer
,wxGraphicsRenderer
) 
1283 static wxGDIPlusRenderer gs_GDIPlusRenderer
; 
1285 wxGraphicsRenderer
* wxGraphicsRenderer::GetDefaultRenderer() 
1287     return &gs_GDIPlusRenderer
; 
1290 void wxGDIPlusRenderer::EnsureIsLoaded() 
1298 void wxGDIPlusRenderer::Load() 
1300     GdiplusStartupInput input
; 
1301     GdiplusStartupOutput output
; 
1302     GdiplusStartup(&m_gditoken
,&input
,&output
); 
1306 void wxGDIPlusRenderer::Unload() 
1309         GdiplusShutdown(m_gditoken
); 
1312 wxGraphicsContext 
* wxGDIPlusRenderer::CreateContext( const wxWindowDC
& dc
) 
1315     return new wxGDIPlusContext(this,(HDC
) dc
.GetHDC()); 
1318 wxGraphicsContext 
* wxGDIPlusRenderer::CreateContext( const wxMemoryDC
& dc
) 
1321     return new wxGDIPlusContext(this,(HDC
) dc
.GetHDC()); 
1324 wxGraphicsContext 
* wxGDIPlusRenderer::CreateMeasuringContext() 
1328     // TODO use GetDC(NULL) but then we have to release it from the context 
1329     //return new wxGDIPlusContext(this,(HDC) dc.GetHDC()); 
1332 wxGraphicsContext 
* wxGDIPlusRenderer::CreateContextFromNativeContext( void * context 
) 
1335     return new wxGDIPlusContext(this,(Graphics
*) context
); 
1339 wxGraphicsContext 
* wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window 
) 
1342     return new wxGDIPlusContext(this,(HWND
) window
); 
1345 wxGraphicsContext 
* wxGDIPlusRenderer::CreateContext( wxWindow
* window 
) 
1348     return new wxGDIPlusContext(this, (HWND
) window
->GetHWND() ); 
1353 wxGraphicsPath 
wxGDIPlusRenderer::CreatePath() 
1357     m
.SetRefData( new wxGDIPlusPathData(this)); 
1364 wxGraphicsMatrix 
wxGDIPlusRenderer::CreateMatrix( wxDouble a
, wxDouble b
, wxDouble c
, wxDouble d
, 
1365                                                            wxDouble tx
, wxDouble ty
) 
1370     wxGDIPlusMatrixData
* data 
= new wxGDIPlusMatrixData( this ); 
1371     data
->Set( a
,b
,c
,d
,tx
,ty 
) ; 
1376 wxGraphicsPen 
wxGDIPlusRenderer::CreatePen(const wxPen
& pen
) 
1379     if ( !pen
.Ok() || pen
.GetStyle() == wxTRANSPARENT 
) 
1380         return wxNullGraphicsPen
; 
1384         p
.SetRefData(new wxGDIPlusPenData( this, pen 
)); 
1389 wxGraphicsBrush 
wxGDIPlusRenderer::CreateBrush(const wxBrush
& brush 
) 
1392     if ( !brush
.Ok() || brush
.GetStyle() == wxTRANSPARENT 
) 
1393         return wxNullGraphicsBrush
; 
1397         p
.SetRefData(new wxGDIPlusBrushData( this, brush 
)); 
1402 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 
1403 wxGraphicsBrush 
wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1
, wxDouble y1
, wxDouble x2
, wxDouble y2
, 
1404                                                                       const wxColour
&c1
, const wxColour
&c2
) 
1408     wxGDIPlusBrushData
* d 
= new wxGDIPlusBrushData( this ); 
1409     d
->CreateLinearGradientBrush(x1
, y1
, x2
, y2
, c1
, c2
); 
1414 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) 
1415 // with radius r and color cColor 
1416 wxGraphicsBrush 
wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo
, wxDouble yo
, wxDouble xc
, wxDouble yc
, wxDouble radius
, 
1417                                                                       const wxColour 
&oColor
, const wxColour 
&cColor
) 
1421     wxGDIPlusBrushData
* d 
= new wxGDIPlusBrushData( this ); 
1422     d
->CreateRadialGradientBrush(xo
,yo
,xc
,yc
,radius
,oColor
,cColor
); 
1428 wxGraphicsFont 
wxGDIPlusRenderer::CreateFont( const wxFont 
&font 
, const wxColour 
&col 
) 
1434         p
.SetRefData(new wxGDIPlusFontData( this , font
, col 
)); 
1438         return wxNullGraphicsFont
; 
1441 #endif  // wxUSE_GRAPHICS_CONTEXT