wxArt2D
gdiplusdrawer.cpp
Go to the documentation of this file.
1 /*! \file gdiplusdrawer/src/gdiplusdrawer.cpp
2  \brief a2dGDIPlusDrawer - Drawer using the gdiplus library
3  \author Klaas Holwerda
4 
5  Copyright: 2001-2004 (C) Klaas Holwerda
6 
7  Licence: wxWidgets licence
8 
9  RCS-ID: $Id: gdiplusdrawer.cpp,v 1.11 2009/10/01 19:22:36 titato Exp $
10 */
11 
12 #include "a2dprec.h"
13 
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21 
22 #include <gdiplus.h>
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <math.h>
27 
28 #include "wx/msw/dc.h"
29 #include "wx/artbase/stylebase.h"
30 #include "wx/gdiplusdrawer/gdiplusdrawer.h"
31 
32 
33 #if wxART2D_USE_GDIPLUSDRAWER
34 
35 WX_DEFINE_LIST( RegionList );
36 
37 a2dGDIPlusDrawer::a2dGDIPlusDrawer( int width, int height ) : a2dDrawer2D( width, height )
38 {
39  Init();
40 }
41 
42 a2dGDIPlusDrawer::a2dGDIPlusDrawer( const wxSize& size ) : a2dDrawer2D( size )
43 {
44  Init();
45 }
46 
47 void a2dGDIPlusDrawer::Init()
48 {
49  GdiplusStartupInput input;
50  GdiplusStartupOutput output;
51  GdiplusStartup( &m_gdiplus_token, &input, &output );
52 
53  m_buffer = wxBitmap( m_width, m_height );
54  m_dc = new wxMemoryDC( );
55  m_dc->SelectObject( m_buffer );
56 
57 #if wxCHECK_VERSION(2, 9, 0)
58  const wxMSWDCImpl* impl;
59  impl = wxDynamicCast ( m_dc->GetImpl(), wxMSWDCImpl );
60  m_context = new Graphics( ( HDC ) impl->GetHDC( ) );
61 #else
62  m_context = new Graphics( ( HDC ) m_dc->GetHDC( ) );
63 #endif
64  m_context->SetSmoothingMode( SmoothingModeHighQuality );
65  m_context->SetSmoothingMode( SmoothingModeAntiAlias );
66 
67  m_current_pen = new Pen( Color( 0, 0, 0 ), 1 );
68  m_current_brush = new SolidBrush( Color( 0, 0, 0 ) );
69  m_matrix = Matrix().Clone();
70  m_penImage = NULL;
71  m_penBrush = NULL;
72  m_brushImage = NULL;
73  m_brushPath = NULL;
74 
75  m_externalDc = false;
76  m_deviceDC = 0;
77  m_clip.Clear();
78  m_OpacityFactor = 255;
79 }
80 
81 a2dGDIPlusDrawer::a2dGDIPlusDrawer( const a2dGDIPlusDrawer& other ) : a2dDrawer2D( other )
82 {
83  m_externalDc = false;
84  m_deviceDC = 0;
85  m_clip.Clear();
86 
87  m_buffer = other.m_buffer;
88 }
89 
90 a2dGDIPlusDrawer::~a2dGDIPlusDrawer( )
91 {
92  if ( m_matrix )
93  delete m_matrix;
94  delete m_context;
95  delete m_current_pen;
96  delete m_current_brush;
97  delete m_penImage;
98  delete m_penBrush;
99  delete m_brushImage;
100  delete m_brushPath;
101  delete m_dc;
102  GdiplusShutdown( m_gdiplus_token );
103 }
104 
105 Matrix* a2dGDIPlusDrawer::_get_gdiplus_user_to_device_transform()
106 {
107  if ( m_matrix )
108  delete m_matrix;
109  const a2dAffineMatrix& rmtx = GetUserToDeviceTransform();
110  Matrix mat(
111  ( REAL )rmtx( 0, 0 ), ( REAL )rmtx( 0, 1 ),
112  ( REAL )rmtx( 1, 0 ), ( REAL )rmtx( 1, 1 ),
113  ( REAL )rmtx( 2, 0 ), ( REAL )rmtx( 2, 1 ) );
114 
115  m_matrix = mat.Clone();
116  return m_matrix;
117 }
118 
119 void a2dGDIPlusDrawer::SetBufferSize( int w, int h )
120 {
121  m_width = w;
122  m_height = h;
123 
124  delete m_context;
125 
126  wxBitmap helpbuf = wxBitmap( w, h );
127  m_dc->SelectObject( wxNullBitmap );
128 
129  //make sure to preserve what was in the old buffer bitmap,
130  //to prevent the need for total redraws
131  wxMemoryDC mdc;
132 
133  m_dc->SelectObject( m_buffer );
134  mdc.SelectObject( helpbuf );
135  m_dc->Blit( 0, 0, w, h, &mdc, 0, 0 );
136  mdc.SelectObject( wxNullBitmap );
137  m_dc->SelectObject( wxNullBitmap );
138 
139  m_buffer = helpbuf;
140  m_dc->SelectObject( m_buffer );
141 #if wxCHECK_VERSION(2, 9, 0)
142  const wxMSWDCImpl* m_impl;
143  m_impl = wxDynamicCast ( m_dc->GetImpl(), wxMSWDCImpl );
144  m_context = new Graphics( ( HDC ) m_impl->GetHDC( ) );
145 #else
146  m_context = new Graphics( ( HDC ) m_dc->GetHDC( ) );
147 #endif
148  m_current_pen = new Pen( Color( 0, 0, 0 ), 1 );
149  m_current_brush = new SolidBrush( Color( 0, 0, 0 ) );
150 }
151 
152 wxBitmap a2dGDIPlusDrawer::GetSubBitmap( wxRect rect ) const
153 {
154  wxBitmap ret( rect.width, rect.height, m_buffer.GetDepth() );
155  wxASSERT_MSG( ret.Ok(), wxT( "GetSubImage error" ) );
156 
157  wxMemoryDC dcm;
158  dcm.SelectObject( const_cast<wxBitmap&>( m_buffer ) );
159 
160  //do NOT use getsubbitmap, renderDc is already set for the buffer therefore will not work properly
161  wxMemoryDC dcb;
162  dcb.SelectObject( ret );
163  dcb.Blit( 0, 0, rect.width, rect.height, const_cast<wxMemoryDC*>( &dcm ), rect.x, rect.y, wxCOPY, false );
164  dcb.SelectObject( wxNullBitmap );
165 
166  dcm.SelectObject( wxNullBitmap );
167  return ret;
168 }
169 
170 void a2dGDIPlusDrawer::CopyIntoBuffer( const wxBitmap& bitm )
171 {
172  delete m_context;
173 
174  m_dc->SelectObject( wxNullBitmap );
175  m_buffer = bitm;
176  m_dc->SelectObject( m_buffer );
177 #if wxCHECK_VERSION(2, 9, 0)
178  const wxMSWDCImpl* m_impl;
179  m_impl = wxDynamicCast ( m_dc->GetImpl(), wxMSWDCImpl );
180  m_context = new Graphics( ( HDC ) m_impl->GetHDC( ) );
181 #else
182  m_context = new Graphics( ( HDC ) m_dc->GetHDC( ) );
183 #endif
184 }
185 
186 void a2dGDIPlusDrawer::SetTransform( const a2dAffineMatrix& userToWorld )
187 {
188  a2dDrawer2D::SetTransform( userToWorld );
189 
190  Matrix m(
191  m_usertodevice( 0, 0 ), m_usertodevice( 0, 1 ),
192  m_usertodevice( 1, 0 ), m_usertodevice( 1, 1 ),
193  m_usertodevice( 2, 0 ), m_usertodevice( 2, 1 ) );
194  m_context->SetTransform( &m );
195 }
196 
197 void a2dGDIPlusDrawer::PushTransform()
198 {
200 
201  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
202 }
203 
204 void a2dGDIPlusDrawer::PushTransform( const a2dAffineMatrix& affine )
205 {
206  a2dDrawer2D::PushTransform( affine );
207 
208  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
209 }
210 
211 void a2dGDIPlusDrawer::PushIdentityTransform()
212 {
214 
215  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
216 }
217 
218 void a2dGDIPlusDrawer::PopTransform( void )
219 {
221 
222  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
223 }
224 
225 void a2dGDIPlusDrawer::BeginDraw( )
226 {
227  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dGDIPlusDrawer, unbalanced BeginDraw EndDraw" ) );
228 
229  if ( m_display && m_beginDraw_endDraw == 0 )
230  {
231  DestroyClippingRegion();
232 
233  SetDrawStyle( m_drawstyle );
234  SetActiveStroke( m_currentstroke );
235  SetActiveFill( m_currentfill );
236 
237  m_deviceDC = new wxClientDC( m_display );
238  m_display->PrepareDC( *m_deviceDC );
239  }
240 
241  m_beginDraw_endDraw++;
242 }
243 
244 void a2dGDIPlusDrawer::EndDraw( )
245 {
246  m_beginDraw_endDraw--;
247 
248  wxASSERT_MSG( m_beginDraw_endDraw >= 0, wxT( "a2dDcDrawer, unbalanced BeginDraw EndDraw" ) );
249 
250  if ( m_display && m_beginDraw_endDraw == 0 )
251  {
252  delete m_deviceDC;
253  m_deviceDC = NULL;
254  }
255 }
256 
257 void a2dGDIPlusDrawer::SetClippingRegion( a2dVertexList* points, bool spline, wxPolygonFillMode fillStyle )
258 {
259  /*
260  unsigned int n = points->size();
261  m_cpointsDouble.resize(n);
262 
263  unsigned int i = 0;
264  double x,y;
265  forEachIn( a2dVertexList, points )
266  {
267  a2dPoint2D point = (*iter)->GetPoint();
268  //transform to device
269  GetUserToDeviceTransform().TransformPoint( point.m_x, point.m_y, x, y );
270  m_cpointsDouble[i].x = x;
271  m_cpointsDouble[i].y = y;
272  i++;
273  }
274 
275  if ( spline )
276  n = ConvertSplinedPolygon2(n);
277 
278  wxPoint* intCPoints = new wxPoint[n];
279 
280  for ( i = 0; i < n; i++)
281  {
282  intCPoints[i].x = Round(m_cpointsDouble[i].x);
283  intCPoints[i].y = Round(m_cpointsDouble[i].y);
284  }
285 
286  m_clip = wxRegion( n, intCPoints, fillStyle );
287 
288  delete[] intCPoints;
289  */
290  GraphicsPath* path = createGraphicsPath( points, spline );
291  m_context->SetClip( path, CombineModeReplace );
292 }
293 
294 void a2dGDIPlusDrawer::ExtendAndPushClippingRegion( a2dVertexList* points, bool spline, wxPolygonFillMode fillStyle, a2dBooleanClip clipoperation )
295 {
296  Region* push = new Region( );
297  m_context->GetClip( push );
298  m_clipping_region_stack.Insert( push );
299 
300  ExtendClippingRegion( points, spline, fillStyle, clipoperation );
301  return;
302 }
303 
304 void a2dGDIPlusDrawer::ExtendClippingRegion( a2dVertexList* points, bool spline, wxPolygonFillMode fillStyle, a2dBooleanClip clipoperation )
305 {
306  GraphicsPath* path = createGraphicsPath( points, spline, fillStyle );
307 
308  if( !m_context->IsClipEmpty( ) )
309  {
310  switch( clipoperation )
311  {
312  case a2dCLIP_AND:
313  m_context->SetClip( path, CombineModeIntersect );
314  break ;
315 
316  case a2dCLIP_OR:
317  m_context->SetClip( path, CombineModeUnion );
318  break ;
319 
320  case a2dCLIP_XOR:
321  m_context->SetClip( path, CombineModeXor );
322  break ;
323 
324  case a2dCLIP_DIFF:
325  m_context->SetClip( path, CombineModeExclude );
326  break ;
327 
328  case a2dCLIP_COPY:
329  default:
330  m_context->SetClip( path, CombineModeReplace );
331  break ;
332  }
333  }
334  else
335  {
336  m_context->SetClip( path, CombineModeReplace );
337  }
338 }
339 
340 void a2dGDIPlusDrawer::PopClippingRegion( )
341 {
342  wxASSERT( m_clipping_region_stack.GetCount( ) > 0 );
343 
344  Region* region = m_clipping_region_stack.GetFirst()->GetData( );
345  //delete m_clipping_region_stack.GetFirst()->GetData();
346  m_clipping_region_stack.DeleteNode( m_clipping_region_stack.GetLast( ) );
347  m_context->SetClip( region, CombineModeReplace );
348 }
349 
350 void a2dGDIPlusDrawer::SetClippingRegionDev( wxCoord minx, wxCoord miny, wxCoord width, wxCoord height )
351 {
352  m_clip = wxRegion( minx, miny, width, height );
353  m_clipboxdev = wxRect( minx, miny, width, height );
354  m_clipboxworld = ToWorld( m_clipboxdev );
355 
356  //we don't know which part of the transform set in m_context is to go from world to device.
357  //remove all first.
358  PushIdentityTransform();
359  m_context->ResetClip();
360  Rect clip_box( m_clipboxdev.x, m_clipboxdev.y, m_clipboxdev.GetWidth(), m_clipboxdev.GetHeight() );
361  m_context->SetClip( clip_box, CombineModeReplace );
362  PopTransform();
363 }
364 
365 void a2dGDIPlusDrawer::SetClippingRegion( double minx, double miny, double maxx, double maxy )
366 {
367  int iminx = WorldToDeviceX( minx );
368  int iminy = WorldToDeviceY( miny );
369  int imaxx = WorldToDeviceX( maxx );
370  int imaxy = WorldToDeviceY( maxy );
371  if ( m_yaxis )
372  {
373  m_clip = wxRegion( iminx, imaxy, imaxx - iminx, iminy - imaxy );
374  m_clipboxdev = wxRect( iminx, imaxy, imaxx - iminx, iminy - imaxy );
375  }
376  else
377  {
378  m_clip = wxRegion( iminx, iminy, imaxx - iminx, imaxy - iminy );
379  m_clipboxdev = wxRect( iminx, iminy, imaxx - iminx, imaxy - iminy );
380  }
381 
382  m_context->ResetClip();
383  //we don't know which part of the transform set in m_context is to go from world to device.
384  //remove all first.
385  PushIdentityTransform();
386  Rect clip_box( m_clipboxdev.x, m_clipboxdev.y, m_clipboxdev.GetWidth(), m_clipboxdev.GetHeight() );
387  m_context->SetClip( clip_box, CombineModeReplace );
388 
389  PopTransform();
390 }
391 
392 void a2dGDIPlusDrawer::DestroyClippingRegion()
393 {
394  m_context->ResetClip( );
395  m_clipboxdev = wxRect( 0, 0, m_width, m_height );
396  m_clipboxworld = ToWorld( m_clipboxdev );
397 }
398 
399 void a2dGDIPlusDrawer::ResetStyle()
400 {
402  SetDrawerFill( *a2dBLACK_FILL ); //set to a sure state
403  SetDrawerStroke( *a2dBLACK_STROKE );
404  SetDrawStyle( m_drawstyle );
405 }
406 
407 void a2dGDIPlusDrawer::DoSetActiveStroke()
408 {
409  if ( m_activestroke.IsNoStroke() || m_activestroke.GetStyle() == a2dSTROKE_TRANSPARENT )
410  {
411  wxColour color = m_activestroke.GetColour( );
412  m_current_pen = new Pen( Color( m_StrokeOpacityCol1, color.Red( ), color.Green( ), color.Blue( ) ), 1 );
413  }
414  else if ( m_drawstyle == a2dWIREFRAME_INVERT_ZERO_WIDTH )
415  {
416  wxColour color = m_activestroke.GetColour( );
417  m_current_pen = new Pen( Color( m_StrokeOpacityCol1, color.Red( ), color.Green( ), color.Blue( ) ), 1 );
418  }
419  else if ( m_activestroke.GetType() == a2dSTROKE_ONE_COLOUR )
420  {
421  wxColour color = m_activestroke.GetColour( );
422  m_current_pen = new Pen( Color( m_StrokeOpacityCol1, color.Red( ), color.Green( ), color.Blue( ) ) );
423  DashStyle dashStyle = DashStyleSolid;
424  switch( m_activestroke.GetStyle() )
425  {
426  case a2dSTROKE_SOLID:
427  break;
428  case a2dSTROKE_DOT:
429  dashStyle = DashStyleDot;
430  break;
431  case a2dSTROKE_DOT_DASH:
432  dashStyle = DashStyleDashDot;
433  break;
434  case a2dSTROKE_LONG_DASH:
435  dashStyle = DashStyleDash;
436  break;
438  dashStyle = DashStyleDash;
439  break;
441  dashStyle = DashStyleDash;
442  break;
443  case a2dSTROKE_STIPPLE:
445  {
446  wxBitmap bmp = m_activestroke.GetStipple();
447  if ( bmp.Ok() )
448  {
449  m_penImage = Bitmap::FromHBITMAP( ( HBITMAP )bmp.GetHBITMAP(), ( HPALETTE )bmp.GetPalette()->GetHPALETTE() );
450  m_penBrush = new TextureBrush( m_penImage );
451  m_current_pen->SetBrush( m_penBrush );
452  }
453 
454  }
455  default :
456  //if ( m_activestroke.GetStyle() >= wxFIRST_HATCH && m_activestroke.GetStyle() <= wxLAST_HATCH )
457  {
458  HatchStyle style = HatchStyleHorizontal;
459  switch( m_activestroke.GetStyle() )
460  {
462  style = HatchStyleBackwardDiagonal;
463  break;
465  style = HatchStyleDiagonalCross;
466  break;
468  style = HatchStyleForwardDiagonal;
469  break;
471  style = HatchStyleCross;
472  break;
474  style = HatchStyleHorizontal;
475  break;
477  style = HatchStyleVertical;
478  break;
479  }
480  m_penBrush = new HatchBrush( style, Color( m_StrokeOpacityCol1, m_activestroke.GetColour().Red() ,
481  m_activestroke.GetColour().Green() , m_activestroke.GetColour().Blue() ), Color::Transparent );
482  m_current_pen->SetBrush( m_penBrush );
483  }
484  break;
485  }
486  if ( dashStyle != DashStyleSolid )
487  m_current_pen->SetDashStyle( dashStyle );
488 
489 
490  double strokewidth;
491 
492  strokewidth = m_activestroke.GetWidth();
493  if ( m_drawstyle == a2dWIREFRAME_ZERO_WIDTH )
494  {
495  m_current_pen->SetLineJoin( LineJoinRound );
496  m_current_pen->SetLineCap( LineCapRound, LineCapRound, DashCapFlat );
497  m_current_pen->SetWidth( 1 );
498  strokewidth = DeviceToWorldXRel( 1 );
499  }
500  else
501  {
502  LineJoin join;
503  switch( m_activestroke.GetJoin( ) )
504  {
505  case wxJOIN_MITER:
506  join = LineJoinMiter;
507  break;
508  case wxJOIN_ROUND:
509  join = LineJoinRound;
510  break;
511  case wxJOIN_BEVEL:
512  join = LineJoinBevel;
513  break;
514  default:
515  join = LineJoinRound;
516  break;
517  }
518  m_current_pen->SetLineJoin( join );
519 
520  LineCap cap;
521  switch( m_activestroke.GetCap( ) )
522  {
523  case wxCAP_BUTT:
524  cap = LineCapFlat;
525  break;
526  case wxCAP_ROUND:
527  cap = LineCapRound;
528  break;
529  // Stavros: What is projecting? I shall write it as triangle and discuss.
530  case wxCAP_PROJECTING:
531  cap = LineCapSquare;
532  break;
533  default:
534  cap = LineCapFlat;
535  break;
536  }
537  m_current_pen->SetLineCap( cap, cap, DashCapFlat );
538 
539  if ( !m_activestroke.GetPixelStroke() )
540  {
541  strokewidth = WorldToDeviceXRel( m_activestroke.GetWidth() );
542  }
543  //if ( m_activestroke.GetPixelStroke() )
544  // strokewidth = WorldToDeviceXRel( m_activestroke.GetWidth() );
545  }
546 
547  strokewidth = !strokewidth ? 1 : strokewidth;
548  m_current_pen->SetWidth( strokewidth );
549  }
550 }
551 
552 void a2dGDIPlusDrawer::DoSetActiveFill()
553 {
554  wxColour color1 = m_activefill.GetColour();
555  wxColour color2 = m_activefill.GetColour2();
556 
557  if ( !m_activefill.GetFilling() )
558  {
559  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
560  m_current_brush = new SolidBrush( gdicolor1 );
561  return;
562  }
563  else if ( m_activefill.GetStyle() == a2dFILL_TRANSPARENT )
564  {
565  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
566  m_current_brush = new SolidBrush( gdicolor1 );
567  return;
568  }
569  else if ( m_activefill.IsNoFill() )
570  {
571  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
572  m_current_brush = new SolidBrush( gdicolor1 );
573  return;
574  }
575 
576  if ( m_activefill.GetType() == a2dFILL_ONE_COLOUR )
577  {
578  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
579  Color gdicolor2( m_FillOpacityCol2, color2.Red( ), color2.Green( ), color2.Blue( ) );
580 
581  bool nohatch = false;
582  HatchStyle style = HatchStyleHorizontal;
583  switch( m_activefill.GetStyle() )
584  {
585  case a2dFILL_TRANSPARENT:
586  nohatch = true;
587  break;
588  case a2dFILL_SOLID:
589  nohatch = true;
590  break;
592  style = HatchStyleBackwardDiagonal;
593  break;
595  style = HatchStyleDiagonalCross;
596  break;
598  style = HatchStyleForwardDiagonal;
599  break;
600  case a2dFILL_CROSS_HATCH:
601  style = HatchStyleCross;
602  break;
604  style = HatchStyleHorizontal;
605  break;
607  style = HatchStyleVertical;
608  break;
609  default:
610  nohatch = true;
611  break;
612  }
613  if ( nohatch )
614  m_current_brush = new SolidBrush( gdicolor1 );
615  else
616  m_current_brush = new HatchBrush( style, gdicolor1, gdicolor2 );
617  }
618  else if ( m_activefill.GetType() == a2dFILL_HATCH_TWO_COLOUR )
619  {
620  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
621  Color gdicolor2( m_FillOpacityCol2, color2.Red( ), color2.Green( ), color2.Blue( ) );
622 
623  bool nohatch = false;
624  HatchStyle style = HatchStyleHorizontal;
625  switch( m_activefill.GetStyle() )
626  {
628  style = HatchStyleBackwardDiagonal;
629  break;
631  style = HatchStyleDiagonalCross;
632  break;
634  style = HatchStyleForwardDiagonal;
635  break;
637  style = HatchStyleCross;
638  break;
640  style = HatchStyleHorizontal;
641  break;
643  style = HatchStyleVertical;
644  break;
645  default:
646  nohatch = true;
647  break;
648  }
649  if ( nohatch )
650  m_current_brush = new SolidBrush( gdicolor1 );
651  else
652  m_current_brush = new HatchBrush( style, gdicolor1, gdicolor2 );
653  }
654  else if ( m_activefill.GetType() == a2dFILL_BITMAP )
655  {
656  wxBrush dcbrush;
657  //wxBrushStyle style;
658  switch( m_activefill.GetStyle() )
659  {
660  case a2dFILL_STIPPLE:
663  {
664  wxBitmap bmp = m_activefill.GetStipple();
665  if ( bmp.Ok() )
666  {
667  wxDELETE( m_brushImage );
668  m_brushImage = Bitmap::FromHBITMAP( ( HBITMAP )bmp.GetHBITMAP(), ( HPALETTE )bmp.GetPalette()->GetHPALETTE() );
669  m_current_brush = new TextureBrush( m_brushImage );
670  }
671  }
672  break;
673  default:
674  break;
675  }
676  }
677  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR )
678  {
679  a2dPoint2D p1 = m_activefill.GetStart();
680  a2dPoint2D p2 = m_activefill.GetStop();
681  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
682  Color gdicolor2( m_FillOpacityCol2, color2.Red( ), color2.Green( ), color2.Blue( ) );
683  m_current_brush = new LinearGradientBrush( PointF( p1.m_x, p1.m_y ) , PointF( p2.m_x, p2.m_x ), gdicolor1, gdicolor2 );
684  }
685  else if ( m_activefill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
686  {
687  Color gdicolor1( m_FillOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
688  Color gdicolor2( m_FillOpacityCol2, color2.Red( ), color2.Green( ), color2.Blue( ) );
689  double xc = m_activefill.GetCenter().m_x;
690  double yc = m_activefill.GetCenter().m_y;
691  double xo = m_activefill.GetFocal().m_x;
692  double yo = m_activefill.GetFocal().m_y;
693  double radius = m_activefill.GetRadius();
694 
695  // Create a path that consists of a single circle.
696  m_brushPath = new GraphicsPath();
697  m_brushPath->AddEllipse( ( REAL )( xc - radius ), ( REAL )( yc - radius ), ( REAL )( 2 * radius ), ( REAL )( 2 * radius ) );
698 
699  PathGradientBrush* b = new PathGradientBrush( m_brushPath );
700  m_current_brush = b;
701  b->SetCenterPoint( PointF( xo, yo ) );
702  b->SetCenterColor( gdicolor1 );
703 
704  Color colors[] = {gdicolor2};
705  int count = 1;
706  b->SetSurroundColors( colors, &count );
707  }
708 
709 }
710 
711 // Stavros: This is a pure virtual function which just sets the
712 // m_drawstyle member. But why pure virtual?
713 void a2dGDIPlusDrawer::DoSetDrawStyle( a2dDrawStyle drawstyle )
714 {
715  m_drawstyle = drawstyle;
716 }
717 
718 void a2dGDIPlusDrawer::DrawRoundedRectangle( double x, double y, double width, double height, double radius, bool pixelsize )
719 {
720  if ( m_disableDrawing )
721  return;
722 
723  if ( !width || !height )
724  return;
725 
726  if ( pixelsize )
727  {
728  width = DeviceToWorldXRel( width );
729  height = DeviceToWorldYRel( height );
730  radius = DeviceToWorldXRel( radius );
731  if( m_yaxis )
732  height = -height;
733  }
734  if ( width < 0 )
735  {
736  x += width; width = -width;
737  }
738  if ( height < 0 )
739  {
740  y += height;
741  height = -height;
742  }
743 
744  if ( fabs( radius ) <= 0.00000001 )
745  {
746  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
747  m_context->FillRectangle( m_current_brush, ( REAL ) x, ( REAL ) y, ( REAL ) width, ( REAL ) height );
748  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
749  m_context->DrawRectangle( m_current_pen, ( REAL ) x, ( REAL ) y, ( REAL ) width, ( REAL )height );
750  return;
751  }
752 
753  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
754  m_context->FillRectangle( m_current_brush, ( REAL ) x, ( REAL ) y, ( REAL ) width, ( REAL ) height );
755  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
756  m_context->DrawRectangle( m_current_pen, ( REAL ) x, ( REAL ) y, ( REAL ) width, ( REAL ) height );
757 }
758 
759 void a2dGDIPlusDrawer::DrawCircle( double x, double y, double radius )
760 {
761  DrawEllipse( x, y, radius * 2, radius * 2 );
762 }
763 
764 void a2dGDIPlusDrawer::DrawPoint( double xc, double yc )
765 {
766  m_usertodevice.TransformPoint( xc, yc, xc, yc );
767  DeviceDrawPixel( xc, yc, m_colour1redStroke, m_colour1greenStroke, m_colour1blueStroke, m_StrokeOpacityCol1 );
768 }
769 
770 void a2dGDIPlusDrawer::DrawEllipse( double xc, double yc, double width, double height )
771 {
772  if ( m_disableDrawing )
773  return;
774 
775  m_context->SetTransform( _get_gdiplus_user_to_device_transform() );
776  m_context->FillEllipse( m_current_brush, ( REAL ) xc - width / 2, ( REAL ) yc - height / 2, ( REAL ) width, ( REAL ) height );
777 
778  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
779  m_context->DrawEllipse( m_current_pen, ( REAL ) xc - width / 2, ( REAL ) yc - height / 2, ( REAL ) width, ( REAL ) height );
780 }
781 
782 void a2dGDIPlusDrawer::DrawImage( const wxImage& image, double xc, double yc, double width, double height, wxUint8 Opacity )
783 {
784  if ( m_disableDrawing )
785  return;
786 
787 // Bitmap* bitmap = new Bitmap(width, height, width,
788 // PixelFormat24bppRGB, (BYTE*) image.GetData() );
789 
790  bool hasAlpha = image.HasAlpha();
791  size_t w = image.GetWidth();
792  size_t h = image.GetHeight();
793  Bitmap* bitmap = new Bitmap( w, h, PixelFormat32bppPARGB );
794  Rect bounds( 0, 0, w, h );
795  BitmapData data ;
796 
797  bitmap->LockBits( &bounds, ImageLockModeWrite,
798  bitmap->GetPixelFormat(), &data );
799 
800 
801  // Write to the temporary buffer provided by LockBits.
802  UINT* pixels = ( UINT* )data.Scan0;
803 
804  const int srcBytesPerLine = w * 3;
805  const int dstBytesPerLine = w * 4;
806  const unsigned char* src = image.GetData() + ( ( h - 1 ) * srcBytesPerLine );
807  const unsigned char* alpha = hasAlpha ? image.GetAlpha() + ( h - 1 ) * w
808  : NULL;
809  unsigned char* dstLineStart = ( unsigned char* )pixels;
810  for ( int y = 0; y < h; y++ )
811  {
812  // copy one DIB line
813  unsigned char* dst = dstLineStart;
814  if ( alpha )
815  {
816  for ( int x = 0; x < w; x++ )
817  {
818  // RGB order is reversed, and we need to premultiply
819  // all channels by alpha value for use with ::AlphaBlend.
820  const unsigned char a = *alpha++;
821  *dst++ = ( unsigned char )( ( src[2] * a + 127 ) / 255 );
822  *dst++ = ( unsigned char )( ( src[1] * a + 127 ) / 255 );
823  *dst++ = ( unsigned char )( ( src[0] * a + 127 ) / 255 );
824  *dst++ = a;
825  src += 3;
826  }
827  }
828  else // no alpha channel
829  {
830  for ( int x = 0; x < w; x++ )
831  {
832  // RGB order is reversed.
833  *dst++ = ( unsigned char )( ( src[2] * m_OpacityFactor + 127 ) / 255 );
834  *dst++ = ( unsigned char )( ( src[1] * m_OpacityFactor + 127 ) / 255 );
835  *dst++ = ( unsigned char )( ( src[0] * m_OpacityFactor + 127 ) / 255 );
836  *dst++ = m_OpacityFactor;
837  src += 3;
838  }
839  }
840 
841  // pass to the previous line in the image
842  src -= 2 * srcBytesPerLine;
843  if ( alpha )
844  alpha -= 2 * w;
845 
846  // and to the next one in the DIB
847  dstLineStart += dstBytesPerLine;
848  }
849  bitmap->UnlockBits( &data );
850 
851  if ( bitmap )
852  m_context->DrawImage( bitmap, ( REAL ) xc - width / 2.0, ( REAL ) yc - height / 2.0, ( REAL ) width, ( REAL ) height ) ;
853  delete bitmap;
854 }
855 
856 void a2dGDIPlusDrawer::DrawImage( const a2dImageRGBA& image, double x, double y, double width, double height, wxUint8 Opacity )
857 {
858  if ( m_disableDrawing )
859  return;
860 
861  //m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
862 }
863 
864 #include "Gdipluspixelformats.h"
865 
866 void a2dGDIPlusDrawer::DeviceDrawPolygon( unsigned int n, bool spline, wxPolygonFillMode fillStyle )
867 {
868  if ( spline )
869  n = ConvertSplinedPolygon2( n );
870 
871  Matrix ident;
872  m_context->SetTransform( &ident );
873 
874  //just 2 points in wxINVERT mode makes it invisible
875  if ( m_drawstyle == a2dWIREFRAME_INVERT || n == 2 )
876  {
877  GraphicsPath path;
878  unsigned int i;
879  for ( i = 0; i < n; i++ )
880  {
881  if ( i == 0 )
882  path.StartFigure();
883  else
884  path.AddLine( ( REAL ) m_cpointsDouble[i - 1].x, ( REAL ) m_cpointsDouble[i - 1].y, ( REAL ) m_cpointsDouble[i].x, ( REAL ) m_cpointsDouble[i].y );
885  }
886  path.CloseFigure();
887  m_context->DrawPath( m_current_pen, &path );
888  }
889  else if ( m_currentfill.GetType() == a2dFILL_GRADIENT_FILL_LINEAR || m_currentfill.GetType() == a2dFILL_GRADIENT_FILL_RADIAL )
890  {
891  GraphicsPath path;
892  unsigned int i;
893  for ( i = 0; i < n; i++ )
894  {
895  if ( i == 0 )
896  path.StartFigure();
897  else
898  path.AddLine( ( REAL ) m_cpointsDouble[i - 1].x, ( REAL ) m_cpointsDouble[i - 1].y, ( REAL ) m_cpointsDouble[i].x, ( REAL ) m_cpointsDouble[i].y );
899  }
900  path.CloseFigure();
901  m_context->FillPath( m_current_brush, &path );
902 
903  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
904  m_context->DrawPath( m_current_pen, &path );
905  }
906  else if ( m_currentfill.GetType() == a2dFILL_BITMAP )
907  {
908  GraphicsPath path;
909  unsigned int i;
910  for ( i = 0; i < n; i++ )
911  {
912  if ( i == 0 )
913  path.StartFigure();
914  else
915  path.AddLine( ( REAL ) m_cpointsDouble[i - 1].x, ( REAL ) m_cpointsDouble[i - 1].y, ( REAL ) m_cpointsDouble[i].x, ( REAL ) m_cpointsDouble[i].y );
916  }
917  path.CloseFigure();
918  m_context->FillPath( m_current_brush, &path );
919 
920  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
921  m_context->DrawPath( m_current_pen, &path );
922  }
923  else
924  {
925  GraphicsPath path;
926  unsigned int i;
927  for ( i = 0; i < n; i++ )
928  {
929  if ( i == 0 )
930  path.StartFigure();
931  else
932  path.AddLine( ( REAL ) m_cpointsDouble[i - 1].x, ( REAL ) m_cpointsDouble[i - 1].y, ( REAL ) m_cpointsDouble[i].x, ( REAL ) m_cpointsDouble[i].y );
933  }
934  path.CloseFigure();
935  m_context->FillPath( m_current_brush, &path );
936 
937  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
938  m_context->DrawPath( m_current_pen, &path );
939  }
940 
941  if ( !m_currentstroke.IsSameAs( *a2dTRANSPARENT_STROKE ) && m_currentstroke.GetType() == a2dSTROKE_OBJECT )
942  {
943  //we must make a copy of the device points now because recursive call
944  //can be made in here, which will change the points stored in de drawer.
945  //First point repeated extra since it is for outline
946  wxRealPoint* copy = new wxRealPoint[n + 1];
947  memcpy( copy, &m_cpointsDouble[0], n * sizeof( wxRealPoint ) );
948  copy[n].x = m_cpointsDouble[0].x;
949  copy[n].y = m_cpointsDouble[0].y;
950 
951  //m_currentstroke.Render( this, m_clipboxworld, n+1, copy );
952  delete [] copy;
953  }
954 
955 }
956 
957 void a2dGDIPlusDrawer::DeviceDrawLines( unsigned int n, bool spline )
958 {
959  if ( spline )
960  n = ConvertSplinedPolyline2( n );
961 
962  Matrix ident;
963  m_context->SetTransform( &ident );
964 
965  GraphicsPath path;
966  unsigned int i;
967  for ( i = 0; i < n; i++ )
968  {
969  if ( i == 0 )
970  path.StartFigure();
971  else
972  path.AddLine( ( REAL ) m_cpointsDouble[i - 1].x, ( REAL ) m_cpointsDouble[i - 1].y, ( REAL ) m_cpointsDouble[i].x, ( REAL ) m_cpointsDouble[i].y );
973  }
974  m_context->DrawPath( m_current_pen, &path );
975 }
976 
977 void a2dGDIPlusDrawer::DeviceDrawLine( double x1, double y1, double x2, double y2 )
978 {
979  Matrix ident;
980  m_context->SetTransform( &ident );
981  if ( !m_currentstroke.IsNoStroke() && !m_currentstroke.GetStyle() == a2dSTROKE_TRANSPARENT )
982  m_context->DrawLine( m_current_pen, ( REAL ) x1, ( REAL ) y1, ( REAL ) x2, ( REAL ) y2 );
983 }
984 
985 void a2dGDIPlusDrawer::DeviceDrawHorizontalLine( int x1, int y1, int x2, bool use_stroke_color )
986 {
987  if ( x1 > x2 )
988  {
989  int tmp = x1;
990  x1 = x2;
991  x2 = tmp;
992  }
993 
994  // clip to clipping region
995  if ( x2 < m_clipboxdev.x )
996  return;
997 
998  if ( x1 >= m_clipboxdev.x + m_clipboxdev.width )
999  return;
1000 
1001  if ( x1 < m_clipboxdev.x ) x1 = m_clipboxdev.x;
1002  if ( x2 >= m_clipboxdev.x + m_clipboxdev.width ) x2 = m_clipboxdev.x + m_clipboxdev.width - 1;
1003  if ( y1 >= m_clipboxdev.y && y1 < m_clipboxdev.y + m_clipboxdev.height )
1004  {
1005  //if (!use_stroke_color)
1006  Matrix ident;
1007  m_context->SetTransform( &ident );
1008  m_context->DrawLine( m_current_pen, ( REAL ) x1, ( REAL ) y1, ( REAL ) x2, ( REAL ) y1 );
1009  }
1010 }
1011 
1012 void a2dGDIPlusDrawer::DeviceDrawVerticalLine( int x1, int y1, int y2, bool use_stroke_color )
1013 {
1014  if ( y1 > y2 )
1015  {
1016  int tmp = y1;
1017  y1 = y2;
1018  y2 = tmp;
1019  }
1020 
1021  // clip to clipping region
1022  if ( y2 < m_clipboxdev.y )
1023  return;
1024 
1025  if ( y1 >= m_clipboxdev.y + m_clipboxdev.height )
1026  return;
1027 
1028  if ( y1 < m_clipboxdev.y ) y1 = m_clipboxdev.y;
1029  if ( y2 >= m_clipboxdev.y + m_clipboxdev.height ) y2 = m_clipboxdev.y + m_clipboxdev.height - 1;
1030  if ( x1 >= m_clipboxdev.x && x1 < m_clipboxdev.x + m_clipboxdev.width )
1031  {
1032  }
1033 }
1034 
1035 void a2dGDIPlusDrawer::DeviceDrawPixel( int x1, int y1, unsigned char r, unsigned char g, unsigned char b, unsigned char a )
1036 {
1037  Matrix ident;
1038  m_context->SetTransform( &ident );
1039  Pen tmp( Color( a, r, g, b ), 1 );
1040  m_context->DrawLine( &tmp, x1, y1, x1, y1 );
1041 }
1042 
1043 // protected functions that only a2dGDIPlusDrawer may use.
1044 GraphicsPath* a2dGDIPlusDrawer::createGraphicsPath( a2dVertexList* list, bool spline, wxPolygonFillMode fillStyle )
1045 {
1046  unsigned int n = list->size();
1047  unsigned int i = 0;
1048 
1049  GraphicsPath ret;
1050 
1051  switch( fillStyle )
1052  {
1053  case wxODDEVEN_RULE:
1054  ret.SetFillMode( FillModeAlternate );
1055  break;
1056  default:
1057  ret.SetFillMode( FillModeWinding );
1058  break;
1059  }
1060 
1061 #ifdef wxUSE_INTPOINT
1062  Point* points = new Point[ n ];
1063 #else
1064  PointF* points = new PointF[ n ];
1065 #endif
1066 
1067  forEachIn( a2dVertexList, list )
1068  {
1069  a2dPoint2D point = ( *iter )->GetPoint();
1070 #ifdef wxUSE_INTPOINT
1071  points[ i ] = Point( point.m_x, point.m_y );
1072 #else
1073  points[ i ] = PointF( point.m_x, point.m_y );
1074 #endif
1075  i++;
1076  }
1077 
1078  if( spline == true )
1079  ret.AddCurve( points, n );
1080  else
1081  ret.AddLines( points, n );
1082 
1083  delete [ ] points;
1084  return ret.Clone( );
1085 }
1086 
1087 void a2dGDIPlusDrawer::BlitBuffer( wxDC* dc, wxRect rect, const wxPoint& bufferpos )
1088 {
1089  if ( rect.x + rect.width > m_buffer.GetWidth() )
1090  rect.width = m_buffer.GetWidth() - rect.x;
1091  if ( rect.y + rect.height > m_buffer.GetHeight() )
1092  rect.height = m_buffer.GetHeight() - rect.y;
1093 
1094  if ( ( rect.width > 0 ) && ( rect.height > 0 ) )
1095  {
1096  dc->Blit( rect.x - bufferpos.x, rect.y - bufferpos.y, rect.width, rect.height, m_dc, rect.x, rect.y, wxCOPY, false );
1097  }
1098 }
1099 
1100 void a2dGDIPlusDrawer::BlitBuffer( wxRect rect, const wxPoint& bufferpos )
1101 {
1102  BeginDraw();
1103  BlitBuffer( m_deviceDC, rect, bufferpos );
1104  EndDraw();
1105 }
1106 
1107 void a2dGDIPlusDrawer::ShiftBuffer( int dxy, bool yshift )
1108 {
1109  int bw = GetBuffer().GetWidth();
1110  int bh = GetBuffer().GetHeight();
1111  if ( yshift )
1112  {
1113  if ( dxy > 0 && dxy < bh )
1114  {
1115  wxRect rect( 0, 0, bw, bh - dxy );
1116  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
1117  wxMemoryDC dcm;
1118  dcm.SelectObject( m_buffer );
1119  dcm.DrawBitmap( sub_bitmap, 0, dxy, true );
1120  dcm.SelectObject( wxNullBitmap );
1121  }
1122  else if ( dxy < 0 && dxy > -bh )
1123  {
1124  wxRect rect( 0, -dxy, bw, bh + dxy );
1125  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
1126  wxMemoryDC dcm;
1127  dcm.SelectObject( m_buffer );
1128  dcm.DrawBitmap( sub_bitmap, 0, 0, true );
1129  dcm.SelectObject( wxNullBitmap );
1130  }
1131  else
1132  wxFAIL_MSG( wxT( "you can only shift within height of buffer" ) );
1133 
1134  }
1135  else
1136  {
1137  if ( dxy > 0 && dxy < bw )
1138  {
1139  wxRect rect( 0, 0, bw - dxy, bh );
1140  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
1141  wxMemoryDC dcm;
1142  dcm.SelectObject( m_buffer );
1143  dcm.DrawBitmap( sub_bitmap, dxy, 0, true );
1144  dcm.SelectObject( wxNullBitmap );
1145  }
1146  else if ( dxy < 0 && dxy > -bw )
1147  {
1148  wxRect rect( -dxy, 0, bw + dxy, bh );
1149  wxBitmap sub_bitmap( m_buffer.GetSubBitmap( rect ) );
1150  wxMemoryDC dcm;
1151  dcm.SelectObject( m_buffer );
1152  dcm.DrawBitmap( sub_bitmap, 0, 0, true );
1153  dcm.SelectObject( wxNullBitmap );
1154  }
1155  else
1156  wxFAIL_MSG( wxT( "you can only shift within width of buffer" ) );
1157  }
1158 }
1159 
1160 void a2dGDIPlusDrawer::DrawCharStroke( wxChar c )
1161 {
1163  return;
1164 
1165 //TODO pen becomes far to big, effected by transform? Using above it is draw with no transform.
1166 
1167  // set text linestroke.
1168  a2dStroke stroke = a2dStroke( m_activestroke.GetColour(), m_currentfont.GetStrokeWidth() );
1169  a2dStroke oldstroke = m_activestroke;
1170  SetActiveStroke( stroke );
1171 
1172  // scale character to size
1173  a2dAffineMatrix affine;
1174  affine.Scale( m_currentfont.GetSize() );
1175  PushTransform( affine );
1176 
1177  GraphicsPath path;
1178  a2dVertexList** ptr = m_currentfont.GetGlyphStroke( c );
1179  if ( ptr )
1180  {
1181  while ( *ptr )
1182  {
1183  a2dVertexList::iterator iter = ( *ptr )->begin();
1184  if ( ( *ptr )->size() )
1185  {
1186  path.StartFigure();
1187  }
1188  while ( iter != ( *ptr )->end() )
1189  {
1190  a2dPoint2D point = ( *iter )->GetPoint();
1191  path.AddLine( ( REAL ) point.m_x, ( REAL ) point.m_y, ( REAL ) point.m_x, ( REAL ) point.m_y );
1192  iter++;
1193  }
1194  ptr++;
1195  }
1196  }
1197 
1198  m_context->DrawPath( m_current_pen, &path );
1199 
1200  // restore context
1201  PopTransform();
1202  SetActiveStroke( oldstroke );
1203 }
1204 
1205 
1206 void a2dGDIPlusDrawer::DrawCharFreetype( wxChar c )
1207 {
1208  double x, y;
1209  x = y = 0.0;
1210 
1211  if ( m_disableDrawing )
1212  return;
1213 
1214  double scale = m_currentfont.GetSize() / ( 64 * m_currentfont.GetDeviceHeight() );
1215 
1216 #if wxART2D_USE_FREETYPE
1217  y += m_currentfont.GetDescent();
1218 
1219  FT_Glyph glyph = m_currentfont.GetGlyphFreetype( c )->m_glyph;
1220  if ( glyph->format != FT_GLYPH_FORMAT_OUTLINE )
1221  return;
1222  FT_Outline& outline = ( ( FT_OutlineGlyph ) glyph )->outline;
1223 
1224  FT_Vector v_last;
1225  FT_Vector v_control;
1226  FT_Vector v_start;
1227 
1228  FT_Vector* point;
1229  FT_Vector* limit;
1230  char* tags;
1231 
1232  int n; // index of contour in outline
1233  int first; // index of first point in contour
1234  char tag; // current point's state
1235 
1236  first = 0;
1237 
1238  GraphicsPath path;
1239  a2dPoint2D pointprev;
1240  for( n = 0; n < outline.n_contours; n++ )
1241  {
1242  int last; // index of last point in contour
1243 
1244  last = outline.contours[n];
1245  limit = outline.points + last;
1246 
1247  v_start = outline.points[first];
1248  v_last = outline.points[last];
1249 
1250  v_control = v_start;
1251 
1252  point = outline.points + first;
1253  tags = outline.tags + first;
1254  tag = FT_CURVE_TAG( tags[0] );
1255 
1256  // A contour cannot start with a cubic control point!
1257  if( tag == FT_CURVE_TAG_CUBIC ) return;
1258 
1259  // check first point to determine origin
1260  if( tag == FT_CURVE_TAG_CONIC )
1261  {
1262  // first point is conic control. Yes, this happens.
1263  if( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
1264  {
1265  // start at last point if it is on the curve
1266  v_start = v_last;
1267  limit--;
1268  }
1269  else
1270  {
1271  // if both first and last points are conic,
1272  // start at their middle and record its position
1273  // for closure
1274  v_start.x = ( v_start.x + v_last.x ) / 2;
1275  v_start.y = ( v_start.y + v_last.y ) / 2;
1276 
1277  v_last = v_start;
1278  }
1279  point--;
1280  tags--;
1281  }
1282 
1283  path.StartFigure();
1284  pointprev = a2dPoint2D( v_start.x, v_start.y );
1285  path.AddLine( ( REAL ) v_start.x, ( REAL ) v_start.y, ( REAL ) v_start.x, ( REAL ) v_start.y );
1286 
1287  while( point < limit )
1288  {
1289  point++;
1290  tags++;
1291 
1292  tag = FT_CURVE_TAG( tags[0] );
1293  switch( tag )
1294  {
1295  case FT_CURVE_TAG_ON: // emit a single line_to
1296  {
1297  path.AddLine( ( REAL ) point->x, ( REAL ) point->y, ( REAL ) point->x, ( REAL ) point->y );
1298  continue;
1299  }
1300 
1301  case FT_CURVE_TAG_CONIC: // consume conic arcs
1302  {
1303  v_control.x = point->x;
1304  v_control.y = point->y;
1305 
1306 Do_Conic:
1307  if( point < limit )
1308  {
1309  FT_Vector vec;
1310  FT_Vector v_middle;
1311 
1312  point++;
1313  tags++;
1314  tag = FT_CURVE_TAG( tags[0] );
1315 
1316  vec.x = point->x;
1317  vec.y = point->y;
1318 
1319  if( tag == FT_CURVE_TAG_ON )
1320  {
1321  PointF c1( v_control.x, v_control.y );
1322  PointF c2( v_control.x, v_control.y );
1323  PointF end( vec.x, vec.y );
1324  PointF start;
1325  path.GetLastPoint( &start );
1326  path.AddBezier( start, c1, c2, end );
1327  continue;
1328  }
1329 
1330  if( tag != FT_CURVE_TAG_CONIC ) return;
1331 
1332  v_middle.x = ( v_control.x + vec.x ) / 2;
1333  v_middle.y = ( v_control.y + vec.y ) / 2;
1334 
1335  PointF c1( v_control.x, v_control.y );
1336  PointF c2( v_control.x, v_control.y );
1337  PointF end( v_middle.x, v_middle.y );
1338  PointF start;
1339  path.GetLastPoint( &start );
1340  path.AddBezier( start, c1, c2, end );
1341 
1342  v_control = vec;
1343  goto Do_Conic;
1344  }
1345  PointF c1( v_control.x, v_control.y );
1346  PointF c2( v_control.x, v_control.y );
1347  PointF end( v_start.x, v_start.y );
1348  PointF start;
1349  path.GetLastPoint( &start );
1350  path.AddBezier( start, c1, c2, end );
1351  goto Close;
1352  }
1353 
1354  default: // FT_CURVE_TAG_CUBIC
1355  {
1356  FT_Vector vec1, vec2;
1357 
1358  if( point + 1 > limit || FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
1359  {
1360  return;
1361  }
1362 
1363  vec1.x = point[0].x;
1364  vec1.y = point[0].y;
1365  vec2.x = point[1].x;
1366  vec2.y = point[1].y;
1367 
1368  point += 2;
1369  tags += 2;
1370 
1371  if( point <= limit )
1372  {
1373  FT_Vector vec;
1374 
1375  vec.x = point->x;
1376  vec.y = point->y;
1377 
1378  PointF c1( vec1.x, vec1.y );
1379  PointF c2( vec2.x, vec2.y );
1380  PointF end( vec.x, vec.y );
1381  PointF start;
1382  path.GetLastPoint( &start );
1383  path.AddBezier( start, c1, c2, end );
1384 
1385  continue;
1386  }
1387 
1388  PointF c1( vec1.x, vec1.y );
1389  PointF c2( vec2.x, vec2.y );
1390  PointF end( v_start.x, v_start.y );
1391  PointF start;
1392  path.GetLastPoint( &start );
1393  path.AddBezier( start, c1, c2, end );
1394 
1395  goto Close;
1396  }
1397  }
1398  }
1399 
1400  path.CloseFigure();
1401 
1402 Close:
1403  first = last + 1;
1404  }
1405 
1406  // scale font to size
1407  a2dAffineMatrix affine;
1408  affine.Scale( scale );
1409  affine.Translate( x, y );
1410  affine = GetUserToDeviceTransform() * affine;
1411 
1412  Matrix charTransform(
1413  ( REAL )affine( 0, 0 ), ( REAL )affine( 0, 1 ),
1414  ( REAL )affine( 1, 0 ), ( REAL )affine( 1, 1 ),
1415  ( REAL )affine( 2, 0 ), ( REAL )affine( 2, 1 ) );
1416 
1417  m_context->SetTransform( &charTransform );
1418 
1419  wxColour color1 = m_currentstroke.GetColour();
1420  Color gdicolor1( m_StrokeOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
1421  SolidBrush* text_brush = new SolidBrush( gdicolor1 );
1422  m_context->FillPath( text_brush, &path );
1423 #else // wxART2D_USE_FREETYPE
1425 #endif // wxART2D_USE_FREETYPE
1426 }
1427 
1428 void a2dGDIPlusDrawer::DrawCharDc( wxChar c )
1429 {
1430 #if wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
1431  if ( m_currentfont.GetType() == a2dFONT_WXDC && m_currentfont.GetFreetypeFont().Ok() )
1432  {
1433  a2dFont oldfont = m_currentfont;
1434  m_currentfont = m_currentfont.GetFreetypeFont();
1435  DrawCharFreetype( c );
1436  m_currentfont = oldfont;
1437  }
1438  else
1440 #else // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
1442 #endif // wxART2D_USE_FREETYPE && defined(__USE_WINAPI__)
1443 }
1444 
1445 void a2dGDIPlusDrawer::DrawTextDc( const wxString& text, double x, double y )
1446 {
1447  a2dDrawer2D::DrawTextDc( text, x, y );
1448  return;
1449  /*
1450  wxFont* wxdcfont = m_currentfont.GetFont();
1451 
1452  wxWCharBuffer s = wxdcfont->GetFaceName().wc_str( *wxConvUI );
1453  int size = wxdcfont->GetPointSize();
1454  int style = FontStyleRegular;
1455  if ( wxdcfont->GetStyle() == wxFONTSTYLE_ITALIC )
1456  style |= FontStyleItalic;
1457  if ( wxdcfont->GetUnderlined() )
1458  style |= FontStyleUnderline;
1459  if ( wxdcfont->GetWeight() == wxFONTWEIGHT_BOLD )
1460  style |= FontStyleBold;
1461  Font* gdifont = new Font( s , size , style );
1462 
1463  wxColour color1 = m_currentstroke.GetColour();
1464  Color gdicolor1( m_StrokeOpacityCol1, color1.Red( ), color1.Green( ), color1.Blue( ) );
1465  SolidBrush* text_brush = new SolidBrush( gdicolor1 );
1466 
1467  wxWCharBuffer convtext = text.wc_str( *wxConvUI );
1468  m_context->DrawString( convtext, -1 , gdifont, PointF( x , y ) , StringFormat::GenericTypographic() , text_brush );
1469  */
1470 }
1471 
1472 #endif // wxART2D_USE_GDIPLUS_DRAWER
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
#define wxDynamicCast(obj, className)
Define wxDynamicCast so that it will give a compiler error for unrelated types.
Definition: gen.h:75
Base class for all types of strokes, understood by a2dDrawer2D classes.
Definition: stylebase.h:378
virtual void SetTransform(const a2dAffineMatrix &userToWorld)
set user-to-world transform matrix.
Definition: drawer2d.cpp:446
const a2dStroke * a2dBLACK_STROKE
global a2dStroke stock object for BLACK stroking
Stroke and fill base classes.
virtual void PopTransform(void)
Recall the previously saved user-to-world transform off the matrix stack.
Definition: drawer2d.cpp:480
const a2dFill * a2dBLACK_FILL
global a2dFill stock object for BLACK filling
Defines a font to be set to a2dDrawer2D or stored in a2dCanvsObject etc.
Definition: stylebase.h:779
vertex list of line and arc segments.
Definition: polyver.h:600
virtual void DrawCharStroke(wxChar c)
Draw a stroke character.
Definition: drawer2d.cpp:2270
a2dDrawStyle
Define the manner in which a2dCanvasView draws to the device.
Definition: artglob.h:280
virtual void PushTransform()
Save the current user-to-world transform on the affine stack.
Definition: drawer2d.cpp:452
virtual void ResetStyle()
set a pre-defined style reseting cashed values.
Definition: drawer2d.cpp:545
#define forEachIn(listtype, list)
easy iteration for a2dlist
Definition: a2dlist.h:111
virtual void DrawCharDc(wxChar c)
Draw a dc character.
Definition: drawer2d.h:981
Drawing context abstraction.
Definition: drawer2d.h:177
virtual void DrawTextDc(const wxString &text, double x, double y)
Draw text in user coordinates, based on a dc font .
Definition: drawer2d.h:987
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
a2dBooleanClip
Used for defining how a ClippingRegion defined as a polygon is combined with.
Definition: drawer2d.h:54
virtual void DrawCharFreetype(wxChar c)
Draw a freetype character.
Definition: drawer2d.h:966
bool Scale(double scale)
Scale by scale (isotropic scaling i.e. the same in x and y):
Definition: afmatrix.cpp:270
bool Translate(double x, double y)
Translate by dx, dy:
Definition: afmatrix.cpp:420
const a2dStroke * a2dTRANSPARENT_STROKE
global a2dStroke stock object for TRANSPARENT stroking
virtual void PushIdentityTransform()
push no transform, to draw directly in device coordinates
Definition: drawer2d.cpp:469
gdiplusdrawer.cpp Source File -- Sun Oct 12 2014 17:04:20 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation