1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/graphcmn.cpp
3 // Purpose:     graphics context methods common to all platforms
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:
7 // RCS-ID:      $Id: dcgraph.cpp 60190 2009-04-16 00:57:35Z KO $
8 // Copyright:   (c) Stefan Csomor
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14 
15 #if defined(__BORLANDC__)
16     #pragma hdrstop
17 #endif
18 
19 #if wxUSE_GRAPHICS_CONTEXT
20 
21 #include "wx/graphics.h"
22 
23 #ifndef WX_PRECOMP
24     #include "wx/icon.h"
25     #include "wx/bitmap.h"
26     #include "wx/dcmemory.h"
27     #include "wx/region.h"
28 #endif
29 
30 #ifdef __WXMAC__
31 #include "wx/mac/private.h"
32 #endif
33 //-----------------------------------------------------------------------------
34 // constants
35 //-----------------------------------------------------------------------------
36 
37 static const double RAD2DEG = 180.0 / M_PI;
38 
39 //-----------------------------------------------------------------------------
40 // Local functions
41 //-----------------------------------------------------------------------------
42 
DegToRad(double deg)43 static inline double DegToRad(double deg)
44 {
45     return (deg * M_PI) / 180.0;
46 }
47 
48 //-----------------------------------------------------------------------------
49 // wxDC bridge class
50 //-----------------------------------------------------------------------------
51 
52 #ifdef __WXMAC__
IMPLEMENT_DYNAMIC_CLASS(wxGCDC,wxDCBase)53 IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDCBase)
54 #else
55 IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC)
56 #endif
57 
58 wxGCDC::wxGCDC()
59 {
60     Init();
61 }
62 
SetGraphicsContext(wxGraphicsContext * ctx)63 void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx )
64 {
65     delete m_graphicContext;
66     m_graphicContext = ctx;
67     if ( m_graphicContext )
68     {
69         m_matrixOriginal = m_graphicContext->GetTransform();
70         m_ok = true;
71         // apply the stored transformations to the passed in context
72         ComputeScaleAndOrigin();
73         m_graphicContext->SetFont( m_font , m_textForegroundColour );
74         m_graphicContext->SetPen( m_pen );
75         m_graphicContext->SetBrush( m_brush);
76     }
77 }
78 
wxGCDC(const wxWindowDC & dc)79 wxGCDC::wxGCDC(const wxWindowDC& dc)
80 {
81     Init();
82     wxGraphicsContext* context;
83 #if wxUSE_CAIRO
84     wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetCairoRenderer();
85     context = renderer->CreateContext(dc);
86 #else
87     context = wxGraphicsContext::Create(dc);
88 #endif
89 
90     SetGraphicsContext( context );
91 }
92 
93 #ifdef __WXMSW__
wxGCDC(const wxMemoryDC & dc)94 wxGCDC::wxGCDC(const wxMemoryDC& dc)
95 {
96     Init();
97     SetGraphicsContext( wxGraphicsContext::Create(dc) );
98 }
99 #endif
100 
Init()101 void wxGCDC::Init()
102 {
103     m_ok = false;
104     m_colour = true;
105     m_mm_to_pix_x = mm2pt;
106     m_mm_to_pix_y = mm2pt;
107 
108     m_pen = *wxBLACK_PEN;
109     m_font = *wxNORMAL_FONT;
110     m_brush = *wxWHITE_BRUSH;
111 
112     m_graphicContext = NULL;
113     m_logicalFunctionSupported = true;
114 }
115 
116 
~wxGCDC()117 wxGCDC::~wxGCDC()
118 {
119     delete m_graphicContext;
120 }
121 
DoDrawBitmap(const wxBitmap & bmp,wxCoord x,wxCoord y,bool WXUNUSED (useMask))122 void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
123 {
124     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") );
125     wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") );
126 
127     if ( bmp.GetDepth() == 1 )
128     {
129         m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
130         m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) );
131         m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() );
132         m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) );
133         m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() );
134         m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush));
135         m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen));
136     }
137     else
138         m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() );
139 }
140 
DoDrawIcon(const wxIcon & icon,wxCoord x,wxCoord y)141 void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
142 {
143     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") );
144     wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") );
145 
146     wxCoord w = icon.GetWidth();
147     wxCoord h = icon.GetHeight();
148 
149     m_graphicContext->DrawIcon( icon , x, y, w, h );
150 }
151 
StartDoc(const wxString & WXUNUSED (message))152 bool wxGCDC::StartDoc( const wxString& WXUNUSED(message) )
153 {
154     return true;
155 }
156 
EndDoc()157 void wxGCDC::EndDoc()
158 {
159 }
160 
StartPage()161 void wxGCDC::StartPage()
162 {
163 }
164 
EndPage()165 void wxGCDC::EndPage()
166 {
167 }
168 
Flush()169 void wxGCDC::Flush()
170 {
171 #ifdef __WXMAC__
172     CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() );
173 #endif
174 }
175 
DoSetClippingRegion(wxCoord x,wxCoord y,wxCoord w,wxCoord h)176 void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
177 {
178     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") );
179 
180     m_graphicContext->Clip( x, y, w, h );
181     if ( m_clipping )
182     {
183         m_clipX1 = wxMax( m_clipX1, x );
184         m_clipY1 = wxMax( m_clipY1, y );
185         m_clipX2 = wxMin( m_clipX2, (x + w) );
186         m_clipY2 = wxMin( m_clipY2, (y + h) );
187     }
188     else
189     {
190         m_clipping = true;
191 
192         m_clipX1 = x;
193         m_clipY1 = y;
194         m_clipX2 = x + w;
195         m_clipY2 = y + h;
196     }
197 }
198 
DoSetClippingRegionAsRegion(const wxRegion & region)199 void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion &region )
200 {
201     // region is in device coordinates
202     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") );
203 
204     if (region.Empty())
205     {
206         //DestroyClippingRegion();
207         return;
208     }
209 
210     wxRegion logRegion( region );
211     wxCoord x, y, w, h;
212 
213     logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) );
214     logRegion.GetBox( x, y, w, h );
215 
216     m_graphicContext->Clip( logRegion );
217     if ( m_clipping )
218     {
219         m_clipX1 = wxMax( m_clipX1, x );
220         m_clipY1 = wxMax( m_clipY1, y );
221         m_clipX2 = wxMin( m_clipX2, (x + w) );
222         m_clipY2 = wxMin( m_clipY2, (y + h) );
223     }
224     else
225     {
226         m_clipping = true;
227 
228         m_clipX1 = x;
229         m_clipY1 = y;
230         m_clipX2 = x + w;
231         m_clipY2 = y + h;
232     }
233 }
234 
DestroyClippingRegion()235 void wxGCDC::DestroyClippingRegion()
236 {
237     m_graphicContext->ResetClip();
238     // currently the clip eg of a window extends to the area between the scrollbars
239     // so we must explicitely make sure it only covers the area we want it to draw
240     int width, height ;
241     GetSize( &width , &height ) ;
242     m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) );
243 
244     m_graphicContext->SetPen( m_pen );
245     m_graphicContext->SetBrush( m_brush );
246 
247     m_clipping = false;
248 }
249 
DoGetSizeMM(int * width,int * height) const250 void wxGCDC::DoGetSizeMM( int* width, int* height ) const
251 {
252     int w = 0, h = 0;
253 
254     GetSize( &w, &h );
255     if (width)
256         *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) );
257     if (height)
258         *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) );
259 }
260 
SetTextForeground(const wxColour & col)261 void wxGCDC::SetTextForeground( const wxColour &col )
262 {
263     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") );
264 
265     if ( col != m_textForegroundColour )
266     {
267         m_textForegroundColour = col;
268         m_graphicContext->SetFont( m_font, m_textForegroundColour );
269     }
270 }
271 
SetTextBackground(const wxColour & col)272 void wxGCDC::SetTextBackground( const wxColour &col )
273 {
274     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") );
275 
276     m_textBackgroundColour = col;
277 }
278 
SetMapMode(int mode)279 void wxGCDC::SetMapMode( int mode )
280 {
281     switch (mode)
282     {
283     case wxMM_TWIPS:
284         SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y );
285         break;
286 
287     case wxMM_POINTS:
288         SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y );
289         break;
290 
291     case wxMM_METRIC:
292         SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
293         break;
294 
295     case wxMM_LOMETRIC:
296         SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 );
297         break;
298 
299     case wxMM_TEXT:
300     default:
301         SetLogicalScale( 1.0, 1.0 );
302         break;
303     }
304 
305     ComputeScaleAndOrigin();
306 }
307 
SetUserScale(double x,double y)308 void wxGCDC::SetUserScale( double x, double y )
309 {
310     // allow negative ? -> no
311 
312     m_userScaleX = x;
313     m_userScaleY = y;
314     ComputeScaleAndOrigin();
315 }
316 
SetLogicalScale(double x,double y)317 void wxGCDC::SetLogicalScale( double x, double y )
318 {
319     // allow negative ?
320     m_logicalScaleX = x;
321     m_logicalScaleY = y;
322     ComputeScaleAndOrigin();
323 }
324 
SetLogicalOrigin(wxCoord x,wxCoord y)325 void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y )
326 {
327     m_logicalOriginX = x * m_signX;   // is this still correct ?
328     m_logicalOriginY = y * m_signY;
329     ComputeScaleAndOrigin();
330 }
331 
SetDeviceOrigin(wxCoord x,wxCoord y)332 void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y )
333 {
334     m_deviceOriginX = x;
335     m_deviceOriginY = y;
336     ComputeScaleAndOrigin();
337 }
338 
SetAxisOrientation(bool xLeftRight,bool yBottomUp)339 void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
340 {
341     m_signX = (xLeftRight ?  1 : -1);
342     m_signY = (yBottomUp ? -1 :  1);
343     ComputeScaleAndOrigin();
344 }
345 
GetPPI() const346 wxSize wxGCDC::GetPPI() const
347 {
348     return wxSize(72, 72);
349 }
350 
GetDepth() const351 int wxGCDC::GetDepth() const
352 {
353     return 32;
354 }
355 
ComputeScaleAndOrigin()356 void wxGCDC::ComputeScaleAndOrigin()
357 {
358     m_scaleX = m_logicalScaleX * m_userScaleX;
359     m_scaleY = m_logicalScaleY * m_userScaleY;
360 
361     if ( m_graphicContext )
362     {
363         m_matrixCurrent = m_graphicContext->CreateMatrix();
364         m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY );
365         m_matrixCurrent.Scale( m_scaleX, m_scaleY );
366         // the logical origin sets the origin to have new coordinates
367         m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY );
368 
369         m_graphicContext->SetTransform( m_matrixOriginal );
370         m_graphicContext->ConcatTransform( m_matrixCurrent );
371     }
372 }
373 
SetPalette(const wxPalette & WXUNUSED (palette))374 void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) )
375 {
376 
377 }
378 
SetBackgroundMode(int mode)379 void wxGCDC::SetBackgroundMode( int mode )
380 {
381     m_backgroundMode = mode;
382 }
383 
SetFont(const wxFont & font)384 void wxGCDC::SetFont( const wxFont &font )
385 {
386     m_font = font;
387     if ( m_graphicContext )
388     {
389         wxFont f = font;
390         if ( f.Ok() )
391             f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize()));
392         m_graphicContext->SetFont( f, m_textForegroundColour );
393     }
394 }
395 
SetPen(const wxPen & pen)396 void wxGCDC::SetPen( const wxPen &pen )
397 {
398     if ( m_pen == pen )
399         return;
400 
401     m_pen = pen;
402     if ( m_graphicContext )
403     {
404         m_graphicContext->SetPen( m_pen );
405     }
406 }
407 
SetBrush(const wxBrush & brush)408 void wxGCDC::SetBrush( const wxBrush &brush )
409 {
410     if (m_brush == brush)
411         return;
412 
413     m_brush = brush;
414     if ( m_graphicContext )
415     {
416         m_graphicContext->SetBrush( m_brush );
417     }
418 }
419 
SetBackground(const wxBrush & brush)420 void wxGCDC::SetBackground( const wxBrush &brush )
421 {
422     if (m_backgroundBrush == brush)
423         return;
424 
425     m_backgroundBrush = brush;
426     if (!m_backgroundBrush.Ok())
427         return;
428 }
429 
SetLogicalFunction(int function)430 void wxGCDC::SetLogicalFunction( int function )
431 {
432     if (m_logicalFunction == function)
433         return;
434 
435     m_logicalFunction = function;
436     if ( m_graphicContext->SetLogicalFunction( function ) )
437         m_logicalFunctionSupported=true;
438     else
439         m_logicalFunctionSupported=false;
440 }
441 
DoFloodFill(wxCoord WXUNUSED (x),wxCoord WXUNUSED (y),const wxColour & WXUNUSED (col),int WXUNUSED (style))442 bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
443                          const wxColour& WXUNUSED(col), int WXUNUSED(style))
444 {
445     return false;
446 }
447 
DoGetPixel(wxCoord WXUNUSED (x),wxCoord WXUNUSED (y),wxColour * WXUNUSED (col)) const448 bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const
449 {
450     //  wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") );
451     return false;
452 }
453 
DoDrawLine(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2)454 void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
455 {
456     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") );
457 
458     if ( !m_logicalFunctionSupported )
459         return;
460 
461     m_graphicContext->StrokeLine(x1,y1,x2,y2);
462 
463     CalcBoundingBox(x1, y1);
464     CalcBoundingBox(x2, y2);
465 }
466 
DoCrossHair(wxCoord x,wxCoord y)467 void wxGCDC::DoCrossHair( wxCoord x, wxCoord y )
468 {
469     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") );
470 
471     if ( !m_logicalFunctionSupported )
472         return;
473 
474     int w = 0, h = 0;
475 
476     GetSize( &w, &h );
477 
478     m_graphicContext->StrokeLine(0,y,w,y);
479     m_graphicContext->StrokeLine(x,0,x,h);
480 
481     CalcBoundingBox(0, 0);
482     CalcBoundingBox(0+w, 0+h);
483 }
484 
DoDrawArc(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2,wxCoord xc,wxCoord yc)485 void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1,
486                         wxCoord x2, wxCoord y2,
487                         wxCoord xc, wxCoord yc )
488 {
489     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") );
490 
491     if ( !m_logicalFunctionSupported )
492         return;
493 
494     double dx = x1 - xc;
495     double dy = y1 - yc;
496     double radius = sqrt((double)(dx * dx + dy * dy));
497     wxCoord rad = (wxCoord)radius;
498     double sa, ea;
499     if (x1 == x2 && y1 == y2)
500     {
501         sa = 0.0;
502         ea = 360.0;
503     }
504     else if (radius == 0.0)
505     {
506         sa = ea = 0.0;
507     }
508     else
509     {
510         sa = (x1 - xc == 0) ?
511      (y1 - yc < 0) ? 90.0 : -90.0 :
512              -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG;
513         ea = (x2 - xc == 0) ?
514      (y2 - yc < 0) ? 90.0 : -90.0 :
515              -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG;
516     }
517 
518     bool fill = m_brush.GetStyle() != wxTRANSPARENT;
519 
520     wxGraphicsPath path = m_graphicContext->CreatePath();
521     if ( fill && ((x1!=x2)||(y1!=y2)) )
522         path.MoveToPoint( xc, yc );
523     // since these angles (ea,sa) are measured counter-clockwise, we invert them to
524     // get clockwise angles
525     path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false );
526     if ( fill && ((x1!=x2)||(y1!=y2)) )
527         path.AddLineToPoint( xc, yc );
528     m_graphicContext->DrawPath(path);
529 }
530 
DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)531 void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
532                                 double sa, double ea )
533 {
534     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") );
535 
536     if ( !m_logicalFunctionSupported )
537         return;
538 
539     m_graphicContext->PushState();
540     m_graphicContext->Translate(x+w/2.0,y+h/2.0);
541     wxDouble factor = ((wxDouble) w) / h;
542     m_graphicContext->Scale( factor , 1.0);
543 
544     // since these angles (ea,sa) are measured counter-clockwise, we invert them to
545     // get clockwise angles
546     if ( m_brush.GetStyle() != wxTRANSPARENT )
547     {
548         wxGraphicsPath path = m_graphicContext->CreatePath();
549         path.MoveToPoint( 0, 0 );
550         path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
551         path.AddLineToPoint( 0, 0 );
552         m_graphicContext->FillPath( path );
553 
554         path = m_graphicContext->CreatePath();
555         path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
556         m_graphicContext->StrokePath( path );
557     }
558     else
559     {
560         wxGraphicsPath path = m_graphicContext->CreatePath();
561         path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
562         m_graphicContext->DrawPath( path );
563     }
564 
565     m_graphicContext->PopState();
566 }
567 
DoDrawPoint(wxCoord x,wxCoord y)568 void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y )
569 {
570     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") );
571 
572     DoDrawLine( x , y , x + 1 , y + 1 );
573 }
574 
DoDrawLines(int n,wxPoint points[],wxCoord xoffset,wxCoord yoffset)575 void wxGCDC::DoDrawLines(int n, wxPoint points[],
576                          wxCoord xoffset, wxCoord yoffset)
577 {
578     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") );
579 
580     if ( !m_logicalFunctionSupported )
581         return;
582 
583     wxPoint2DDouble* pointsD = new wxPoint2DDouble[n];
584     for( int i = 0; i < n; ++i)
585     {
586         pointsD[i].m_x = points[i].x + xoffset;
587         pointsD[i].m_y = points[i].y + yoffset;
588     }
589 
590     m_graphicContext->StrokeLines( n , pointsD);
591     delete[] pointsD;
592 }
593 
594 #if wxUSE_SPLINES
DoDrawSpline(wxList * points)595 void wxGCDC::DoDrawSpline(wxList *points)
596 {
597     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") );
598 
599     if ( !m_logicalFunctionSupported )
600         return;
601 
602     wxGraphicsPath path = m_graphicContext->CreatePath();
603 
604     wxList::compatibility_iterator node = points->GetFirst();
605     if (node == wxList::compatibility_iterator())
606         // empty list
607         return;
608 
609     wxPoint *p = (wxPoint *)node->GetData();
610 
611     wxCoord x1 = p->x;
612     wxCoord y1 = p->y;
613 
614     node = node->GetNext();
615     p = (wxPoint *)node->GetData();
616 
617     wxCoord x2 = p->x;
618     wxCoord y2 = p->y;
619     wxCoord cx1 = ( x1 + x2 ) / 2;
620     wxCoord cy1 = ( y1 + y2 ) / 2;
621 
622     path.MoveToPoint( x1 , y1 );
623     path.AddLineToPoint( cx1 , cy1 );
624 #if !wxUSE_STL
625 
626     while ((node = node->GetNext()) != NULL)
627 #else
628 
629     while ((node = node->GetNext()))
630 #endif // !wxUSE_STL
631 
632     {
633         p = (wxPoint *)node->GetData();
634         x1 = x2;
635         y1 = y2;
636         x2 = p->x;
637         y2 = p->y;
638         wxCoord cx4 = (x1 + x2) / 2;
639         wxCoord cy4 = (y1 + y2) / 2;
640 
641         path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 );
642 
643         cx1 = cx4;
644         cy1 = cy4;
645     }
646 
647     path.AddLineToPoint( x2 , y2 );
648 
649     m_graphicContext->StrokePath( path );
650 }
651 #endif // wxUSE_SPLINES
652 
DoDrawPolygon(int n,wxPoint points[],wxCoord xoffset,wxCoord yoffset,int fillStyle)653 void wxGCDC::DoDrawPolygon( int n, wxPoint points[],
654                             wxCoord xoffset, wxCoord yoffset,
655                             int fillStyle )
656 {
657     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") );
658 
659     if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
660         return;
661     if ( !m_logicalFunctionSupported )
662         return;
663 
664     bool closeIt = false;
665     if (points[n-1] != points[0])
666         closeIt = true;
667 
668     wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)];
669     for( int i = 0; i < n; ++i)
670     {
671         pointsD[i].m_x = points[i].x + xoffset;
672         pointsD[i].m_y = points[i].y + yoffset;
673     }
674     if ( closeIt )
675         pointsD[n] = pointsD[0];
676 
677     m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle);
678     delete[] pointsD;
679 }
680 
DoDrawPolyPolygon(int n,int count[],wxPoint points[],wxCoord xoffset,wxCoord yoffset,int fillStyle)681 void wxGCDC::DoDrawPolyPolygon(int n,
682                                int count[],
683                                wxPoint points[],
684                                wxCoord xoffset,
685                                wxCoord yoffset,
686                                int fillStyle)
687 {
688     wxASSERT(n > 1);
689     wxGraphicsPath path = m_graphicContext->CreatePath();
690 
691     int i = 0;
692     for ( int j = 0; j < n; ++j)
693     {
694         wxPoint start = points[i];
695         path.MoveToPoint( start.x+ xoffset, start.y+ yoffset);
696         ++i;
697         int l = count[j];
698         for ( int k = 1; k < l; ++k)
699         {
700             path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset);
701             ++i;
702         }
703         // close the polygon
704         if ( start != points[i-1])
705             path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset);
706     }
707     m_graphicContext->DrawPath( path , fillStyle);
708 }
709 
DoDrawRectangle(wxCoord x,wxCoord y,wxCoord w,wxCoord h)710 void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
711 {
712     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") );
713 
714     if ( !m_logicalFunctionSupported )
715         return;
716 
717     // CMB: draw nothing if transformed w or h is 0
718     if (w == 0 || h == 0)
719         return;
720 
721     if ( m_graphicContext->ShouldOffset() )
722     {
723         // if we are offsetting the entire rectangle is moved 0.5, so the
724         // border line gets off by 1
725         w -= 1;
726         h -= 1;
727     }
728     m_graphicContext->DrawRectangle(x,y,w,h);
729 }
730 
DoDrawRoundedRectangle(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double radius)731 void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
732                                     wxCoord w, wxCoord h,
733                                     double radius)
734 {
735     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") );
736 
737     if ( !m_logicalFunctionSupported )
738         return;
739 
740     if (radius < 0.0)
741         radius = - radius * ((w < h) ? w : h);
742 
743     // CMB: draw nothing if transformed w or h is 0
744     if (w == 0 || h == 0)
745         return;
746 
747     if ( m_graphicContext->ShouldOffset() )
748     {
749         // if we are offsetting the entire rectangle is moved 0.5, so the
750         // border line gets off by 1
751         w -= 1;
752         h -= 1;
753     }
754     m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius);
755 }
756 
DoDrawEllipse(wxCoord x,wxCoord y,wxCoord w,wxCoord h)757 void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
758 {
759     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") );
760 
761     if ( !m_logicalFunctionSupported )
762         return;
763 
764     if ( m_graphicContext->ShouldOffset() )
765     {
766         // if we are offsetting the entire rectangle is moved 0.5, so the
767         // border line gets off by 1
768         w -= 1;
769         h -= 1;
770     }
771     m_graphicContext->DrawEllipse(x,y,w,h);
772 }
773 
CanDrawBitmap() const774 bool wxGCDC::CanDrawBitmap() const
775 {
776     return true;
777 }
778 
DoBlit(wxCoord xdest,wxCoord ydest,wxCoord width,wxCoord height,wxDC * source,wxCoord xsrc,wxCoord ysrc,int logical_func,bool WXUNUSED (useMask),wxCoord xsrcMask,wxCoord ysrcMask)779 bool wxGCDC::DoBlit(
780     wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
781     wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask),
782     wxCoord xsrcMask, wxCoord ysrcMask )
783 {
784     wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") );
785     wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") );
786 
787     if ( logical_func == wxNO_OP )
788         return true;
789     else if ( !m_graphicContext->SetLogicalFunction( logical_func ) )
790 
791     {
792         wxFAIL_MSG( wxT("Logical function is not supported by the graphics context.") );
793         return false;
794     }
795 
796     if (xsrcMask == -1 && ysrcMask == -1)
797     {
798         xsrcMask = xsrc;
799         ysrcMask = ysrc;
800     }
801 
802     wxRect subrect(source->LogicalToDeviceX(xsrc),
803                    source->LogicalToDeviceY(ysrc),
804                    source->LogicalToDeviceXRel(width),
805                    source->LogicalToDeviceYRel(height));
806 
807     // if needed clip the subrect down to the size of the source DC
808     wxCoord sw, sh;
809     source->GetSize(&sw, &sh);
810     sw = source->LogicalToDeviceXRel(sw);
811     sh = source->LogicalToDeviceYRel(sh);
812     if (subrect.x + subrect.width > sw)
813         subrect.width = sw - subrect.x;
814     if (subrect.y + subrect.height > sh)
815         subrect.height = sh - subrect.y;
816 
817     wxBitmap blit = source->GetAsBitmap( &subrect );
818 
819     if ( blit.Ok() )
820     {
821         m_graphicContext->DrawBitmap( blit, xdest, ydest,
822                                       wxMin(width, blit.GetWidth()),
823                                       wxMin(height, blit.GetHeight()));
824     }
825     else
826     {
827         wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
828         return false;
829     }
830 
831     // reset logical function
832     m_graphicContext->SetLogicalFunction( m_logicalFunction );
833 
834     return true;
835 }
836 
DoDrawRotatedText(const wxString & str,wxCoord x,wxCoord y,double angle)837 void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
838                                double angle)
839 {
840     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
841 
842     if ( str.length() == 0 )
843         return;
844     if ( !m_logicalFunctionSupported )
845         return;
846 
847     if ( m_backgroundMode == wxTRANSPARENT )
848         m_graphicContext->DrawText( str, x ,y , DegToRad(angle ));
849     else
850         m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) );
851 }
852 
DoDrawText(const wxString & str,wxCoord x,wxCoord y)853 void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y)
854 {
855     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
856 
857     if ( str.length() == 0 )
858         return;
859 
860     if ( !m_logicalFunctionSupported )
861         return;
862 
863     if ( m_backgroundMode == wxTRANSPARENT )
864         m_graphicContext->DrawText( str, x ,y);
865     else
866         m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) );
867 }
868 
CanGetTextExtent() const869 bool wxGCDC::CanGetTextExtent() const
870 {
871     wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") );
872 
873     return true;
874 }
875 
DoGetTextExtent(const wxString & str,wxCoord * width,wxCoord * height,wxCoord * descent,wxCoord * externalLeading,wxFont * theFont) const876 void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
877                               wxCoord *descent, wxCoord *externalLeading ,
878                               wxFont *theFont ) const
879 {
880     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") );
881 
882     if ( theFont )
883     {
884         m_graphicContext->SetFont( *theFont, m_textForegroundColour );
885     }
886 
887     wxDouble h , d , e , w;
888 
889     m_graphicContext->GetTextExtent( str, &w, &h, &d, &e );
890 
891     if ( height )
892         *height = (wxCoord)(h+0.5);
893     if ( descent )
894         *descent = (wxCoord)(d+0.5);
895     if ( externalLeading )
896         *externalLeading = (wxCoord)(e+0.5);
897     if ( width )
898         *width = (wxCoord)(w+0.5);
899 
900     if ( theFont )
901     {
902         m_graphicContext->SetFont( m_font, m_textForegroundColour );
903     }
904 }
905 
DoGetPartialTextExtents(const wxString & text,wxArrayInt & widths) const906 bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
907 {
908     wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") );
909     widths.Clear();
910     widths.Add(0,text.Length());
911     if ( text.IsEmpty() )
912         return true;
913 
914     wxArrayDouble widthsD;
915 
916     m_graphicContext->GetPartialTextExtents( text, widthsD );
917     for ( size_t i = 0; i < widths.GetCount(); ++i )
918         widths[i] = (wxCoord)(widthsD[i] + 0.5);
919 
920     return true;
921 }
922 
GetCharWidth(void) const923 wxCoord wxGCDC::GetCharWidth(void) const
924 {
925     wxCoord width;
926     DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL );
927 
928     return width;
929 }
930 
GetCharHeight(void) const931 wxCoord wxGCDC::GetCharHeight(void) const
932 {
933     wxCoord height;
934     DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL );
935 
936     return height;
937 }
938 
Clear(void)939 void wxGCDC::Clear(void)
940 {
941     wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") );
942     // TODO better implementation / incorporate size info into wxGCDC or context
943     m_graphicContext->SetBrush( m_backgroundBrush );
944     wxPen p = *wxTRANSPARENT_PEN;
945     m_graphicContext->SetPen( p );
946     DoDrawRectangle( 0, 0, 32000 , 32000 );
947     m_graphicContext->SetPen( m_pen );
948     m_graphicContext->SetBrush( m_brush );
949 }
950 
DoGetSize(int * width,int * height) const951 void wxGCDC::DoGetSize(int *width, int *height) const
952 {
953     *width = 10000;
954     *height = 10000;
955 }
956 
DoGradientFillLinear(const wxRect & rect,const wxColour & initialColour,const wxColour & destColour,wxDirection nDirection)957 void wxGCDC::DoGradientFillLinear(const wxRect& rect,
958                                   const wxColour& initialColour,
959                                   const wxColour& destColour,
960                                   wxDirection nDirection )
961 {
962     wxPoint start;
963     wxPoint end;
964     switch( nDirection)
965     {
966     case wxWEST :
967         start = rect.GetRightBottom();
968         start.x++;
969         end = rect.GetLeftBottom();
970         break;
971     case wxEAST :
972         start = rect.GetLeftBottom();
973         end = rect.GetRightBottom();
974         end.x++;
975         break;
976     case wxNORTH :
977         start = rect.GetLeftBottom();
978         start.y++;
979         end = rect.GetLeftTop();
980         break;
981     case wxSOUTH :
982         start = rect.GetLeftTop();
983         end = rect.GetLeftBottom();
984         end.y++;
985         break;
986     default :
987         break;
988     }
989 
990     if (rect.width == 0 || rect.height == 0)
991         return;
992 
993     m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush(
994         start.x,start.y,end.x,end.y, initialColour, destColour));
995     m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
996     m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
997     m_graphicContext->SetPen(m_pen);
998 }
999 
DoGradientFillConcentric(const wxRect & rect,const wxColour & initialColour,const wxColour & destColour,const wxPoint & circleCenter)1000 void wxGCDC::DoGradientFillConcentric(const wxRect& rect,
1001                                       const wxColour& initialColour,
1002                                       const wxColour& destColour,
1003                                       const wxPoint& circleCenter)
1004 {
1005     //Radius
1006     wxInt32 cx = rect.GetWidth() / 2;
1007     wxInt32 cy = rect.GetHeight() / 2;
1008     wxInt32 nRadius;
1009     if (cx < cy)
1010         nRadius = cx;
1011     else
1012         nRadius = cy;
1013 
1014     // make sure the background is filled (todo move into specific platform implementation ?)
1015     m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
1016     m_graphicContext->SetBrush( wxBrush( destColour) );
1017     m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1018 
1019     m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush(
1020         rect.x+circleCenter.x,rect.y+circleCenter.y,
1021         rect.x+circleCenter.x,rect.y+circleCenter.y,
1022         nRadius,initialColour,destColour));
1023 
1024     m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1025     m_graphicContext->SetPen(m_pen);
1026 }
1027 
DoDrawCheckMark(wxCoord x,wxCoord y,wxCoord width,wxCoord height)1028 void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y,
1029                              wxCoord width, wxCoord height)
1030 {
1031     wxDCBase::DoDrawCheckMark(x,y,width,height);
1032 }
1033 
1034 #endif // wxUSE_GRAPHICS_CONTEXT
1035