KiCad PCB EDA Suite
cairo_gal.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KICAD, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright (C) 2012-2021 Kicad Developers, see AUTHORS.txt for contributors.
6  * Copyright (C) 2017-2018 CERN
7  *
8  * @author Maciej Suminski <[email protected]>
9  *
10  * CairoGal - Graphics Abstraction Layer for Cairo
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 #include <wx/image.h>
31 #include <wx/log.h>
32 
33 #include <gal/cairo/cairo_gal.h>
35 #include <gal/definitions.h>
37 #include <math/util.h> // for KiROUND
38 #include <bitmap_base.h>
39 
40 #include <algorithm>
41 #include <cmath>
42 #include <limits>
43 
44 #include <pixman.h>
45 
46 using namespace KIGFX;
47 
48 
49 CAIRO_GAL_BASE::CAIRO_GAL_BASE( GAL_DISPLAY_OPTIONS& aDisplayOptions ) : GAL( aDisplayOptions )
50 {
51  // Initialise grouping
52  m_isGrouping = false;
53  m_isElementAdded = false;
54  m_groupCounter = 0;
55  m_currentGroup = nullptr;
56 
57  m_lineWidth = 1.0;
58  m_lineWidthInPixels = 1.0;
59  m_lineWidthIsOdd = true;
60 
61  // Initialise Cairo state
62  cairo_matrix_init_identity( &m_cairoWorldScreenMatrix );
63  m_currentContext = nullptr;
64  m_context = nullptr;
65  m_surface = nullptr;
66 
67  // Grid color settings are different in Cairo and OpenGL
68  SetGridColor( COLOR4D( 0.1, 0.1, 0.1, 0.8 ) );
70 
71  // Avoid uninitialized variables:
72  cairo_matrix_init_identity( &m_currentXform );
73  cairo_matrix_init_identity( &m_currentWorld2Screen );
74 }
75 
76 
78 {
79  ClearCache();
80 
81  if( m_surface )
82  cairo_surface_destroy( m_surface );
83 
84  if( m_context )
85  cairo_destroy( m_context );
86 
87  for( _cairo_surface* imageSurface : m_imageSurfaces )
88  cairo_surface_destroy( imageSurface );
89 }
90 
91 
93 {
94  resetContext();
95 }
96 
97 
99 {
100  // Force remaining objects to be drawn
101  Flush();
102 }
103 
104 
106 {
107  cairo_matrix_multiply( &m_currentWorld2Screen, &m_currentXform, &m_cairoWorldScreenMatrix );
108 }
109 
110 
111 const VECTOR2D CAIRO_GAL_BASE::xform( double x, double y )
112 {
113  VECTOR2D rv;
114 
117  return rv;
118 }
119 
120 
122 {
123  return xform( aP.x, aP.y );
124 }
125 
126 
127 const double CAIRO_GAL_BASE::angle_xform( const double aAngle )
128 {
129  // calculate rotation angle due to the rotation transform
130  // and if flipped on X axis.
131  double world_rotation = -std::atan2( m_currentWorld2Screen.xy, m_currentWorld2Screen.xx );
132 
133  // When flipped on X axis, the rotation angle is M_PI - initial angle:
134  if( IsFlippedX() )
135  world_rotation = M_PI - world_rotation;
136 
137  return std::fmod( aAngle + world_rotation, 2.0 * M_PI );
138 }
139 
140 
141 void CAIRO_GAL_BASE::arc_angles_xform_and_normalize( double& aStartAngle, double& aEndAngle )
142 {
143  // 360 deg arcs have a specific calculation.
144  bool is_360deg_arc = std::abs( aEndAngle - aStartAngle ) >= 2 * M_PI;
145  double startAngle = aStartAngle;
146  double endAngle = aEndAngle;
147 
148  // When the view is flipped, the coordinates are flipped by the matrix transform
149  // However, arc angles need to be "flipped": the flipped angle is M_PI - initial angle.
150  if( IsFlippedX() )
151  {
152  startAngle = M_PI - startAngle;
153  endAngle = M_PI - endAngle;
154  }
155 
156  // Normalize arc angles
157  SWAP( startAngle, >, endAngle );
158 
159  // now rotate arc according to the rotation transform matrix
160  // Remark:
161  // We call angle_xform() to calculate angles according to the flip/rotation
162  // transform and normalize between -2M_PI and +2M_PI.
163  // Therefore, if aStartAngle = aEndAngle + 2*n*M_PI, the transform gives
164  // aEndAngle = aStartAngle
165  // So, if this is the case, force the aEndAngle value to draw a circle.
166  aStartAngle = angle_xform( startAngle );
167 
168  if( is_360deg_arc ) // arc is a full circle
169  aEndAngle = aStartAngle + 2 * M_PI;
170  else
171  aEndAngle = angle_xform( endAngle );
172 }
173 
174 
175 const double CAIRO_GAL_BASE::xform( double x )
176 {
177  double dx = m_currentWorld2Screen.xx * x;
178  double dy = m_currentWorld2Screen.yx * x;
179  return sqrt( dx * dx + dy * dy );
180 }
181 
182 
183 static double roundp( double x )
184 {
185  return floor( x + 0.5 ) + 0.5;
186 }
187 
188 
190 {
192  return VECTOR2D( ::roundp( v.x ), ::roundp( v.y ) );
193  else
194  return VECTOR2D( floor( v.x + 0.5 ), floor( v.y + 0.5 ) );
195 }
196 
197 
198 void CAIRO_GAL_BASE::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
199 {
200  syncLineWidth();
201 
202  VECTOR2D p0 = roundp( xform( aStartPoint ) );
203  VECTOR2D p1 = roundp( xform( aEndPoint ) );
204 
205  cairo_move_to( m_currentContext, p0.x, p0.y );
206  cairo_line_to( m_currentContext, p1.x, p1.y );
207  flushPath();
208  m_isElementAdded = true;
209 }
210 
211 
212 void CAIRO_GAL_BASE::syncLineWidth( bool aForceWidth, double aWidth )
213 {
214  double w = floor( xform( aForceWidth ? aWidth : m_lineWidth ) + 0.5 );
215 
216  if( w <= 1.0 )
217  {
218  w = 1.0;
219  cairo_set_line_join( m_currentContext, CAIRO_LINE_JOIN_MITER );
220  cairo_set_line_cap( m_currentContext, CAIRO_LINE_CAP_BUTT );
221  cairo_set_line_width( m_currentContext, 1.0 );
222  m_lineWidthIsOdd = true;
223  }
224  else
225  {
226  cairo_set_line_join( m_currentContext, CAIRO_LINE_JOIN_ROUND );
227  cairo_set_line_cap( m_currentContext, CAIRO_LINE_CAP_ROUND );
228  cairo_set_line_width( m_currentContext, w );
229  m_lineWidthIsOdd = ( (int) w % 2 ) == 1;
230  }
231 
233 }
234 
235 
236 void CAIRO_GAL_BASE::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
237  double aWidth )
238 {
239  if( m_isFillEnabled )
240  {
241  syncLineWidth( true, aWidth );
242 
243  VECTOR2D p0 = roundp( xform( aStartPoint ) );
244  VECTOR2D p1 = roundp( xform( aEndPoint ) );
245 
246  cairo_move_to( m_currentContext, p0.x, p0.y );
247  cairo_line_to( m_currentContext, p1.x, p1.y );
248  cairo_set_source_rgba( m_currentContext, m_fillColor.r, m_fillColor.g, m_fillColor.b,
249  m_fillColor.a );
250  cairo_stroke( m_currentContext );
251  }
252  else
253  {
254  aWidth /= 2.0;
255  SetLineWidth( 1.0 );
256  syncLineWidth();
257 
258  // Outline mode for tracks
259  VECTOR2D startEndVector = aEndPoint - aStartPoint;
260  double lineAngle = atan2( startEndVector.y, startEndVector.x );
261 
262  double sa = sin( lineAngle + M_PI / 2.0 );
263  double ca = cos( lineAngle + M_PI / 2.0 );
264 
265  VECTOR2D pa0 = xform( aStartPoint + VECTOR2D( aWidth * ca, aWidth * sa ) );
266  VECTOR2D pa1 = xform( aStartPoint - VECTOR2D( aWidth * ca, aWidth * sa ) );
267  VECTOR2D pb0 = xform( aEndPoint + VECTOR2D( aWidth * ca, aWidth * sa ) );
268  VECTOR2D pb1 = xform( aEndPoint - VECTOR2D( aWidth * ca, aWidth * sa ) );
269 
270  cairo_set_source_rgba( m_currentContext, m_strokeColor.r, m_strokeColor.g, m_strokeColor.b,
271  m_strokeColor.a );
272 
273  cairo_move_to( m_currentContext, pa0.x, pa0.y );
274  cairo_line_to( m_currentContext, pb0.x, pb0.y );
275 
276  cairo_move_to( m_currentContext, pa1.x, pa1.y );
277  cairo_line_to( m_currentContext, pb1.x, pb1.y );
278  flushPath();
279 
280  // Calculate the segment angle and arc center in normal/mirrored transform for rounded ends.
281  VECTOR2D center_a = xform( aStartPoint );
282  VECTOR2D center_b = xform( aEndPoint );
283  startEndVector = center_b - center_a;
284  lineAngle = atan2( startEndVector.y, startEndVector.x );
285  double radius = ( pa0 - center_a ).EuclideanNorm();
286 
287  // Draw the rounded end point of the segment
288  double arcStartAngle = lineAngle - M_PI / 2.0;
289  cairo_arc( m_currentContext, center_b.x, center_b.y, radius, arcStartAngle, arcStartAngle + M_PI );
290 
291  // Draw the rounded start point of the segment
292  arcStartAngle = lineAngle + M_PI / 2.0;
293  cairo_arc( m_currentContext, center_a.x, center_a.y, radius, arcStartAngle, arcStartAngle + M_PI );
294 
295  flushPath();
296  }
297 
298  m_isElementAdded = true;
299 }
300 
301 
302 void CAIRO_GAL_BASE::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
303 {
304  syncLineWidth();
305 
306  VECTOR2D c = roundp( xform( aCenterPoint ) );
307  double r = ::roundp( xform( aRadius ) );
308 
309  cairo_set_line_width( m_currentContext, std::min( 2.0 * r, m_lineWidthInPixels ) );
310  cairo_new_sub_path( m_currentContext );
311  cairo_arc( m_currentContext, c.x, c.y, r, 0.0, 2 * M_PI );
312  cairo_close_path( m_currentContext );
313  flushPath();
314  m_isElementAdded = true;
315 }
316 
317 
318 void CAIRO_GAL_BASE::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
319  double aEndAngle )
320 {
321  syncLineWidth();
322 
323  // calculate start and end arc angles according to the rotation transform matrix
324  // and normalize:
325  arc_angles_xform_and_normalize( aStartAngle, aEndAngle );
326 
327  double r = xform( aRadius );
328 
329  // N.B. This is backwards. We set this because we want to adjust the center
330  // point that changes both endpoints. In the worst case, this is twice as far.
331  // We cannot adjust radius or center based on the other because this causes the
332  // whole arc to change position/size
333  m_lineWidthIsOdd = !( static_cast<int>( aRadius ) % 2 );
334 
335  auto mid = roundp( xform( aCenterPoint ) );
336 
337  cairo_set_line_width( m_currentContext, m_lineWidthInPixels );
338  cairo_new_sub_path( m_currentContext );
339 
340  if( m_isFillEnabled )
341  cairo_move_to( m_currentContext, mid.x, mid.y );
342 
343  cairo_arc( m_currentContext, mid.x, mid.y, r, aStartAngle, aEndAngle );
344 
345  if( m_isFillEnabled )
346  cairo_close_path( m_currentContext );
347 
348  flushPath();
349 
350  m_isElementAdded = true;
351 }
352 
353 
354 void CAIRO_GAL_BASE::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius,
355  double aStartAngle, double aEndAngle, double aWidth,
356  double aMaxError )
357 {
358  // Note: aMaxError is not used because Cairo can draw true arcs
359  if( m_isFillEnabled )
360  {
361  m_lineWidth = aWidth;
362  m_isStrokeEnabled = true;
363  m_isFillEnabled = false;
364  DrawArc( aCenterPoint, aRadius, aStartAngle, aEndAngle );
365  m_isFillEnabled = true;
366  m_isStrokeEnabled = false;
367  return;
368  }
369 
370  syncLineWidth();
371 
372  // calculate start and end arc angles according to the rotation transform matrix
373  // and normalize:
374  double startAngleS = aStartAngle;
375  double endAngleS = aEndAngle;
376  arc_angles_xform_and_normalize( startAngleS, endAngleS );
377 
378  double r = xform( aRadius );
379 
380  // N.B. This is backwards. We set this because we want to adjust the center
381  // point that changes both endpoints. In the worst case, this is twice as far.
382  // We cannot adjust radius or center based on the other because this causes the
383  // whole arc to change position/size
384  m_lineWidthIsOdd = !( static_cast<int>( aRadius ) % 2 );
385 
386  VECTOR2D mid = roundp( xform( aCenterPoint ) );
387  double width = xform( aWidth / 2.0 );
388  VECTOR2D startPointS = VECTOR2D( r, 0.0 ).Rotate( startAngleS );
389  VECTOR2D endPointS = VECTOR2D( r, 0.0 ).Rotate( endAngleS );
390 
391  cairo_save( m_currentContext );
392 
393  cairo_set_source_rgba( m_currentContext, m_strokeColor.r, m_strokeColor.g, m_strokeColor.b,
394  m_strokeColor.a );
395 
396  cairo_translate( m_currentContext, mid.x, mid.y );
397 
398  cairo_new_sub_path( m_currentContext );
399  cairo_arc( m_currentContext, 0, 0, r - width, startAngleS, endAngleS );
400 
401  cairo_new_sub_path( m_currentContext );
402  cairo_arc( m_currentContext, 0, 0, r + width, startAngleS, endAngleS );
403 
404  cairo_new_sub_path( m_currentContext );
405  cairo_arc_negative( m_currentContext, startPointS.x, startPointS.y, width, startAngleS,
406  startAngleS + M_PI );
407 
408  cairo_new_sub_path( m_currentContext );
409  cairo_arc( m_currentContext, endPointS.x, endPointS.y, width, endAngleS, endAngleS + M_PI );
410 
411  cairo_restore( m_currentContext );
412  flushPath();
413 
414  m_isElementAdded = true;
415 }
416 
417 
418 void CAIRO_GAL_BASE::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
419 {
420  // Calculate the diagonal points
421  syncLineWidth();
422 
423  const VECTOR2D p0 = roundp( xform( aStartPoint ) );
424  const VECTOR2D p1 = roundp( xform( VECTOR2D( aEndPoint.x, aStartPoint.y ) ) );
425  const VECTOR2D p2 = roundp( xform( aEndPoint ) );
426  const VECTOR2D p3 = roundp( xform( VECTOR2D( aStartPoint.x, aEndPoint.y ) ) );
427 
428  // The path is composed from 4 segments
429  cairo_move_to( m_currentContext, p0.x, p0.y );
430  cairo_line_to( m_currentContext, p1.x, p1.y );
431  cairo_line_to( m_currentContext, p2.x, p2.y );
432  cairo_line_to( m_currentContext, p3.x, p3.y );
433  cairo_close_path( m_currentContext );
434  flushPath();
435 
436  m_isElementAdded = true;
437 }
438 
439 
440 void CAIRO_GAL_BASE::DrawPolygon( const SHAPE_POLY_SET& aPolySet, bool aStrokeTriangulation )
441 {
442  for( int i = 0; i < aPolySet.OutlineCount(); ++i )
443  drawPoly( aPolySet.COutline( i ) );
444 }
445 
446 
448 {
449  drawPoly( aPolygon );
450 }
451 
452 
453 void CAIRO_GAL_BASE::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
454  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint,
455  double aFilterValue )
456 {
457  // Note: aFilterValue is not used because the cubic Bezier curve is
458  // supported by Cairo.
459  syncLineWidth();
460 
461  const VECTOR2D sp = roundp( xform( aStartPoint ) );
462  const VECTOR2D cpa = roundp( xform( aControlPointA ) );
463  const VECTOR2D cpb = roundp( xform( aControlPointB ) );
464  const VECTOR2D ep = roundp( xform( aEndPoint ) );
465 
466  cairo_move_to( m_currentContext, sp.x, sp.y );
467  cairo_curve_to( m_currentContext, cpa.x, cpa.y, cpb.x, cpb.y, ep.x, ep.y );
468  cairo_line_to( m_currentContext, ep.x, ep.y );
469 
470  flushPath();
471  m_isElementAdded = true;
472 }
473 
474 
476 {
477  cairo_save( m_currentContext );
478 
479  // We have to calculate the pixel size in users units to draw the image.
480  // m_worldUnitLength is a factor used for converting IU to inches
481  double scale = 1.0 / ( aBitmap.GetPPI() * m_worldUnitLength );
482 
483  // The position of the bitmap is the bitmap center.
484  // move the draw origin to the top left bitmap corner:
485  int w = aBitmap.GetSizePixels().x;
486  int h = aBitmap.GetSizePixels().y;
487 
488  cairo_set_matrix( m_currentContext, &m_currentWorld2Screen );
489  cairo_scale( m_currentContext, scale, scale );
490  cairo_translate( m_currentContext, -w / 2.0, -h / 2.0 );
491 
492  cairo_new_path( m_currentContext );
493  cairo_surface_t* image = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, w, h );
494  cairo_surface_flush( image );
495 
496  unsigned char* pix_buffer = cairo_image_surface_get_data( image );
497 
498  // The pixel buffer of the initial bitmap:
499  const wxImage& bm_pix_buffer = *aBitmap.GetImageData();
500 
501  uint32_t mask_color = ( bm_pix_buffer.GetMaskRed() << 16 )
502  + ( bm_pix_buffer.GetMaskGreen() << 8 ) + ( bm_pix_buffer.GetMaskBlue() );
503 
504  // Copy the source bitmap to the cairo bitmap buffer.
505  // In cairo bitmap buffer, a ARGB32 bitmap is an ARGB pixel packed into a uint_32
506  // 24 low bits only are used for color, top 8 are transparency.
507  for( int row = 0; row < h; row++ )
508  {
509  for( int col = 0; col < w; col++ )
510  {
511  // Build the RGB24 pixel:
512  uint32_t pixel = bm_pix_buffer.GetRed( col, row ) << 16;
513  pixel += bm_pix_buffer.GetGreen( col, row ) << 8;
514  pixel += bm_pix_buffer.GetBlue( col, row );
515 
516  if( bm_pix_buffer.HasAlpha() )
517  pixel += bm_pix_buffer.GetAlpha( col, row ) << 24;
518  else if( bm_pix_buffer.HasMask() && pixel == mask_color )
519  pixel += ( wxALPHA_TRANSPARENT << 24 );
520  else
521  pixel += ( wxALPHA_OPAQUE << 24 );
522 
523  // Write the pixel to the cairo image buffer:
524  uint32_t* pix_ptr = (uint32_t*) pix_buffer;
525  *pix_ptr = pixel;
526  pix_buffer += 4;
527  }
528  }
529 
530  cairo_surface_mark_dirty( image );
531  cairo_set_source_surface( m_currentContext, image, 0, 0 );
532  cairo_paint( m_currentContext );
533 
534  // store the image handle so it can be destroyed later
535  m_imageSurfaces.push_back( image );
536 
537  m_isElementAdded = true;
538 
539  cairo_restore( m_currentContext );
540 }
541 
542 
543 void CAIRO_GAL_BASE::ResizeScreen( int aWidth, int aHeight )
544 {
545  m_screenSize = VECTOR2I( aWidth, aHeight );
546 }
547 
548 
550 {
551  storePath();
552 }
553 
554 
556 {
557  cairo_set_source_rgb( m_currentContext, m_clearColor.r, m_clearColor.g, m_clearColor.b );
558  cairo_rectangle( m_currentContext, 0.0, 0.0, m_screenSize.x, m_screenSize.y );
559  cairo_fill( m_currentContext );
560 }
561 
562 
563 void CAIRO_GAL_BASE::SetIsFill( bool aIsFillEnabled )
564 {
565  storePath();
566  m_isFillEnabled = aIsFillEnabled;
567 
568  if( m_isGrouping )
569  {
570  GROUP_ELEMENT groupElement;
571  groupElement.m_Command = CMD_SET_FILL;
572  groupElement.m_Argument.BoolArg = aIsFillEnabled;
573  m_currentGroup->push_back( groupElement );
574  }
575 }
576 
577 
578 void CAIRO_GAL_BASE::SetIsStroke( bool aIsStrokeEnabled )
579 {
580  storePath();
581  m_isStrokeEnabled = aIsStrokeEnabled;
582 
583  if( m_isGrouping )
584  {
585  GROUP_ELEMENT groupElement;
586  groupElement.m_Command = CMD_SET_STROKE;
587  groupElement.m_Argument.BoolArg = aIsStrokeEnabled;
588  m_currentGroup->push_back( groupElement );
589  }
590 }
591 
592 
594 {
595  storePath();
596  m_strokeColor = aColor;
597 
598  if( m_isGrouping )
599  {
600  GROUP_ELEMENT groupElement;
601  groupElement.m_Command = CMD_SET_STROKECOLOR;
602  groupElement.m_Argument.DblArg[0] = m_strokeColor.r;
603  groupElement.m_Argument.DblArg[1] = m_strokeColor.g;
604  groupElement.m_Argument.DblArg[2] = m_strokeColor.b;
605  groupElement.m_Argument.DblArg[3] = m_strokeColor.a;
606  m_currentGroup->push_back( groupElement );
607  }
608 }
609 
610 
612 {
613  storePath();
614  m_fillColor = aColor;
615 
616  if( m_isGrouping )
617  {
618  GROUP_ELEMENT groupElement;
619  groupElement.m_Command = CMD_SET_FILLCOLOR;
620  groupElement.m_Argument.DblArg[0] = m_fillColor.r;
621  groupElement.m_Argument.DblArg[1] = m_fillColor.g;
622  groupElement.m_Argument.DblArg[2] = m_fillColor.b;
623  groupElement.m_Argument.DblArg[3] = m_fillColor.a;
624  m_currentGroup->push_back( groupElement );
625  }
626 }
627 
628 
629 void CAIRO_GAL_BASE::SetLineWidth( float aLineWidth )
630 {
631  storePath();
632  GAL::SetLineWidth( aLineWidth );
633 
634  if( m_isGrouping )
635  {
636  GROUP_ELEMENT groupElement;
637  groupElement.m_Command = CMD_SET_LINE_WIDTH;
638  groupElement.m_Argument.DblArg[0] = aLineWidth;
639  m_currentGroup->push_back( groupElement );
640  }
641  else
642  {
643  m_lineWidth = aLineWidth;
644  }
645 }
646 
647 
648 void CAIRO_GAL_BASE::SetLayerDepth( double aLayerDepth )
649 {
650  super::SetLayerDepth( aLayerDepth );
651  storePath();
652 }
653 
654 
655 void CAIRO_GAL_BASE::Transform( const MATRIX3x3D& aTransformation )
656 {
657  cairo_matrix_t cairoTransformation, newXform;
658 
659  cairo_matrix_init( &cairoTransformation, aTransformation.m_data[0][0],
660  aTransformation.m_data[1][0], aTransformation.m_data[0][1],
661  aTransformation.m_data[1][1], aTransformation.m_data[0][2],
662  aTransformation.m_data[1][2] );
663 
664  cairo_matrix_multiply( &newXform, &m_currentXform, &cairoTransformation );
665  m_currentXform = newXform;
667 }
668 
669 
670 void CAIRO_GAL_BASE::Rotate( double aAngle )
671 {
672  storePath();
673 
674  if( m_isGrouping )
675  {
676  GROUP_ELEMENT groupElement;
677  groupElement.m_Command = CMD_ROTATE;
678  groupElement.m_Argument.DblArg[0] = aAngle;
679  m_currentGroup->push_back( groupElement );
680  }
681  else
682  {
683  cairo_matrix_rotate( &m_currentXform, aAngle );
685  }
686 }
687 
688 
689 void CAIRO_GAL_BASE::Translate( const VECTOR2D& aTranslation )
690 {
691  storePath();
692 
693  if( m_isGrouping )
694  {
695  GROUP_ELEMENT groupElement;
696  groupElement.m_Command = CMD_TRANSLATE;
697  groupElement.m_Argument.DblArg[0] = aTranslation.x;
698  groupElement.m_Argument.DblArg[1] = aTranslation.y;
699  m_currentGroup->push_back( groupElement );
700  }
701  else
702  {
703  cairo_matrix_translate( &m_currentXform, aTranslation.x, aTranslation.y );
705  }
706 }
707 
708 
709 void CAIRO_GAL_BASE::Scale( const VECTOR2D& aScale )
710 {
711  storePath();
712 
713  if( m_isGrouping )
714  {
715  GROUP_ELEMENT groupElement;
716  groupElement.m_Command = CMD_SCALE;
717  groupElement.m_Argument.DblArg[0] = aScale.x;
718  groupElement.m_Argument.DblArg[1] = aScale.y;
719  m_currentGroup->push_back( groupElement );
720  }
721  else
722  {
723  cairo_matrix_scale( &m_currentXform, aScale.x, aScale.y );
725  }
726 }
727 
728 
730 {
731  storePath();
732 
733  if( m_isGrouping )
734  {
735  GROUP_ELEMENT groupElement;
736  groupElement.m_Command = CMD_SAVE;
737  m_currentGroup->push_back( groupElement );
738  }
739  else
740  {
741  m_xformStack.push_back( m_currentXform );
743  }
744 }
745 
746 
748 {
749  storePath();
750 
751  if( m_isGrouping )
752  {
753  GROUP_ELEMENT groupElement;
754  groupElement.m_Command = CMD_RESTORE;
755  m_currentGroup->push_back( groupElement );
756  }
757  else
758  {
759  if( !m_xformStack.empty() )
760  {
761  m_currentXform = m_xformStack.back();
762  m_xformStack.pop_back();
764  }
765  }
766 }
767 
768 
770 {
771  // If the grouping is started: the actual path is stored in the group, when
772  // a attribute was changed or when grouping stops with the end group method.
773  storePath();
774 
775  GROUP group;
776  int groupNumber = getNewGroupNumber();
777  m_groups.insert( std::make_pair( groupNumber, group ) );
778  m_currentGroup = &m_groups[groupNumber];
779  m_isGrouping = true;
780 
781  return groupNumber;
782 }
783 
784 
786 {
787  storePath();
788  m_isGrouping = false;
789 }
790 
791 
792 void CAIRO_GAL_BASE::DrawGroup( int aGroupNumber )
793 {
794  // This method implements a small Virtual Machine - all stored commands
795  // are executed; nested calling is also possible
796 
797  storePath();
798 
799  for( auto it = m_groups[aGroupNumber].begin(); it != m_groups[aGroupNumber].end(); ++it )
800  {
801  switch( it->m_Command )
802  {
803  case CMD_SET_FILL:
804  m_isFillEnabled = it->m_Argument.BoolArg;
805  break;
806 
807  case CMD_SET_STROKE:
808  m_isStrokeEnabled = it->m_Argument.BoolArg;
809  break;
810 
811  case CMD_SET_FILLCOLOR:
812  m_fillColor = COLOR4D( it->m_Argument.DblArg[0], it->m_Argument.DblArg[1],
813  it->m_Argument.DblArg[2], it->m_Argument.DblArg[3] );
814  break;
815 
816  case CMD_SET_STROKECOLOR:
817  m_strokeColor = COLOR4D( it->m_Argument.DblArg[0], it->m_Argument.DblArg[1],
818  it->m_Argument.DblArg[2], it->m_Argument.DblArg[3] );
819  break;
820 
821  case CMD_SET_LINE_WIDTH:
822  {
823  // Make lines appear at least 1 pixel wide, no matter of zoom
824  double x = 1.0, y = 1.0;
825  cairo_device_to_user_distance( m_currentContext, &x, &y );
826  double minWidth = std::min( fabs( x ), fabs( y ) );
827  cairo_set_line_width( m_currentContext,
828  std::max( it->m_Argument.DblArg[0], minWidth ) );
829  break;
830  }
831 
832 
833  case CMD_STROKE_PATH:
834  cairo_set_source_rgba( m_currentContext, m_strokeColor.r, m_strokeColor.g,
836  cairo_append_path( m_currentContext, it->m_CairoPath );
837  cairo_stroke( m_currentContext );
838  break;
839 
840  case CMD_FILL_PATH:
841  cairo_set_source_rgba( m_currentContext, m_fillColor.r, m_fillColor.g, m_fillColor.b,
842  m_strokeColor.a );
843  cairo_append_path( m_currentContext, it->m_CairoPath );
844  cairo_fill( m_currentContext );
845  break;
846 
847  /*
848  case CMD_TRANSFORM:
849  cairo_matrix_t matrix;
850  cairo_matrix_init( &matrix, it->argument.DblArg[0], it->argument.DblArg[1],
851  it->argument.DblArg[2], it->argument.DblArg[3],
852  it->argument.DblArg[4], it->argument.DblArg[5] );
853  cairo_transform( m_currentContext, &matrix );
854  break;
855  */
856 
857  case CMD_ROTATE:
858  cairo_rotate( m_currentContext, it->m_Argument.DblArg[0] );
859  break;
860 
861  case CMD_TRANSLATE:
862  cairo_translate( m_currentContext, it->m_Argument.DblArg[0], it->m_Argument.DblArg[1] );
863  break;
864 
865  case CMD_SCALE:
866  cairo_scale( m_currentContext, it->m_Argument.DblArg[0], it->m_Argument.DblArg[1] );
867  break;
868 
869  case CMD_SAVE:
870  cairo_save( m_currentContext );
871  break;
872 
873  case CMD_RESTORE:
874  cairo_restore( m_currentContext );
875  break;
876 
877  case CMD_CALL_GROUP:
878  DrawGroup( it->m_Argument.IntArg );
879  break;
880  }
881  }
882 }
883 
884 
885 void CAIRO_GAL_BASE::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
886 {
887  storePath();
888 
889  for( auto it = m_groups[aGroupNumber].begin(); it != m_groups[aGroupNumber].end(); ++it )
890  {
891  if( it->m_Command == CMD_SET_FILLCOLOR || it->m_Command == CMD_SET_STROKECOLOR )
892  {
893  it->m_Argument.DblArg[0] = aNewColor.r;
894  it->m_Argument.DblArg[1] = aNewColor.g;
895  it->m_Argument.DblArg[2] = aNewColor.b;
896  it->m_Argument.DblArg[3] = aNewColor.a;
897  }
898  }
899 }
900 
901 
902 void CAIRO_GAL_BASE::ChangeGroupDepth( int aGroupNumber, int aDepth )
903 {
904  // Cairo does not have any possibilities to change the depth coordinate of stored items,
905  // it depends only on the order of drawing
906 }
907 
908 
909 void CAIRO_GAL_BASE::DeleteGroup( int aGroupNumber )
910 {
911  storePath();
912 
913  // Delete the Cairo paths
914  std::deque<GROUP_ELEMENT>::iterator it, end;
915 
916  for( it = m_groups[aGroupNumber].begin(), end = m_groups[aGroupNumber].end(); it != end; ++it )
917  {
918  if( it->m_Command == CMD_FILL_PATH || it->m_Command == CMD_STROKE_PATH )
919  cairo_path_destroy( it->m_CairoPath );
920  }
921 
922  // Delete the group
923  m_groups.erase( aGroupNumber );
924 }
925 
926 
928 {
929  for( auto it = m_groups.begin(); it != m_groups.end(); )
930  DeleteGroup( ( it++ )->first );
931 }
932 
933 
935 {
936  cairo_set_operator( m_currentContext, aSetting ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_OVER );
937 }
938 
939 
941 {
944 }
945 
946 
948 {
949  m_compositor->DrawBuffer( m_tempBuffer, m_mainBuffer, CAIRO_OPERATOR_ADD );
950 }
951 
952 
954 {
957 }
958 
959 
961 {
962  m_compositor->DrawBuffer( m_tempBuffer, m_mainBuffer, CAIRO_OPERATOR_OVER );
963 }
964 
965 
966 void CAIRO_GAL_BASE::DrawCursor( const VECTOR2D& aCursorPosition )
967 {
968  m_cursorPosition = aCursorPosition;
969 }
970 
971 
972 void CAIRO_GAL_BASE::EnableDepthTest( bool aEnabled )
973 {
974 }
975 
976 
978 {
979  for( _cairo_surface* imageSurface : m_imageSurfaces )
980  cairo_surface_destroy( imageSurface );
981 
982  m_imageSurfaces.clear();
983 
984  ClearScreen();
985 
986  // Compute the world <-> screen transformations
988 
989  cairo_matrix_init( &m_cairoWorldScreenMatrix, m_worldScreenMatrix.m_data[0][0],
992  m_worldScreenMatrix.m_data[1][2] );
993 
994  // we work in screen-space coordinates and do the transforms outside.
995  cairo_identity_matrix( m_context );
996 
997  cairo_matrix_init_identity( &m_currentXform );
998 
999  // Start drawing with a new path
1000  cairo_new_path( m_context );
1001  m_isElementAdded = true;
1002 
1004 
1005  m_lineWidth = 0;
1006 }
1007 
1008 
1009 void CAIRO_GAL_BASE::drawAxes( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1010 {
1011  syncLineWidth();
1012 
1013  VECTOR2D p0 = roundp( xform( aStartPoint ) );
1014  VECTOR2D p1 = roundp( xform( aEndPoint ) );
1015  VECTOR2D org = roundp( xform( VECTOR2D( 0.0, 0.0 ) ) ); // Axis origin = 0,0 coord
1016 
1017  cairo_set_source_rgba( m_currentContext, m_axesColor.r, m_axesColor.g, m_axesColor.b,
1018  m_axesColor.a );
1019  cairo_move_to( m_currentContext, p0.x, org.y );
1020  cairo_line_to( m_currentContext, p1.x, org.y );
1021  cairo_move_to( m_currentContext, org.x, p0.y );
1022  cairo_line_to( m_currentContext, org.x, p1.y );
1023  cairo_stroke( m_currentContext );
1024 }
1025 
1026 
1027 void CAIRO_GAL_BASE::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
1028 {
1029  syncLineWidth();
1030  VECTOR2D p0 = roundp( xform( aStartPoint ) );
1031  VECTOR2D p1 = roundp( xform( aEndPoint ) );
1032 
1033  cairo_set_source_rgba( m_currentContext, m_gridColor.r, m_gridColor.g, m_gridColor.b,
1034  m_gridColor.a );
1035  cairo_move_to( m_currentContext, p0.x, p0.y );
1036  cairo_line_to( m_currentContext, p1.x, p1.y );
1037  cairo_stroke( m_currentContext );
1038 }
1039 
1040 
1042 {
1043  syncLineWidth();
1044  VECTOR2D offset( 0, 0 );
1045  double size = 2.0 * m_lineWidthInPixels + 0.5;
1046 
1047  VECTOR2D p0 = roundp( xform( aPoint ) ) - VECTOR2D( size, 0 ) + offset;
1048  VECTOR2D p1 = roundp( xform( aPoint ) ) + VECTOR2D( size, 0 ) + offset;
1049  VECTOR2D p2 = roundp( xform( aPoint ) ) - VECTOR2D( 0, size ) + offset;
1050  VECTOR2D p3 = roundp( xform( aPoint ) ) + VECTOR2D( 0, size ) + offset;
1051 
1052  cairo_set_source_rgba( m_currentContext, m_gridColor.r, m_gridColor.g, m_gridColor.b,
1053  m_gridColor.a );
1054  cairo_move_to( m_currentContext, p0.x, p0.y );
1055  cairo_line_to( m_currentContext, p1.x, p1.y );
1056  cairo_move_to( m_currentContext, p2.x, p2.y );
1057  cairo_line_to( m_currentContext, p3.x, p3.y );
1058  cairo_stroke( m_currentContext );
1059 }
1060 
1061 
1062 void CAIRO_GAL_BASE::drawGridPoint( const VECTOR2D& aPoint, double aWidth, double aHeight )
1063 {
1064  VECTOR2D p = roundp( xform( aPoint ) );
1065 
1066  double sw = std::max( 1.0, aWidth );
1067  double sh = std::max( 1.0, aHeight );
1068 
1069  cairo_set_source_rgba( m_currentContext, m_gridColor.r, m_gridColor.g, m_gridColor.b,
1070  m_gridColor.a );
1071  cairo_rectangle( m_currentContext, p.x - std::floor( sw / 2 ) - 0.5,
1072  p.y - std::floor( sh / 2 ) - 0.5, sw, sh );
1073 
1074  cairo_fill( m_currentContext );
1075 }
1076 
1077 
1079 {
1080  if( m_isFillEnabled )
1081  {
1082  cairo_set_source_rgba( m_currentContext, m_fillColor.r, m_fillColor.g, m_fillColor.b,
1083  m_fillColor.a );
1084 
1085  if( m_isStrokeEnabled )
1086  {
1087  cairo_set_line_width( m_currentContext, m_lineWidthInPixels );
1088  cairo_fill_preserve( m_currentContext );
1089  }
1090  else
1091  {
1092  cairo_fill( m_currentContext );
1093  }
1094  }
1095 
1096  if( m_isStrokeEnabled )
1097  {
1098  cairo_set_line_width( m_currentContext, m_lineWidthInPixels );
1099  cairo_set_source_rgba( m_currentContext, m_strokeColor.r, m_strokeColor.g, m_strokeColor.b,
1100  m_strokeColor.a );
1101  cairo_stroke( m_currentContext );
1102  }
1103 }
1104 
1105 
1107 {
1108  if( m_isElementAdded )
1109  {
1110  m_isElementAdded = false;
1111 
1112  if( !m_isGrouping )
1113  {
1114  if( m_isFillEnabled )
1115  {
1116  cairo_set_source_rgba( m_currentContext, m_fillColor.r, m_fillColor.g,
1118  cairo_fill_preserve( m_currentContext );
1119  }
1120 
1121  if( m_isStrokeEnabled )
1122  {
1123  cairo_set_source_rgba( m_currentContext, m_strokeColor.r, m_strokeColor.g,
1125  cairo_stroke_preserve( m_currentContext );
1126  }
1127  }
1128  else
1129  {
1130  // Copy the actual path, append it to the global path list
1131  // then check, if the path needs to be stroked/filled and
1132  // add this command to the group list;
1133  if( m_isStrokeEnabled )
1134  {
1135  GROUP_ELEMENT groupElement;
1136  groupElement.m_CairoPath = cairo_copy_path( m_currentContext );
1137  groupElement.m_Command = CMD_STROKE_PATH;
1138  m_currentGroup->push_back( groupElement );
1139  }
1140 
1141  if( m_isFillEnabled )
1142  {
1143  GROUP_ELEMENT groupElement;
1144  groupElement.m_CairoPath = cairo_copy_path( m_currentContext );
1145  groupElement.m_Command = CMD_FILL_PATH;
1146  m_currentGroup->push_back( groupElement );
1147  }
1148  }
1149 
1150  cairo_new_path( m_currentContext );
1151  }
1152 }
1153 
1154 
1155 void CAIRO_GAL_BASE::blitCursor( wxMemoryDC& clientDC )
1156 {
1157  if( !IsCursorEnabled() )
1158  return;
1159 
1161  const COLOR4D cColor = getCursorColor();
1162  const int cursorSize = m_fullscreenCursor ? 8000 : 80;
1163 
1164  wxColour color( cColor.r * cColor.a * 255, cColor.g * cColor.a * 255, cColor.b * cColor.a * 255,
1165  255 );
1166  clientDC.SetPen( wxPen( color ) );
1167  clientDC.DrawLine( p.x - cursorSize / 2, p.y, p.x + cursorSize / 2, p.y );
1168  clientDC.DrawLine( p.x, p.y - cursorSize / 2, p.x, p.y + cursorSize / 2 );
1169 }
1170 
1171 
1172 void CAIRO_GAL_BASE::drawPoly( const std::deque<VECTOR2D>& aPointList )
1173 {
1174  wxCHECK( aPointList.size() > 1, /* void */ );
1175 
1176  // Iterate over the point list and draw the segments
1177  std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
1178 
1179  syncLineWidth();
1180 
1181  const VECTOR2D p = roundp( xform( it->x, it->y ) );
1182 
1183  cairo_move_to( m_currentContext, p.x, p.y );
1184 
1185  for( ++it; it != aPointList.end(); ++it )
1186  {
1187  const VECTOR2D p2 = roundp( xform( it->x, it->y ) );
1188 
1189  cairo_line_to( m_currentContext, p2.x, p2.y );
1190  }
1191 
1192  flushPath();
1193  m_isElementAdded = true;
1194 }
1195 
1196 
1197 void CAIRO_GAL_BASE::drawPoly( const VECTOR2D aPointList[], int aListSize )
1198 {
1199  wxCHECK( aListSize > 1, /* void */ );
1200 
1201  // Iterate over the point list and draw the segments
1202  const VECTOR2D* ptr = aPointList;
1203 
1204  syncLineWidth();
1205 
1206  const VECTOR2D p = roundp( xform( ptr->x, ptr->y ) );
1207  cairo_move_to( m_currentContext, p.x, p.y );
1208 
1209  for( int i = 1; i < aListSize; ++i )
1210  {
1211  ++ptr;
1212  const VECTOR2D p2 = roundp( xform( ptr->x, ptr->y ) );
1213  cairo_line_to( m_currentContext, p2.x, p2.y );
1214  }
1215 
1216  flushPath();
1217  m_isElementAdded = true;
1218 }
1219 
1220 
1222 {
1223  wxCHECK( aLineChain.PointCount() > 1, /* void */ );
1224 
1225  syncLineWidth();
1226 
1227  auto numPoints = aLineChain.PointCount();
1228 
1229  if( aLineChain.IsClosed() )
1230  numPoints += 1;
1231 
1232  const VECTOR2I start = aLineChain.CPoint( 0 );
1233  const VECTOR2D p = roundp( xform( start.x, start.y ) );
1234  cairo_move_to( m_currentContext, p.x, p.y );
1235 
1236  for( int i = 1; i < numPoints; ++i )
1237  {
1238  const VECTOR2I& pw = aLineChain.CPoint( i );
1239  const VECTOR2D ps = roundp( xform( pw.x, pw.y ) );
1240  cairo_line_to( m_currentContext, ps.x, ps.y );
1241  }
1242 
1243  flushPath();
1244  m_isElementAdded = true;
1245 }
1246 
1247 
1249 {
1250  wxASSERT_MSG( m_groups.size() < std::numeric_limits<unsigned int>::max(),
1251  wxT( "There are no free slots to store a group" ) );
1252 
1253  while( m_groups.find( m_groupCounter ) != m_groups.end() )
1254  m_groupCounter++;
1255 
1256  return m_groupCounter++;
1257 }
1258 
1259 
1260 CAIRO_GAL::CAIRO_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
1261  wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener,
1262  const wxString& aName ) :
1263  CAIRO_GAL_BASE( aDisplayOptions ),
1264  wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName )
1265 {
1266  // Initialise compositing state
1267  m_mainBuffer = 0;
1268  m_overlayBuffer = 0;
1269  m_tempBuffer = 0;
1270  m_savedBuffer = 0;
1271  m_validCompositor = false;
1273 
1274  m_bitmapBuffer = nullptr;
1275  m_wxOutput = nullptr;
1276 
1277  m_parentWindow = aParent;
1278  m_mouseListener = aMouseListener;
1279  m_paintListener = aPaintListener;
1280 
1281  // Connect the native cursor handler
1282  Connect( wxEVT_SET_CURSOR, wxSetCursorEventHandler( CAIRO_GAL::onSetNativeCursor ), nullptr,
1283  this );
1284 
1285  // Connecting the event handlers
1286  Connect( wxEVT_PAINT, wxPaintEventHandler( CAIRO_GAL::onPaint ) );
1287 
1288  // Mouse events are skipped to the parent
1289  Connect( wxEVT_MOTION, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1290  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1291  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1292  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1293  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1294  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1295  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1296  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1297  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1298  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1299  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1300 #if defined _WIN32 || defined _WIN64
1301  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
1302 #endif
1303 
1304  SetSize( aParent->GetClientSize() );
1305  m_screenSize = VECTOR2I( aParent->GetClientSize() );
1306 
1307  // Allocate memory for pixel storage
1308  allocateBitmaps();
1309 
1310  m_isInitialized = false;
1311 }
1312 
1313 
1315 {
1316  deleteBitmaps();
1317 }
1318 
1319 
1321 {
1322  initSurface();
1323 
1325 
1326  if( !m_validCompositor )
1327  setCompositor();
1328 
1329  m_compositor->SetMainContext( m_context );
1330  m_compositor->SetBuffer( m_mainBuffer );
1331 }
1332 
1333 
1335 {
1337 
1338  // Merge buffers on the screen
1339  m_compositor->DrawBuffer( m_mainBuffer );
1340  m_compositor->DrawBuffer( m_overlayBuffer );
1341 
1342  // Now translate the raw context data from the format stored
1343  // by cairo into a format understood by wxImage.
1344  pixman_image_t* dstImg = pixman_image_create_bits(
1345  wxPlatformInfo::Get().GetEndianness() == wxENDIAN_LITTLE ? PIXMAN_b8g8r8
1346  : PIXMAN_r8g8b8,
1347  m_screenSize.x, m_screenSize.y, (uint32_t*) m_wxOutput, m_wxBufferWidth * 3 );
1348  pixman_image_t* srcImg =
1349  pixman_image_create_bits( PIXMAN_a8r8g8b8, m_screenSize.x, m_screenSize.y,
1350  (uint32_t*) m_bitmapBuffer, m_wxBufferWidth * 4 );
1351 
1352  pixman_image_composite( PIXMAN_OP_SRC, srcImg, nullptr, dstImg, 0, 0, 0, 0, 0, 0,
1354 
1355  // Free allocated memory
1356  pixman_image_unref( srcImg );
1357  pixman_image_unref( dstImg );
1358 
1359  wxImage img( m_wxBufferWidth, m_screenSize.y, m_wxOutput, true );
1360  wxBitmap bmp( img );
1361  wxMemoryDC mdc( bmp );
1362  wxClientDC clientDC( this );
1363 
1364  // Now it is the time to blit the mouse cursor
1365  blitCursor( mdc );
1366  clientDC.Blit( 0, 0, m_screenSize.x, m_screenSize.y, &mdc, 0, 0, wxCOPY );
1367 
1368  deinitSurface();
1369 }
1370 
1371 
1372 void CAIRO_GAL::PostPaint( wxPaintEvent& aEvent )
1373 {
1374  // posts an event to m_paint_listener to ask for redraw the canvas.
1375  if( m_paintListener )
1376  wxPostEvent( m_paintListener, aEvent );
1377 }
1378 
1379 
1380 void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight )
1381 {
1382  CAIRO_GAL_BASE::ResizeScreen( aWidth, aHeight );
1383 
1384  // Recreate the bitmaps
1385  deleteBitmaps();
1386  allocateBitmaps();
1387 
1388  if( m_validCompositor )
1389  m_compositor->Resize( aWidth, aHeight );
1390 
1391  m_validCompositor = false;
1392 
1393  SetSize( wxSize( aWidth, aHeight ) );
1394 }
1395 
1396 
1397 bool CAIRO_GAL::Show( bool aShow )
1398 {
1399  bool s = wxWindow::Show( aShow );
1400 
1401  if( aShow )
1402  wxWindow::Raise();
1403 
1404  return s;
1405 }
1406 
1407 
1409 {
1410  initSurface();
1411  return CAIRO_GAL_BASE::BeginGroup();
1412 }
1413 
1414 
1416 {
1418  deinitSurface();
1419 }
1420 
1421 
1423 {
1424  // If the compositor is not set, that means that there is a recaching process going on
1425  // and we do not need the compositor now
1426  if( !m_validCompositor )
1427  return;
1428 
1429  // Cairo grouping prevents display of overlapping items on the same layer in the lighter color
1430  if( m_isInitialized )
1431  storePath();
1432 
1433  switch( aTarget )
1434  {
1435  default:
1436  case TARGET_CACHED:
1437  case TARGET_NONCACHED: m_compositor->SetBuffer( m_mainBuffer ); break;
1438  case TARGET_OVERLAY: m_compositor->SetBuffer( m_overlayBuffer ); break;
1439  case TARGET_TEMP: m_compositor->SetBuffer( m_tempBuffer ); break;
1440  }
1441 
1442  m_currentTarget = aTarget;
1443 }
1444 
1445 
1447 {
1448  return m_currentTarget;
1449 }
1450 
1451 
1453 {
1454  // Save the current state
1455  unsigned int currentBuffer = m_compositor->GetBuffer();
1456 
1457  switch( aTarget )
1458  {
1459  // Cached and noncached items are rendered to the same buffer
1460  default:
1461  case TARGET_CACHED:
1462  case TARGET_NONCACHED: m_compositor->SetBuffer( m_mainBuffer ); break;
1463  case TARGET_OVERLAY: m_compositor->SetBuffer( m_overlayBuffer ); break;
1464  case TARGET_TEMP: m_compositor->SetBuffer( m_tempBuffer ); break;
1465  }
1466 
1467  m_compositor->ClearBuffer( COLOR4D::BLACK );
1468 
1469  // Restore the previous state
1470  m_compositor->SetBuffer( currentBuffer );
1471 }
1472 
1473 
1475 {
1476  if( m_isInitialized )
1477  return;
1478 
1479  m_surface = cairo_image_surface_create_for_data( m_bitmapBuffer, GAL_FORMAT, m_wxBufferWidth,
1480  m_screenSize.y, m_stride );
1481 
1482  m_context = cairo_create( m_surface );
1483 
1484 #ifdef DEBUG
1485  cairo_status_t status = cairo_status( m_context );
1486  wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, wxT( "Cairo context creation error" ) );
1487 #endif /* DEBUG */
1488 
1490 
1491  m_isInitialized = true;
1492 }
1493 
1494 
1496 {
1497  if( !m_isInitialized )
1498  return;
1499 
1500  cairo_destroy( m_context );
1501  m_context = nullptr;
1502  cairo_surface_destroy( m_surface );
1503  m_surface = nullptr;
1504 
1505  m_isInitialized = false;
1506 }
1507 
1508 
1510 {
1512 
1513  while( ( ( m_wxBufferWidth * 3 ) % 4 ) != 0 )
1514  m_wxBufferWidth++;
1515 
1516  // Create buffer, use the system independent Cairo context backend
1517  m_stride = cairo_format_stride_for_width( GAL_FORMAT, m_wxBufferWidth );
1519 
1520  wxASSERT( m_bitmapBuffer == nullptr );
1521  m_bitmapBuffer = new unsigned char[m_bufferSize * 4];
1522 
1523  wxASSERT( m_wxOutput == nullptr );
1524  m_wxOutput = new unsigned char[m_wxBufferWidth * 3 * m_screenSize.y];
1525 }
1526 
1527 
1529 {
1530  delete[] m_bitmapBuffer;
1531  m_bitmapBuffer = nullptr;
1532 
1533  delete[] m_wxOutput;
1534  m_wxOutput = nullptr;
1535 }
1536 
1537 
1539 {
1540  // Recreate the compositor with the new Cairo context
1543  m_compositor->SetAntialiasingMode( m_options.cairo_antialiasing_mode );
1544 
1545  // Prepare buffers
1546  m_mainBuffer = m_compositor->CreateBuffer();
1547  m_overlayBuffer = m_compositor->CreateBuffer();
1548  m_tempBuffer = m_compositor->CreateBuffer();
1549 
1550  m_validCompositor = true;
1551 }
1552 
1553 
1554 void CAIRO_GAL::onPaint( wxPaintEvent& aEvent )
1555 {
1556  PostPaint( aEvent );
1557 }
1558 
1559 
1560 void CAIRO_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1561 {
1562  // Post the mouse event to the event listener registered in constructor, if any
1563  if( m_mouseListener )
1564  wxPostEvent( m_mouseListener, aEvent );
1565 }
1566 
1567 
1569 {
1570  bool refresh = false;
1571 
1572  if( m_validCompositor &&
1573  aOptions.cairo_antialiasing_mode != m_compositor->GetAntialiasingMode() )
1574  {
1575  m_compositor->SetAntialiasingMode( m_options.cairo_antialiasing_mode );
1576  m_validCompositor = false;
1577  deinitSurface();
1578 
1579  refresh = true;
1580  }
1581 
1582  if( super::updatedGalDisplayOptions( aOptions ) )
1583  {
1584  Refresh();
1585  refresh = true;
1586  }
1587 
1588  return refresh;
1589 }
1590 
1591 
1593 {
1594  // Store the current cursor type and get the wxCursor for it
1595  if( !GAL::SetNativeCursorStyle( aCursor ) )
1596  return false;
1597 
1599 
1600  // Update the cursor in the wx control
1601  wxWindow::SetCursor( m_currentwxCursor );
1602 
1603  return true;
1604 }
1605 
1606 
1607 void CAIRO_GAL::onSetNativeCursor( wxSetCursorEvent& aEvent )
1608 {
1609  aEvent.SetCursor( m_currentwxCursor );
1610 }
1611 
1612 
1614 {
1616 
1617  // Draw the grid
1618  // For the drawing the start points, end points and increments have
1619  // to be calculated in world coordinates
1620  VECTOR2D worldStartPoint = m_screenWorldMatrix * VECTOR2D( 0.0, 0.0 );
1621  VECTOR2D worldEndPoint = m_screenWorldMatrix * VECTOR2D( m_screenSize );
1622 
1623  // Compute the line marker or point radius of the grid
1624  // Note: generic grids can't handle sub-pixel lines without
1625  // either losing fine/course distinction or having some dots
1626  // fail to render
1627  float marker = std::fmax( 1.0f, m_gridLineWidth ) / m_worldScale;
1628  float doubleMarker = 2.0f * marker;
1629 
1630  // Draw axes if desired
1631  if( m_axesEnabled )
1632  {
1633  SetLineWidth( marker );
1634  drawAxes( worldStartPoint, worldEndPoint );
1635  }
1636 
1637  if( !m_gridVisibility || m_gridSize.x == 0 || m_gridSize.y == 0 )
1638  return;
1639 
1640  VECTOR2D gridScreenSize( m_gridSize );
1641 
1642  double gridThreshold = KiROUND( computeMinGridSpacing() / m_worldScale );
1643 
1645  gridThreshold *= 2.0;
1646 
1647  // If we cannot display the grid density, scale down by a tick size and
1648  // try again. Eventually, we get some representation of the grid
1649  while( std::min( gridScreenSize.x, gridScreenSize.y ) <= gridThreshold )
1650  {
1651  gridScreenSize = gridScreenSize * static_cast<double>( m_gridTick );
1652  }
1653 
1654  // Compute grid starting and ending indexes to draw grid points on the
1655  // visible screen area
1656  // Note: later any point coordinate will be offsetted by m_gridOrigin
1657  int gridStartX = KiROUND( ( worldStartPoint.x - m_gridOrigin.x ) / gridScreenSize.x );
1658  int gridEndX = KiROUND( ( worldEndPoint.x - m_gridOrigin.x ) / gridScreenSize.x );
1659  int gridStartY = KiROUND( ( worldStartPoint.y - m_gridOrigin.y ) / gridScreenSize.y );
1660  int gridEndY = KiROUND( ( worldEndPoint.y - m_gridOrigin.y ) / gridScreenSize.y );
1661 
1662  // Ensure start coordinate > end coordinate
1663  SWAP( gridStartX, >, gridEndX );
1664  SWAP( gridStartY, >, gridEndY );
1665 
1666  // Ensure the grid fills the screen
1667  --gridStartX;
1668  ++gridEndX;
1669  --gridStartY;
1670  ++gridEndY;
1671 
1672  // Draw the grid behind all other layers
1673  SetLayerDepth( m_depthRange.y * 0.75 );
1674 
1676  {
1677  // Now draw the grid, every coarse grid line gets the double width
1678 
1679  // Vertical lines
1680  for( int j = gridStartY; j <= gridEndY; j++ )
1681  {
1682  const double y = j * gridScreenSize.y + m_gridOrigin.y;
1683 
1684  if( m_axesEnabled && y == 0.0 )
1685  continue;
1686 
1687  SetLineWidth( ( j % m_gridTick ) ? marker : doubleMarker );
1688  drawGridLine( VECTOR2D( gridStartX * gridScreenSize.x + m_gridOrigin.x, y ),
1689  VECTOR2D( gridEndX * gridScreenSize.x + m_gridOrigin.x, y ) );
1690  }
1691 
1692  // Horizontal lines
1693  for( int i = gridStartX; i <= gridEndX; i++ )
1694  {
1695  const double x = i * gridScreenSize.x + m_gridOrigin.x;
1696 
1697  if( m_axesEnabled && x == 0.0 )
1698  continue;
1699 
1700  SetLineWidth( ( i % m_gridTick ) ? marker : doubleMarker );
1701  drawGridLine( VECTOR2D( x, gridStartY * gridScreenSize.y + m_gridOrigin.y ),
1702  VECTOR2D( x, gridEndY * gridScreenSize.y + m_gridOrigin.y ) );
1703  }
1704  }
1705  else // Dots or Crosses grid
1706  {
1707  m_lineWidthIsOdd = true;
1708  m_isStrokeEnabled = true;
1709 
1710  for( int j = gridStartY; j <= gridEndY; j++ )
1711  {
1712  bool tickY = ( j % m_gridTick == 0 );
1713 
1714  for( int i = gridStartX; i <= gridEndX; i++ )
1715  {
1716  bool tickX = ( i % m_gridTick == 0 );
1717  VECTOR2D pos{ i * gridScreenSize.x + m_gridOrigin.x,
1718  j * gridScreenSize.y + m_gridOrigin.y };
1719 
1721  {
1722  SetLineWidth( ( tickX && tickY ) ? doubleMarker : marker );
1723  drawGridCross( pos );
1724  }
1725  else if( m_gridStyle == GRID_STYLE::DOTS )
1726  {
1727  double doubleGridLineWidth = m_gridLineWidth * 2.0f;
1728  drawGridPoint( pos, ( tickX ) ? doubleGridLineWidth : m_gridLineWidth,
1729  ( tickY ) ? doubleGridLineWidth : m_gridLineWidth );
1730  }
1731  }
1732  }
1733  }
1734 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
void SetNegativeDrawMode(bool aSetting) override
Set negative draw mode in the renderer.
Definition: cairo_gal.cpp:934
wxWindow * m_parentWindow
Parent window.
Definition: cairo_gal.h:484
void initSurface()
Prepare Cairo surfaces for drawing.
Definition: cairo_gal.cpp:1474
unsigned char * m_wxOutput
wxImage compatible buffer
Definition: cairo_gal.h:488
void DrawBitmap(const BITMAP_BASE &aBitmap) override
Draw a bitmap image.
Definition: cairo_gal.cpp:475
std::map< int, GROUP > m_groups
List of graphic groups.
Definition: cairo_gal.h:331
Use lines for the grid.
void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
Definition: cairo_gal.cpp:543
bool m_isFillEnabled
Is filling of graphic objects enabled ?
CAIRO_GAL(GAL_DISPLAY_OPTIONS &aDisplayOptions, wxWindow *aParent, wxEvtHandler *aMouseListener=nullptr, wxEvtHandler *aPaintListener=nullptr, const wxString &aName=wxT("CairoCanvas"))
Definition: cairo_gal.cpp:1260
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void EndGroup() override
End the group.
Definition: cairo_gal.cpp:785
void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Change the color used to draw the group.
Definition: cairo_gal.cpp:885
void EndDrawing() override
End the drawing, needs to be called for every new frame.
Definition: cairo_gal.cpp:1334
void EndDiffLayer() override
Ends rendering of a differential layer.
Definition: cairo_gal.cpp:947
bool m_isInitialized
Are Cairo image & surface ready to use.
Definition: cairo_gal.h:494
double m_lineWidthInPixels
Definition: cairo_gal.h:335
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Handle updating display options.
Definition: cairo_gal.cpp:1568
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:236
bool m_axesEnabled
Should the axes be drawn.
void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
Definition: cairo_gal.cpp:1380
void deinitSurface()
Destroy Cairo surfaces when are not needed anymore.
Definition: cairo_gal.cpp:1495
void SetIsStroke(bool aIsStrokeEnabled) override
Enable/disable stroked outlines.
Definition: cairo_gal.cpp:578
double computeMinGridSpacing() const
compute minimum grid spacing from the grid settings
RENDER_TARGET m_currentTarget
Current rendering target.
Definition: cairo_gal.h:480
MATRIX3x3D m_screenWorldMatrix
Screen transformation.
void EnableDepthTest(bool aEnabled=false) override
Definition: cairo_gal.cpp:972
void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Change the depth (Z-axis position) of the group.
Definition: cairo_gal.cpp:902
void onPaint(wxPaintEvent &aEvent)
Paint event handler.
Definition: cairo_gal.cpp:1554
std::deque< GROUP_ELEMENT > GROUP
A graphic group type definition.
Definition: cairo_gal.h:326
~CAIRO_GAL()
Return true if the GAL canvas is visible on the screen.
Definition: cairo_gal.cpp:1314
bool IsFlippedX() const
Return true if flip flag for the X axis is set.
void Translate(const VECTOR2D &aTranslation) override
Translate the context.
Definition: cairo_gal.cpp:689
VECTOR2D ToScreen(const VECTOR2D &aPoint) const
Compute the point position in screen coordinates from given world coordinates.
CAIRO_GAL_BASE(GAL_DISPLAY_OPTIONS &aDisplayOptions)
Definition: cairo_gal.cpp:49
int color
Definition: DXF_plotter.cpp:57
void setCompositor()
Prepare the compositor.
Definition: cairo_gal.cpp:1538
void storePath()
Store the actual path.
Definition: cairo_gal.cpp:1106
VECTOR2D m_gridSize
The grid size.
wxImage * GetImageData()
Definition: bitmap_base.h:70
unsigned int m_savedBuffer
Handle to buffer to restore after rendering to temp buffer.
Definition: cairo_gal.h:479
GROUP * m_currentGroup
Currently used group.
Definition: cairo_gal.h:333
Type definition for an graphics group element.
Definition: cairo_gal.h:315
static const COLOR4D BLACK
Definition: color4d.h:387
void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
Definition: cairo_gal.cpp:909
double g
Green component.
Definition: color4d.h:378
unsigned int m_tempBuffer
Handle to the temp buffer.
Definition: cairo_gal.h:478
void BeginDrawing() override
Start/end drawing functions, draw calls can be only made in between the calls to BeginDrawing()/EndDr...
Definition: cairo_gal.cpp:1320
unsigned char * m_bitmapBuffer
Storage of the Cairo image.
Definition: cairo_gal.h:491
KICURSOR
Definition: cursors.h:33
union KIGFX::CAIRO_GAL_BASE::GROUP_ELEMENT::@26 m_Argument
void PostPaint(wxPaintEvent &aEvent)
Post an event to m_paint_listener.
Definition: cairo_gal.cpp:1372
void drawAxes(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Definition: cairo_gal.cpp:1009
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
int PointCount() const
Return the number of points (vertices) in this line chain.
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
cairo_matrix_t m_cairoWorldScreenMatrix
Cairo world to screen transform matrix.
Definition: cairo_gal.h:338
Enable/disable filling.
Definition: cairo_gal.h:298
void SetLayerDepth(double aLayerDepth) override
Set the depth of the layer (position on the z-axis)
Definition: cairo_gal.cpp:648
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
unsigned int m_groupCounter
Counter used for generating group keys.
Definition: cairo_gal.h:332
int m_gridTick
Every tick line gets the double width.
unsigned int m_bufferSize
Size of buffers cairoOutput, bitmapBuffers.
Definition: cairo_gal.h:487
float m_gridLineWidth
Line width of the grid.
const double angle_xform(const double aAngle)
Transform according to the rotation from m_currentWorld2Screen transform matrix.
Definition: cairo_gal.cpp:127
MATRIX3x3D m_worldScreenMatrix
World transformation.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
double b
Blue component.
Definition: color4d.h:379
Class that handles multitarget rendering (ie.
Auxiliary rendering target (noncached)
Definition: definitions.h:49
T m_data[3][3]
Definition: matrix3x3.h:64
COLOR4D m_gridColor
Color of the grid.
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:51
void ClearCache() override
Delete all data created during caching of graphic items.
Definition: cairo_gal.cpp:927
double m_worldScale
The scale factor world->screen.
void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: cairo_gal.cpp:302
CAIRO_ANTIALIASING_MODE cairo_antialiasing_mode
static double roundp(double x)
Definition: cairo_gal.cpp:183
void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: cairo_gal.cpp:236
VECTOR2D m_cursorPosition
Current cursor position (world coordinates)
GAL_DISPLAY_OPTIONS & m_options
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void drawGridPoint(const VECTOR2D &aPoint, double aWidth, double aHeight)
Definition: cairo_gal.cpp:1062
void ClearScreen() override
Clear the screen.
Definition: cairo_gal.cpp:555
bool m_isElementAdded
Was an graphic element added ?
Definition: cairo_gal.h:330
void SetGridColor(const COLOR4D &aGridColor)
Set the grid color.
void EndDrawing() override
End the drawing, needs to be called for every new frame.
Definition: cairo_gal.cpp:98
GRAPHICS_COMMAND m_Command
Command to execute.
Definition: cairo_gal.h:317
double a
Alpha component.
Definition: color4d.h:380
bool m_isStrokeEnabled
Are the outlines stroked ?
COLOR4D m_strokeColor
The color of the outlines.
void ClearTarget(RENDER_TARGET aTarget) override
Clear the target for rendering.
Definition: cairo_gal.cpp:1452
void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
Definition: cairo_gal.cpp:198
std::vector< cairo_matrix_t > m_xformStack
Definition: cairo_gal.h:348
VECTOR2< double > VECTOR2D
Definition: vector2d.h:622
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
bool IsClosed() const override
bool m_gridVisibility
Should the grid be shown.
Represent a set of closed polygons.
static const wxCursor GetCursor(KICURSOR aCursorType)
Definition: cursors.cpp:394
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
Definition: cairo_gal.h:103
wxCursor m_currentwxCursor
wxCursor showing the current native cursor
Definition: cairo_gal.h:496
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
cairo_t * m_currentContext
Currently used Cairo context for drawing.
Definition: cairo_gal.h:341
bool SetNativeCursorStyle(KICURSOR aCursor) override
Set the cursor in the native panel.
Definition: cairo_gal.cpp:1592
void updateWorldScreenMatrix()
Definition: cairo_gal.cpp:105
void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
Definition: cairo_gal.cpp:966
void onSetNativeCursor(wxSetCursorEvent &aEvent)
Give the correct cursor image when the native widget asks for it.
Definition: cairo_gal.cpp:1607
E_SERIE r
Definition: eserie.cpp:41
const double xform(double x)
Definition: cairo_gal.cpp:175
int m_stride
Stride value for Cairo.
Definition: cairo_gal.h:492
cairo_t * m_context
Cairo image.
Definition: cairo_gal.h:342
void SetTarget(RENDER_TARGET aTarget) override
Set the target for rendering.
Definition: cairo_gal.cpp:1422
void skipMouseEvent(wxMouseEvent &aEvent)
Mouse event handler, forwards the event to the child.
Definition: cairo_gal.cpp:1560
Use dots for the grid.
Use small cross instead of dots for the grid.
Save the transformation matrix.
Definition: cairo_gal.h:309
COLOR4D getCursorColor() const
Get the actual cursor color to draw.
void SetIsFill(bool aIsFillEnabled) override
Enable/disable fill.
Definition: cairo_gal.cpp:563
const VECTOR2D roundp(const VECTOR2D &v)
Definition: cairo_gal.cpp:189
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Handle updating display options.
bool m_validCompositor
Compositor initialization flag.
Definition: cairo_gal.h:481
cairo_matrix_t m_currentWorld2Screen
Definition: cairo_gal.h:340
virtual bool SetNativeCursorStyle(KICURSOR aCursor)
Set the cursor in the native panel.
void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: cairo_gal.cpp:318
void SetStrokeColor(const COLOR4D &aColor) override
Set the stroke color.
Definition: cairo_gal.cpp:593
void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: cairo_gal.cpp:418
void Restore() override
Restore the context.
Definition: cairo_gal.cpp:747
GRID_STYLE m_gridStyle
Grid display style.
bool Show(bool aShow) override
Show/hide the GAL canvas.
Definition: cairo_gal.cpp:1397
cairo_matrix_t m_currentXform
Definition: cairo_gal.h:339
void StartDiffLayer() override
Begins rendering of a differential layer.
Definition: cairo_gal.cpp:940
COLOR4D m_fillColor
The fill color.
int BeginGroup() override
Begin a group.
Definition: cairo_gal.cpp:769
Definition: color4d.h:56
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
VECTOR2D m_depthRange
Range of the depth.
bool BoolArg
A bool argument.
Definition: cairo_gal.h:320
COLOR4D m_axesColor
Color of the axes.
const int scale
Main rendering target (cached)
Definition: definitions.h:48
void arc_angles_xform_and_normalize(double &aStartAngle, double &aEndAngle)
Transform according to the rotation from m_currentWorld2Screen transform matrix for the start angle a...
Definition: cairo_gal.cpp:141
wxEvtHandler * m_mouseListener
Mouse listener.
Definition: cairo_gal.h:485
RENDER_TARGET GetTarget() const override
Get the currently used target for rendering.
Definition: cairo_gal.cpp:1446
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void drawPoly(const std::deque< VECTOR2D > &aPointList)
Drawing polygons & polylines is the same in Cairo, so here is the common code.
Definition: cairo_gal.cpp:1172
void EndNegativesLayer() override
Ends rendering of a negatives layer and draws it to the main layer.
Definition: cairo_gal.cpp:960
void DrawGrid() override
Definition: cairo_gal.cpp:1613
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Translate the context.
Definition: cairo_gal.h:307
wxSize GetSizePixels() const
Definition: bitmap_base.h:124
void Save() override
Save the context.
Definition: cairo_gal.cpp:729
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
Temporary target for drawing in separate layer.
Definition: definitions.h:51
#define SWAP(varA, condition, varB)
Swap the variables if a condition is met.
Definition: definitions.h:31
void drawGridLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a grid line (usually a simplified line function).
Definition: cairo_gal.cpp:1027
unsigned int m_mainBuffer
Handle to the main buffer.
Definition: cairo_gal.h:476
bool m_fullscreenCursor
Shape of the cursor (fullscreen or small cross)
cairo_path_t * m_CairoPath
Pointer to a Cairo path.
Definition: cairo_gal.h:323
void SetLineWidth(float aLineWidth) override
Set the line width.
Definition: cairo_gal.cpp:629
std::shared_ptr< CAIRO_COMPOSITOR > m_compositor
Object for layers compositing.
Definition: cairo_gal.h:475
void Scale(const VECTOR2D &aScale) override
Scale the context.
Definition: cairo_gal.cpp:709
void deleteBitmaps()
Allocate the bitmaps for drawing.
Definition: cairo_gal.cpp:1528
void DrawGroup(int aGroupNumber) override
Draw the stored group.
Definition: cairo_gal.cpp:792
VECTOR2D m_gridOrigin
The grid origin.
void syncLineWidth(bool aForceWidth=false, double aWidth=0.0)
Definition: cairo_gal.cpp:212
double m_worldUnitLength
The unit length of the world coordinates [inch].
double r
Red component.
Definition: color4d.h:377
int BeginGroup() override
Begin a group.
Definition: cairo_gal.cpp:1408
double DblArg[MAX_CAIRO_ARGUMENTS]
Arguments for Cairo commands.
Definition: cairo_gal.h:319
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:46
void allocateBitmaps()
Allocate the bitmaps for drawing.
Definition: cairo_gal.cpp:1509
unsigned int m_overlayBuffer
Handle to the overlay buffer.
Definition: cairo_gal.h:477
void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
Definition: cairo_gal.cpp:655
bool IsCursorEnabled() const
Return information about cursor visibility.
VECTOR2I m_screenSize
Screen size in screen coordinates.
void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0) override
Draw a cubic bezier spline.
Definition: cairo_gal.cpp:453
void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle, double aWidth, double aMaxError) override
Draw an arc segment.
Definition: cairo_gal.cpp:354
KICURSOR m_currentNativeCursor
Current cursor.
float m_lineWidth
The line width.
void EndGroup() override
End the group.
Definition: cairo_gal.cpp:1415
cairo_surface_t * m_surface
Cairo surface.
Definition: cairo_gal.h:343
void BeginDrawing() override
Start/end drawing functions, draw calls can be only made in between the calls to BeginDrawing()/EndDr...
Definition: cairo_gal.cpp:92
virtual void SetTarget(RENDER_TARGET aTarget)
Set the target for rendering.
void Flush() override
Force all remaining objects to be drawn.
Definition: cairo_gal.cpp:549
std::vector< cairo_surface_t * > m_imageSurfaces
List of surfaces that were created by painting images, to be cleaned up later.
Definition: cairo_gal.h:346
int GetPPI() const
Definition: bitmap_base.h:135
Enable/disable stroking.
Definition: cairo_gal.h:299
unsigned int getNewGroupNumber()
Return a valid key that can be used as a new group number.
Definition: cairo_gal.cpp:1248
bool m_isGrouping
Is grouping enabled ?
Definition: cairo_gal.h:329
void blitCursor(wxMemoryDC &clientDC)
Blit cursor into the current screen.
Definition: cairo_gal.cpp:1155
Restore the transformation matrix.
Definition: cairo_gal.h:310
void SetFillColor(const COLOR4D &aColor) override
Set the fill color.
Definition: cairo_gal.cpp:611
void drawGridCross(const VECTOR2D &aPoint)
Definition: cairo_gal.cpp:1041
Abstract interface for drawing on a 2D-surface.
void Rotate(double aAngle) override
Rotate the context.
Definition: cairo_gal.cpp:670
static constexpr cairo_format_t GAL_FORMAT
Format used to store pixels.
Definition: cairo_gal.h:350
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
wxEvtHandler * m_paintListener
Paint listener.
Definition: cairo_gal.h:486
void StartNegativesLayer() override
Begins rendering in a new layer that will be copied to the main layer in EndNegativesLayer().
Definition: cairo_gal.cpp:953