PLplot  5.11.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
cairo.c
Go to the documentation of this file.
1 // June 2, 2007
2 //
3 // Graphics drivers that are based on the Cairo / Pango Libraries.
4 //
5 // Copyright (C) 2008 Hazen Babcock
6 // Copyright (C) 2009, 2010 Hezekiah M. Carty
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 //
25 
26 //--------------------------------------------------------------------------
27 // Header files
28 //--------------------------------------------------------------------------
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <math.h>
33 
34 #include <cairo.h>
35 #include <pango/pangocairo.h>
36 
37 // PLplot header files (must occur before driver-dependent includes)
38 
39 #include "plDevs.h"
40 #include "plplotP.h"
41 #include "drivers.h"
42 
43 // Driver-dependent includes
44 #if defined ( PLD_wincairo )
45 #include <windows.h>
46 #include <cairo-win32.h>
47 #endif
48 #if defined ( PLD_xcairo )
49 #include <cairo-xlib.h>
50 #include <X11/X.h>
51 #include <X11/Xlib.h>
52 #include <X11/Xutil.h>
53 #include <X11/cursorfont.h>
54 #include <X11/keysym.h>
55 #endif
56 #if defined ( PLD_pdfcairo )
57 #include <cairo-pdf.h>
58 #endif
59 #if defined ( PLD_pscairo )
60 #include <cairo-ps.h>
61 #endif
62 #if defined ( PLD_svgcairo )
63 #include <cairo-svg.h>
64 #endif
65 
66 
67 //--------------------------------------------------------------------------
68 // Constants & global (to this file) variables
69 //--------------------------------------------------------------------------
70 
71 #define DPI 72
72 #define PLCAIRO_DEFAULT_X 720
73 #define PLCAIRO_DEFAULT_Y 540
74 
75 #define MAX_STRING_LEN 500
76 #define MAX_MARKUP_LEN MAX_STRING_LEN * 10
77 
78 static int text_clipping;
79 static int text_anti_aliasing;
81 static int external_drawable;
82 static int rasterize_image;
83 static int set_background;
84 static int image_buffering;
85 static int already_warned = 0;
86 
87 static DrvOpt cairo_options[] = { { "text_clipping", DRV_INT, &text_clipping, "Use text clipping (text_clipping=0|1)" },
88  { "text_anti_aliasing", DRV_INT, &text_anti_aliasing, "Set desired text anti-aliasing (text_anti_aliasing=0|1|2|3). The numbers are in the same order as the cairo_antialias_t enumeration documented at http://cairographics.org/manual/cairo-cairo-t.html#cairo-antialias-t)" },
89  { "graphics_anti_aliasing", DRV_INT, &graphics_anti_aliasing, "Set desired graphics anti-aliasing (graphics_anti_aliasing=0|1|2|3). The numbers are in the same order as the cairo_antialias_t enumeration documented at http://cairographics.org/manual/cairo-cairo-t.html#cairo-antialias-t" },
90  { "external_drawable", DRV_INT, &external_drawable, "Plot to external X drawable" },
91  { "rasterize_image", DRV_INT, &rasterize_image, "Raster or vector image rendering (rasterize_image=0|1)" },
92  { "set_background", DRV_INT, &set_background, "Set the background for the extcairo device (set_background=0|1). If 1 then the plot background will set by PLplot" },
93  { "image_buffering", DRV_INT, &image_buffering, "Buffered offscreen rendering for the xcairo device (image_buffering=0|1)." },
94  { NULL, DRV_INT, NULL, NULL } };
95 
96 typedef struct
97 {
98  cairo_surface_t *cairoSurface;
99  cairo_t *cairoContext;
100  cairo_surface_t *cairoSurface_raster;
108  double downscale;
110  short upDown;
111  float fontSize;
112  short uline;
113 
114  // These are arguments for plP_script_scale which must be retained
115  // in aStream for the alt_unicode approach. level has an
116  // identical meaning to upDown above, but it is incremented and
117  // decremented in plP_script_scale as well as other places in the
118  // code so the only safe thing to do is to treat level separately
119  // from upDown.
120  PLFLT old_sscale, sscale, old_soffset, soffset;
122 
123 #if defined ( PLD_xcairo )
124  cairo_surface_t *cairoSurface_X;
125  cairo_t *cairoContext_X;
126  short exit_event_loop;
127  Display *XDisplay;
128  Window XWindow;
129  unsigned int xdrawable_mode;
130 #endif
131 #if defined ( PLD_memcairo )
132  unsigned char *memory;
133  unsigned char *cairo_format_memory;
134  char bigendian;
135 #endif
136 #if defined ( PLD_wincairo )
137  cairo_surface_t *cairoSurface_win;
138  cairo_t *cairoContext_win;
139  WNDCLASSEX wndclass;
140  HWND hwnd;
141  MSG msg;
142  HDC hdc;
143  HDC SCRN_hdc;
144  COLORREF oldcolour;
145  RECT rect;
146 #endif
147 } PLCairo;
148 
150 #if defined ( PLD_xcairo )
151  "xcairo:Cairo X Windows Driver:1:cairo:100:xcairo\n"
152 #endif
153 #if defined ( PLD_pdfcairo )
154  "pdfcairo:Cairo PDF Driver:0:cairo:101:pdfcairo\n"
155 #endif
156 #if defined ( PLD_pscairo )
157  "pscairo:Cairo PS Driver:0:cairo:102:pscairo\n"
158 #endif
159 #if defined ( PLD_epscairo )
160  "epscairo:Cairo EPS Driver:0:cairo:103:epscairo\n"
161 #endif
162 #if defined ( PLD_svgcairo )
163  "svgcairo:Cairo SVG Driver:0:cairo:104:svgcairo\n"
164 #endif
165 #if defined ( PLD_pngcairo )
166  "pngcairo:Cairo PNG Driver:0:cairo:105:pngcairo\n"
167 #endif
168 #if defined ( PLD_memcairo )
169  "memcairo:Cairo Memory Driver:0:cairo:106:memcairo\n"
170 #endif
171 #if defined ( PLD_extcairo )
172  "extcairo:Cairo External Context Driver:0:cairo:107:extcairo\n"
173 #endif
174 #if defined ( PLD_wincairo )
175  "wincairo:Cairo Microscoft Windows Driver:0:cairo:108:wincairo\n"
176 #endif
177 ;
178 
179 //
180 // Structure for passing external drawables to xcairo devices via
181 // the PLESC_DEVINIT escape function.
182 //
183 #if defined ( PLD_xcairo )
184 typedef struct
185 {
186  Display *display;
187  Drawable drawable;
188 } PLXcairoDrawableInfo;
189 #endif
190 
191 //--------------------------------------------------------------------------
192 // Font style and weight lookup tables (copied
193 // from the psttf driver).
194 //--------------------------------------------------------------------------
195 
196 #define NPANGOLOOKUP 5
197 
199  "sans",
200  "serif",
201  "monospace",
202  "sans,serif",
203  "sans,serif"
204 };
205 
207  "PLPLOT_FREETYPE_SANS_FAMILY",
208  "PLPLOT_FREETYPE_SERIF_FAMILY",
209  "PLPLOT_FREETYPE_MONO_FAMILY",
210  "PLPLOT_FREETYPE_SCRIPT_FAMILY",
211  "PLPLOT_FREETYPE_SYMBOL_FAMILY"
212 };
213 
214 #define FAMILY_LOOKUP_LEN 1024
216 
217 #define TAG_LEN 200
218 
219 const char *weightLookup[2] = {
220  "normal",
221  "bold"
222 };
223 
224 const char *styleLookup[3] = {
225  "normal",
226  "italic",
227  "oblique"
228 };
229 
230 //--------------------------------------------------------------------------
231 //--------------------------------------------------------------------------
232 //
233 // That which is common to all the Cairo Drivers
234 //
235 //--------------------------------------------------------------------------
236 //--------------------------------------------------------------------------
237 
238 //--------------------------------------------------------------------------
239 // function declarations
240 //--------------------------------------------------------------------------
241 
242 // General
243 
245 cairo_status_t write_to_stream( void *, unsigned char *, unsigned int );
246 void set_clip( PLStream *pls );
248 
249 // String processing
250 
251 static void proc_str( PLStream *, EscText * );
252 static void text_begin_cairo( PLStream *pls, EscText *args );
253 static void text_char_cairo( PLStream *pls, EscText *args );
254 static void text_esc_cairo( PLStream *pls, EscText *args );
255 static void text_end_cairo( PLStream *pls, EscText *args );
256 static char *ucs4_to_pango_markup_format( PLUNICODE *, int, float );
257 static void open_span_tag( char *, PLUNICODE, float, int );
258 static void close_span_tag( char *, int );
259 static char *rise_span_tag( int, float, float, float );
260 
261 // Graphics
262 
263 static void set_current_context( PLStream * );
264 static void poly_line( PLStream *, short *, short *, PLINT );
265 static void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts );
266 static void gradient( PLStream *pls, short *xa, short *ya, PLINT npts );
267 static void arc( PLStream *, arc_struct * );
268 static void rotate_cairo_surface( PLStream *, float, float, float, float, float, float, PLBOOL );
269 static void blit_to_x( PLStream *pls, double x, double y, double w, double h );
270 // Rasterization of plotted material
271 static void start_raster( PLStream* );
272 static void end_raster( PLStream* );
273 // Get/set drawing mode
274 static void set_mode( PLStream*, PLINT* );
275 static void get_mode( PLStream*, PLINT* );
276 // Get / set line properties
277 void get_line_properties( PLCairo *aStream, cairo_line_join_t *join, cairo_line_cap_t *cap );
278 void set_line_properties( PLCairo *aStream, cairo_line_join_t join, cairo_line_cap_t cap );
279 
280 
281 // PLplot interface functions
282 
283 // general
284 void plD_bop_cairo( PLStream * );
285 void plD_eop_cairo( PLStream * );
286 void plD_state_cairo( PLStream *, PLINT );
287 void plD_esc_cairo( PLStream *, PLINT, void * );
288 void plD_tidy_cairo( PLStream * );
289 void plD_line_cairo( PLStream *, short, short, short, short );
290 void plD_polyline_cairo( PLStream *, short *, short *, PLINT );
291 
292 //--------------------------------------------------------------------------
293 // start_raster()
294 //
295 // Set up off-screen rasterized rendering
296 //--------------------------------------------------------------------------
297 
299 {
300  PLCairo *aStream;
301  cairo_surface_t *tmp_sfc;
302  cairo_t *tmp_context;
303 
304  aStream = (PLCairo *) pls->dev;
305 
306  // Do not use the external surface if the user says not to
307  if ( !aStream->rasterize_image )
308  return;
309 
310  // Create an image surface and context for the offscreen rendering
311  aStream->cairoSurface_raster =
312  //
313  // cairo_surface_create_similar( aStream->cairoSurface,
314  // CAIRO_CONTENT_COLOR,
315  // pls->xlength, pls->ylength );
316  //
317  cairo_image_surface_create( CAIRO_FORMAT_ARGB32,
318  pls->xlength, pls->ylength );
319  aStream->cairoContext_raster = cairo_create( aStream->cairoSurface_raster );
320 
321  // Disable antialiasing for the raster surface. The output seems to look
322  // better that way.
323  cairo_set_antialias( aStream->cairoContext_raster, CAIRO_ANTIALIAS_NONE );
324 
325  // Swap the raster and main plot surfaces and contexts
326  tmp_sfc = aStream->cairoSurface;
327  tmp_context = aStream->cairoContext;
328  aStream->cairoSurface = aStream->cairoSurface_raster;
329  aStream->cairoContext = aStream->cairoContext_raster;
330  // Save the main plot surface and context for when we are finished
331  aStream->cairoSurface_raster = tmp_sfc;
332  aStream->cairoContext_raster = tmp_context;
333 }
334 
335 //--------------------------------------------------------------------------
336 // end_raster()
337 //
338 // Finish off-screen rasterized rendering and copy the result on to the
339 // main plot surface.
340 //--------------------------------------------------------------------------
341 
343 {
344  PLCairo *aStream;
345  cairo_surface_t *tmp_sfc;
346  cairo_t *tmp_context;
347 
348  aStream = (PLCairo *) pls->dev;
349 
350  // TODO FIXME: This should really only copy the used portion of the
351  // offscreen pixmap.
352 
353  // Do not use the external surface if the user says not to
354  if ( !aStream->rasterize_image )
355  return;
356 
357  // Some Cairo devices support delayed device setup (eg: xcairo with
358  // external drawable and extcairo with an external context).
359  if ( aStream->cairoContext == NULL )
360  plexit( "Can not plot to a Cairo device with no context" );
361 
362  // Restore the main plot surface and context for future plotting
363  tmp_sfc = aStream->cairoSurface;
364  tmp_context = aStream->cairoContext;
365  aStream->cairoSurface = aStream->cairoSurface_raster;
366  aStream->cairoContext = aStream->cairoContext_raster;
367  aStream->cairoSurface_raster = tmp_sfc;
368  aStream->cairoContext_raster = tmp_context;
369 
370  // Blit the raster surface on to the main plot
371  cairo_set_source_surface( aStream->cairoContext, aStream->cairoSurface_raster, 0.0, 0.0 );
372  cairo_paint( aStream->cairoContext );
373 
374  // Free the now extraneous surface and context
375  cairo_destroy( aStream->cairoContext_raster );
376  cairo_surface_destroy( aStream->cairoSurface_raster );
377 }
378 
379 //--------------------------------------------------------------------------
380 // plD_bop_cairo()
381 //
382 // Set up for the next page.
383 //--------------------------------------------------------------------------
384 
386 {
387  PLCairo *aStream;
388 
389  aStream = (PLCairo *) pls->dev;
390 
391  // Some Cairo devices support delayed device setup (eg: xcairo with
392  // external drawable and extcairo with an external context).
393  if ( aStream->cairoContext == NULL )
394  return;
395 
396  // Fill in the window with the background color.
397  cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
398  if ( (double) pls->cmap0[0].a < 1.0 )
399  {
400  cairo_set_source_rgba( aStream->cairoContext, 1.0, 1.0, 1.0, 1.0 );
401  cairo_fill_preserve( aStream->cairoContext );
402  }
403  cairo_set_source_rgba( aStream->cairoContext,
404  (double) pls->cmap0[0].r / 255.0,
405  (double) pls->cmap0[0].g / 255.0,
406  (double) pls->cmap0[0].b / 255.0,
407  (double) pls->cmap0[0].a );
408  cairo_fill( aStream->cairoContext );
409 }
410 
411 //--------------------------------------------------------------------------
412 // plD_line_cairo()
413 //
414 // Draw a line in the current color from (x1,y1) to (x2,y2).
415 //--------------------------------------------------------------------------
416 
417 //--------------------------------------------------------------------------
418 // (get|set)_line_properties
419 //
420 // (Get|Set) the current Cairo line drawing properties.
421 //--------------------------------------------------------------------------
422 void get_line_properties( PLCairo *aStream, cairo_line_join_t *join, cairo_line_cap_t *cap )
423 {
424  *join = cairo_get_line_join( aStream->cairoContext );
425  *cap = cairo_get_line_cap( aStream->cairoContext );
426 }
427 
428 void set_line_properties( PLCairo *aStream, cairo_line_join_t join, cairo_line_cap_t cap )
429 {
430  cairo_set_line_join( aStream->cairoContext, join );
431  cairo_set_line_cap( aStream->cairoContext, cap );
432 }
433 
434 void plD_line_cairo( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
435 {
436  PLCairo *aStream;
437 
438  aStream = (PLCairo *) pls->dev;
439 
440  set_current_context( pls );
441 
442  cairo_save( aStream->cairoContext );
443 
444  set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_ROUND );
445 
446  cairo_move_to( aStream->cairoContext, aStream->downscale * (double) x1a, aStream->downscale * (double) y1a );
447  cairo_line_to( aStream->cairoContext, aStream->downscale * (double) x2a, aStream->downscale * (double) y2a );
448 
449  cairo_stroke( aStream->cairoContext );
450 
451  cairo_restore( aStream->cairoContext );
452 }
453 
454 //--------------------------------------------------------------------------
455 // plD_polyline_cairo()
456 //
457 // Draw a polyline in the current color.
458 //--------------------------------------------------------------------------
459 
460 void plD_polyline_cairo( PLStream *pls, short *xa, short *ya, PLINT npts )
461 {
462  PLCairo *aStream;
463 
464  aStream = (PLCairo *) pls->dev;
465 
466  cairo_save( aStream->cairoContext );
467 
468  set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
469 
470  poly_line( pls, xa, ya, npts );
471 
472  cairo_stroke( aStream->cairoContext );
473 
474  cairo_restore( aStream->cairoContext );
475 }
476 
477 //--------------------------------------------------------------------------
478 // plD_eop_cairo()
479 //
480 // Generic end of page.
481 //--------------------------------------------------------------------------
482 
484 {
485  PLCairo *aStream;
486 
487  aStream = (PLCairo *) pls->dev;
488 
489  cairo_show_page( aStream->cairoContext );
490 }
491 
492 //--------------------------------------------------------------------------
493 // plD_tidy_cairo()
494 //
495 // General: Close graphics file or otherwise clean up.
496 //--------------------------------------------------------------------------
497 
499 {
500  PLCairo *aStream;
501 
502  aStream = (PLCairo *) pls->dev;
503 
504  // Free the cairo context and surface.
505  cairo_destroy( aStream->cairoContext );
506  cairo_surface_destroy( aStream->cairoSurface );
507 
508  plCloseFile( pls );
509 }
510 
511 //--------------------------------------------------------------------------
512 // plD_state_cairo()
513 //
514 // Handle change in PLStream state (color, pen width, fill attribute, etc).
515 //
516 // Nothing is done here because these attributes are acquired from
517 // PLStream for each element that is drawn.
518 //--------------------------------------------------------------------------
519 
521 {
522 }
523 
524 //--------------------------------------------------------------------------
525 // plD_esc_cairo()
526 //
527 // Generic escape function.
528 //--------------------------------------------------------------------------
529 
530 void plD_esc_cairo( PLStream *pls, PLINT op, void *ptr )
531 {
532  //PLCairo *aStream;
533 
534  //aStream = (PLCairo *) pls->dev;
535 
536  switch ( op )
537  {
538  case PLESC_FILL: // filled polygon
539  filled_polygon( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
540  break;
541  case PLESC_GRADIENT: // render a gradient within a polygon.
542  gradient( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
543  break;
544  case PLESC_HAS_TEXT:
545  if ( !pls->alt_unicode )
546  {
547  proc_str( pls, (EscText *) ptr );
548  }
549  break;
550  case PLESC_BEGIN_TEXT: // get ready to get a handle a string of text
551  text_begin_cairo( pls, (EscText *) ptr );
552  break;
553  case PLESC_TEXT_CHAR: // handle a character of text to display
554  text_char_cairo( pls, (EscText *) ptr );
555  break;
556  case PLESC_CONTROL_CHAR: // handle a control character (super/subscript of fontchange)
557  text_esc_cairo( pls, (EscText *) ptr );
558  break;
559  case PLESC_END_TEXT: // finish a string of text
560  text_end_cairo( pls, (EscText *) ptr );
561  break;
562  case PLESC_START_RASTERIZE: // Start offscreen/rasterized rendering
563  start_raster( pls );
564  break;
565  case PLESC_END_RASTERIZE: // End offscreen/rasterized rendering
566  end_raster( pls );
567  break;
568  case PLESC_ARC: // Draw an arc, either filled or outline
569  arc( pls, (arc_struct *) ptr );
570  break;
571  case PLESC_MODESET: // Set drawing mode
572  set_mode( pls, (int *) ptr );
573  break;
574  case PLESC_MODEGET: // Get drawing mode
575  get_mode( pls, (int *) ptr );
576  break;
577  }
578 }
579 
580 
581 //--------------------------------------------------------------------------
582 // set_mode
583 //
584 // Set drawing mode.
585 //--------------------------------------------------------------------------
586 void set_mode( PLStream *pls, PLINT *mode )
587 {
588  PLCairo *aStream;
589 
590  aStream = (PLCairo *) pls->dev;
591 
592  switch ( *mode )
593  {
594  case PL_DRAWMODE_UNKNOWN: // Invalid - do nothing
595  break;
596  case PL_DRAWMODE_DEFAULT:
597  cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_OVER );
598  break;
599  case PL_DRAWMODE_REPLACE:
600  cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_SOURCE );
601  break;
602  case PL_DRAWMODE_XOR:
603  cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_XOR );
604  break;
605  }
606  return;
607 }
608 
609 //--------------------------------------------------------------------------
610 // get_mode
611 //
612 // Get drawing mode.
613 //--------------------------------------------------------------------------
614 void get_mode( PLStream *pls, PLINT *mode )
615 {
616  PLCairo *aStream;
617  cairo_operator_t op;
618 
619  aStream = (PLCairo *) pls->dev;
620 
621  op = cairo_get_operator( aStream->cairoContext );
622 
623  switch ( op )
624  {
625  case CAIRO_OPERATOR_OVER:
626  *mode = PL_DRAWMODE_DEFAULT;
627  break;
628  case CAIRO_OPERATOR_SOURCE:
629  *mode = PL_DRAWMODE_REPLACE;
630  break;
631  case CAIRO_OPERATOR_XOR:
632  *mode = PL_DRAWMODE_XOR;
633  break;
634  default:
635  *mode = PL_DRAWMODE_UNKNOWN;
636  }
637  return;
638 }
639 
640 //--------------------------------------------------------------------------
641 // text_begin_cairo()
642 //
643 // Begin text.
644 //--------------------------------------------------------------------------
645 
647 {
648  PLCairo *aStream;
649 
650  aStream = (PLCairo *) pls->dev;
651  aStream->upDown = 0;
652  aStream->uline = 0;
653  aStream->level = 0;
654  aStream->pangoMarkupString = (char *) malloc( sizeof ( char ) * MAX_MARKUP_LEN );
655  // Calculate the font size (in points since DPI = 72).
656  aStream->fontSize = (float) ( pls->chrht * DPI / 25.4 );
657 
658  // Initialize the markup string array
659  memset( aStream->pangoMarkupString, 0, MAX_MARKUP_LEN );
660 
661  open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, 0 );
662 }
663 
664 //--------------------------------------------------------------------------
665 // text_char_cairo()
666 //
667 // Add text.
668 //--------------------------------------------------------------------------
669 
671 {
672  char utf8[5];
673  PLCairo *aStream;
674 
675  aStream = (PLCairo *) pls->dev;
676  // make sure we are not too close to the end of the string
677  if ( strlen( aStream->pangoMarkupString ) < ( MAX_MARKUP_LEN - 50 ) )
678  {
679  switch ( args->n_char )
680  {
681  case 38:
682  strncat( aStream->pangoMarkupString, "&#38;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
683  break;
684  case 60:
685  strncat( aStream->pangoMarkupString, "&#60;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
686  break;
687  case 62:
688  strncat( aStream->pangoMarkupString, "&#62;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
689  break;
690  default:
691  ucs4_to_utf8( args->n_char, utf8 );
692  strncat( aStream->pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
693  break;
694  }
695  }
696 }
697 
698 //--------------------------------------------------------------------------
699 // text_esc_cairo()
700 //
701 // A font change, superscript, subscript, etc...
702 //--------------------------------------------------------------------------
703 
705 {
706  PLCairo *aStream;
707 
708  aStream = (PLCairo *) pls->dev;
709  switch ( args->n_ctrl_char )
710  {
711  case PLTEXT_FONTCHANGE:
712  close_span_tag( aStream->pangoMarkupString, aStream->upDown );
713  open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, aStream->upDown );
714  break;
715  case PLTEXT_SUPERSCRIPT:
716  if ( aStream->upDown < 0 )
717  {
718  strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
719  aStream->level++;
720  }
721  else
722  {
723  plP_script_scale( TRUE, &aStream->level,
724  &aStream->old_sscale, &aStream->sscale, &aStream->old_soffset, &aStream->soffset );
725  strncat( aStream->pangoMarkupString,
726  rise_span_tag( TRUE, aStream->fontSize, (float) aStream->sscale, (float) aStream->soffset ),
727  MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
728  }
729  aStream->upDown++;
730  break;
731  case PLTEXT_SUBSCRIPT:
732  if ( aStream->upDown > 0 )
733  {
734  strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
735  aStream->level--;
736  }
737  else
738  {
739  plP_script_scale( FALSE, &aStream->level,
740  &aStream->old_sscale, &aStream->sscale, &aStream->old_soffset, &aStream->soffset );
741  strncat( aStream->pangoMarkupString,
742  rise_span_tag( FALSE, aStream->fontSize, (float) aStream->sscale, (float) aStream->soffset ),
743  MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
744  }
745  aStream->upDown--;
746  break;
747  case PLTEXT_UNDERLINE:
748  if ( aStream->uline == 1 )
749  {
750  strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
751  aStream->level++;
752  }
753  else
754  {
755  strncat( aStream->pangoMarkupString, "<span underline=\"single\">", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
756  aStream->level++;
757  }
758  aStream->uline = !aStream->uline;
759  break;
760  case PLTEXT_BACKCHAR:
761  case PLTEXT_OVERLINE:
762  plwarn( "'-', and 'b/B' text escape sequences not processed." );
763  break;
764  }
765 }
766 
767 //--------------------------------------------------------------------------
768 // text_end_cairo()
769 //
770 // Draw the text and clean up.
771 //--------------------------------------------------------------------------
772 
774 {
775  int textXExtent, textYExtent, baseline;
776  PLFLT rotation, shear, stride, cos_rot, sin_rot, cos_shear, sin_shear;
777  cairo_matrix_t *cairoTransformMatrix;
778  cairo_font_options_t *cairoFontOptions;
779  PangoContext *context;
780  PangoLayout *layout;
781  PLCairo *aStream;
782 
783  aStream = (PLCairo *) pls->dev;
784 
785  set_current_context( pls );
786 
787  // Close the last span tag.
788  close_span_tag( aStream->pangoMarkupString, aStream->upDown );
789 
790  // printf("%s\n", aStream->pangoMarkupString);
791 
792  // Create the Pango text layout so we can figure out how big it is
793  layout = pango_cairo_create_layout( aStream->cairoContext );
794  pango_layout_set_markup( layout, aStream->pangoMarkupString, -1 );
795  pango_layout_get_pixel_size( layout, &textXExtent, &textYExtent );
796  baseline = pango_layout_get_baseline( layout );
797 
798  // If asked, set the string length (in mm) and return
799  if ( pls->get_string_length )
800  {
801  pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
802  }
803  else
804  {
805  // Set font aliasing
806  context = pango_layout_get_context( layout );
807  cairoFontOptions = cairo_font_options_create();
808  cairo_font_options_set_antialias( cairoFontOptions, aStream->text_anti_aliasing );
809  pango_cairo_context_set_font_options( context, cairoFontOptions );
810  pango_layout_context_changed( layout );
811  cairo_font_options_destroy( cairoFontOptions );
812 
813  // Save current transform matrix & clipping region
814  cairo_save( aStream->cairoContext );
815 
816  // Set up the clipping region if we are doing text clipping
817  if ( aStream->text_clipping )
818  {
819  set_clip( pls );
820  }
821 
822  // Move to the string reference point
823  cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
824 
825  // Invert the coordinate system so that the text is drawn right side up
826  cairoTransformMatrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
827  cairo_matrix_init( cairoTransformMatrix, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
828  cairo_transform( aStream->cairoContext, cairoTransformMatrix );
829 
830  // Extract rotation angle and shear from the PLplot tranformation matrix.
831  // Compute sines and cosines of the angles as an optimization.
832  plRotationShear( args->xform, &rotation, &shear, &stride );
833  rotation -= pls->diorot * PI / 2.0;
834  cos_rot = cos( rotation );
835  sin_rot = sin( rotation );
836  cos_shear = cos( shear );
837  sin_shear = sin( shear );
838 
839  // Apply the transform matrix
840  cairo_matrix_init( cairoTransformMatrix,
841  cos_rot * stride,
842  -sin_rot * stride,
843  cos_rot * sin_shear + sin_rot * cos_shear,
844  -sin_rot * sin_shear + cos_rot * cos_shear,
845  0, 0 );
846  cairo_transform( aStream->cairoContext, cairoTransformMatrix );
847  free( cairoTransformMatrix );
848 
849  // Move to the text starting point
850  // printf("baseline %d %d\n", baseline, textYExtent);
851  cairo_rel_move_to( aStream->cairoContext,
852  (double) ( -1.0 * args->just * (double) textXExtent ),
853  (double) 0.5 * aStream->fontSize - baseline / 1024.0 );
854 
855  // Render the text
856  pango_cairo_show_layout( aStream->cairoContext, layout );
857 
858  // Restore the transform matrix to its state prior to the text transform.
859  cairo_restore( aStream->cairoContext );
860  }
861 
862  // Free the layout object and the markup string
863  g_object_unref( layout );
864  free( aStream->pangoMarkupString );
865 }
866 
867 //--------------------------------------------------------------------------
868 // proc_str()
869 //
870 // Processes strings for display.
871 //--------------------------------------------------------------------------
872 
873 void proc_str( PLStream *pls, EscText *args )
874 {
875  float fontSize;
876  int textXExtent, textYExtent, baseline;
877  char *textWithPangoMarkup;
878  PLFLT rotation, shear, stride, cos_rot, sin_rot, cos_shear, sin_shear;
879  cairo_matrix_t *cairoTransformMatrix;
880  cairo_font_options_t *cairoFontOptions;
881  PangoContext *context;
882  PangoLayout *layout;
883  PLCairo *aStream;
884 
885  aStream = (PLCairo *) pls->dev;
886 
887  set_current_context( pls );
888 
889  // Check that we got unicode, warning message and return if not
890  if ( args->unicode_array_len == 0 )
891  {
892  printf( "Non unicode string passed to a cairo driver, ignoring\n" );
893  return;
894  }
895 
896  // Check that unicode string isn't longer then the max we allow
897  if ( args->unicode_array_len >= MAX_STRING_LEN )
898  {
899  printf( "Sorry, the cairo drivers only handles strings of length < %d\n", MAX_STRING_LEN );
900  return;
901  }
902 
903  // Calculate the font size (in points since DPI = 72).
904  fontSize = (float) ( pls->chrht * DPI / 25.4 );
905 
906  // Convert the escape characters into the appropriate Pango markup
907  textWithPangoMarkup = ucs4_to_pango_markup_format( args->unicode_array, args->unicode_array_len, fontSize );
908 
909  // Create the Pango text layout so we can figure out how big it is
910  layout = pango_cairo_create_layout( aStream->cairoContext );
911  pango_layout_set_markup( layout, textWithPangoMarkup, -1 );
912  pango_layout_get_pixel_size( layout, &textXExtent, &textYExtent );
913  baseline = pango_layout_get_baseline( layout );
914 
915  // If asked, set the string length (in mm) and return
916  if ( pls->get_string_length )
917  {
918  pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
919  return;
920  }
921 
922  // Set font aliasing
923  context = pango_layout_get_context( layout );
924  cairoFontOptions = cairo_font_options_create();
925  cairo_font_options_set_antialias( cairoFontOptions, aStream->text_anti_aliasing );
926  pango_cairo_context_set_font_options( context, cairoFontOptions );
927  pango_layout_context_changed( layout );
928  cairo_font_options_destroy( cairoFontOptions );
929 
930  // Save current transform matrix & clipping region
931  cairo_save( aStream->cairoContext );
932 
933  // Set up the clipping region if we are doing text clipping
934  if ( aStream->text_clipping )
935  {
936  set_clip( pls );
937  }
938 
939  // Move to the string reference point
940  cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
941 
942  // Invert the coordinate system so that the text is drawn right side up
943  cairoTransformMatrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
944  cairo_matrix_init( cairoTransformMatrix, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
945  cairo_transform( aStream->cairoContext, cairoTransformMatrix );
946 
947  // Extract rotation angle and shear from the PLplot tranformation matrix.
948  // Compute sines and cosines of the angles as an optimization.
949  plRotationShear( args->xform, &rotation, &shear, &stride );
950  rotation -= pls->diorot * PI / 2.0;
951  cos_rot = cos( rotation );
952  sin_rot = sin( rotation );
953  cos_shear = cos( shear );
954  sin_shear = sin( shear );
955 
956  // Apply the transform matrix
957  cairo_matrix_init( cairoTransformMatrix,
958  cos_rot * stride,
959  -sin_rot * stride,
960  cos_rot * sin_shear + sin_rot * cos_shear,
961  -sin_rot * sin_shear + cos_rot * cos_shear,
962  0, 0 );
963  cairo_transform( aStream->cairoContext, cairoTransformMatrix );
964  free( cairoTransformMatrix );
965 
966  // printf("baseline (ps) %d %d %f\n", baseline, textYExtent, aStream->fontSize);
967  // Move to the text starting point
968  cairo_rel_move_to( aStream->cairoContext,
969  (double) ( -1.0 * args->just * (double) textXExtent ),
970  (double) 0.5 * fontSize - baseline / 1024.0 );
971 
972  // Render the text
973  pango_cairo_show_layout( aStream->cairoContext, layout );
974 
975  // Restore the transform matrix to its state prior to the text transform.
976  cairo_restore( aStream->cairoContext );
977 
978  // Free the layout object and the markup string.
979  g_object_unref( layout );
980  free( textWithPangoMarkup );
981 }
982 
983 //--------------------------------------------------------------------------
984 // ucs4_to_pango_markup_format()
985 //
986 // Converts the plplot string (in ucs4) to a utf8 string that includes
987 // pango markup.
988 //
989 // http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html
990 //--------------------------------------------------------------------------
991 
992 char *ucs4_to_pango_markup_format( PLUNICODE *ucs4, int ucs4Len, float fontSize )
993 {
994  char plplotEsc;
995  int i;
996  int upDown = 0;
997  PLUNICODE fci;
998  char utf8[5];
999  char *pangoMarkupString;
1000  PLFLT old_sscale, sscale, old_soffset, soffset;
1001  PLINT level = 0;
1002  short uline = 0;
1003 
1004  // Will this be big enough? We might have lots of markup.
1005  pangoMarkupString = (char *) malloc( sizeof ( char ) * MAX_MARKUP_LEN );
1006  for ( i = 0; i < MAX_MARKUP_LEN; i++ )
1007  {
1008  pangoMarkupString[i] = 0;
1009  }
1010 
1011  // Get PLplot escape character
1012  plgesc( &plplotEsc );
1013 
1014  // Get the curent font and open the first span tag
1015  plgfci( &fci );
1016  open_span_tag( pangoMarkupString, fci, fontSize, 0 );
1017 
1018  // Parse the string to generate the tags
1019  i = 0;
1020  while ( i < ucs4Len )
1021  {
1022  // Try to avoid going off the end of the string
1023  if ( strlen( pangoMarkupString ) > ( MAX_MARKUP_LEN - 50 ) )
1024  {
1025  continue;
1026  }
1027  if ( ucs4[i] < PL_FCI_MARK ) // not a font change
1028  {
1029  if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
1030  { // we have to handle "<", ">" and "&" separately since they throw off the XML
1031  switch ( ucs4[i] )
1032  {
1033  case 38:
1034  strncat( pangoMarkupString, "&#38;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1035  break;
1036  case 60:
1037  strncat( pangoMarkupString, "&#60;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1038  break;
1039  case 62:
1040  strncat( pangoMarkupString, "&#62;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1041  break;
1042  default:
1043  ucs4_to_utf8( ucs4[i], utf8 );
1044  strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1045  break;
1046  }
1047  i++;
1048  continue;
1049  }
1050  i++;
1051  if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
1052  {
1053  ucs4_to_utf8( ucs4[i], utf8 );
1054  strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1055  i++;
1056  continue;
1057  }
1058  else
1059  {
1060  if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
1061  {
1062  if ( upDown < 0 )
1063  {
1064  strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1065  level++;
1066  }
1067  else
1068  {
1069  plP_script_scale( TRUE, &level,
1070  &old_sscale, &sscale, &old_soffset, &soffset );
1071  strncat( pangoMarkupString,
1072  rise_span_tag( TRUE, fontSize, (float) sscale, (float) soffset ),
1073  MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1074  }
1075  upDown++;
1076  }
1077  if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
1078  {
1079  if ( upDown > 0 )
1080  {
1081  strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1082  level--;
1083  }
1084  else
1085  {
1086  plP_script_scale( FALSE, &level,
1087  &old_sscale, &sscale, &old_soffset, &soffset );
1088  strncat( pangoMarkupString,
1089  rise_span_tag( FALSE, fontSize, (float) sscale, (float) soffset ),
1090  MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1091  }
1092  upDown--;
1093  }
1094  if ( ucs4[i] == (PLUNICODE) '-' ) // Superscript
1095  {
1096  if ( uline == 1 )
1097  {
1098  strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1099  level++;
1100  }
1101  else
1102  {
1103  strncat( pangoMarkupString,
1104  "<span underline=\"single\">",
1105  MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1106  }
1107  uline = uline;
1108  }
1109  i++;
1110  }
1111  }
1112  else // a font change
1113  {
1114  close_span_tag( pangoMarkupString, upDown );
1115  open_span_tag( pangoMarkupString, ucs4[i], fontSize, upDown );
1116  i++;
1117  }
1118  }
1119 
1120  // Close the last span tag.
1121  close_span_tag( pangoMarkupString, upDown );
1122 
1123  // printf("%s\n", pangoMarkupString);
1124 
1125  return pangoMarkupString;
1126 }
1127 
1128 //--------------------------------------------------------------------------
1129 // open_span_tag
1130 //
1131 // 1. Opens a span tag with the appropriate font description given the
1132 // current fci.
1133 // 2. Add the appropriate number of <sub> or <sup> tags to bring us
1134 // back to our current sub/super-script level.
1135 //--------------------------------------------------------------------------
1136 
1137 void open_span_tag( char *pangoMarkupString, PLUNICODE fci, float fontSize, int upDown )
1138 {
1139  unsigned char fontFamily, fontStyle, fontWeight;
1140  char openTag[TAG_LEN];
1141  int upDown_level;
1142  PLFLT old_sscale, sscale, old_soffset, soffset;
1143  PLINT level = 0.;
1144 
1145  // Generate the font info for the open tag & concatenate this
1146  // onto the markup string.
1147  plP_fci2hex( fci, &fontFamily, PL_FCI_FAMILY );
1148  plP_fci2hex( fci, &fontStyle, PL_FCI_STYLE );
1149  plP_fci2hex( fci, &fontWeight, PL_FCI_WEIGHT );
1150 
1151  // Check for unreasonable values and raise a warning
1152  if ( fontStyle >= 3 )
1153  {
1154  plwarn( "cairo: Unknown font style specified, forcing normal\n" );
1155  fontStyle = 0;
1156  }
1157  if ( fontWeight >= 2 )
1158  {
1159  plwarn( "cairo: Unknown font weight specified, forcing normal\n" );
1160  fontWeight = 0;
1161  }
1162 
1163  // From http://library.gnome.org/devel/pango/unstable/PangoMarkupFormat.html
1164  // size = font size in 1024ths of a point.
1165  snprintf( openTag, TAG_LEN, "<span font_desc=\"%s\" size=\"%d\" ", familyLookup[fontFamily], (int) ( fontSize * 1024. ) );
1166  strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1167 
1168  snprintf( openTag, TAG_LEN, "style=\"%s\" ", styleLookup[fontStyle] );
1169  strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1170 
1171  snprintf( openTag, TAG_LEN, "weight=\"%s\">", weightLookup[fontWeight] );
1172  strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1173 
1174  // Move to the right superscript/subscript level
1175  for ( upDown_level = 0; upDown_level < upDown; upDown_level++ )
1176  {
1177  plP_script_scale( TRUE, &level,
1178  &old_sscale, &sscale, &old_soffset, &soffset );
1179  strncat( pangoMarkupString,
1180  rise_span_tag( TRUE, fontSize, (float) sscale, (float) soffset ),
1181  MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1182  }
1183  for ( upDown_level = 0; upDown_level > upDown; upDown_level-- )
1184  {
1185  plP_script_scale( FALSE, &level,
1186  &old_sscale, &sscale, &old_soffset, &soffset );
1187  strncat( pangoMarkupString,
1188  rise_span_tag( FALSE, fontSize, (float) sscale, (float) soffset ),
1189  MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1190  }
1191 }
1192 
1193 //--------------------------------------------------------------------------
1194 // close_span_tag
1195 //
1196 // Close a span tag & brings us down to zero sub/super-script level.
1197 //--------------------------------------------------------------------------
1198 
1199 void close_span_tag( char *pangoMarkupString, int upDown )
1200 {
1201  if ( upDown > 0 )
1202  {
1203  while ( upDown > 0 )
1204  {
1205  strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1206  upDown--;
1207  }
1208  }
1209  if ( upDown < 0 )
1210  {
1211  while ( upDown < 0 )
1212  {
1213  strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1214  upDown++;
1215  }
1216  }
1217 
1218  strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1219 }
1220 
1221 // 0.8 mimics the offset of first superscript/subscript level implemented
1222 // in plstr (plsym.c) for Hershey fonts. Indeed when comparing with
1223 // -dev xwin results this factor appears to offset the centers of the
1224 // letters appropriately (but not their edges since different font sizes
1225 // are involved).
1226 # define RISE_FACTOR 0.8
1227 
1228 //--------------------------------------------------------------------------
1229 // rise_span_tag
1230 //
1231 // Create a rise span tag w/ appropriate font size & baseline offset
1232 // fontSize is the baseline font size in points (1/72 of an inch),
1233 // multiplier is a scaling factor for that font size for superscript
1234 // or subscript, and rise is the vertical offset (in units of font
1235 // size) for that superscript or subscript.
1236 
1237 //--------------------------------------------------------------------------
1238 
1239 char *rise_span_tag( int ifsuperscript, float fontSize, float multiplier, float rise )
1240 {
1241  float offset;
1242  static char tag[100];
1243 
1244  // http://developer.gnome.org/pango/unstable/PangoMarkupFormat.html says
1245  // rise should be in units of 10000 em's, but empirical evidence shows
1246  // it is in units of 1024th of a point. Therefore, since FontSize
1247  // is in points, a rise of 1024. * fontSize corresponds a rise of
1248  // a full character height.
1249  rise = 1024.f * fontSize * (float) RISE_FACTOR * rise;
1250 
1251  // This is the correction for the difference between baseline and
1252  // middle coordinate systems. This offset should be
1253  // 0.5*(fontSize - superscript/subscript fontSize).
1254  offset = 1024.f * 0.5f * fontSize * ( 1.0f - multiplier );
1255 
1256  if ( ifsuperscript )
1257  {
1258  sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
1259  (int) ( rise + offset ), (int) ( fontSize * 1024. * multiplier ) );
1260  }
1261  else
1262  {
1263  sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
1264  (int) -( rise - offset ), (int) ( fontSize * 1024. * multiplier ) );
1265  }
1266 
1267  return ( tag );
1268 }
1269 
1270 //--------------------------------------------------------------------------
1271 // write_to_stream()
1272 //
1273 // Writes data to a open file stream. This function is passed to the
1274 // Cairo file IO devices.
1275 //--------------------------------------------------------------------------
1276 
1277 cairo_status_t write_to_stream( void *filePointer, unsigned char *data, unsigned int length )
1278 {
1279  unsigned int bytes_written;
1280 
1281  bytes_written = (unsigned int) fwrite( data, 1, (size_t) length, (FILE *) filePointer );
1282  if ( bytes_written == length )
1283  {
1284  return CAIRO_STATUS_SUCCESS;
1285  }
1286  else
1287  {
1288  return CAIRO_STATUS_WRITE_ERROR;
1289  }
1290 }
1291 
1292 //--------------------------------------------------------------------------
1293 // stream_and_font_setup()
1294 //
1295 // Initializes the PLStream structure for the cairo devices.
1296 // Initializes the font lookup table.
1297 // Checks for cairo specific user options.
1298 // Returns a new PLCairo structure.
1299 //--------------------------------------------------------------------------
1300 
1302 {
1303  int i;
1304  char *a;
1305  PLCairo *aStream;
1306  PLFLT downscale;
1307  downscale = 0.0;
1308 
1309  // Stream setup
1310  pls->termin = interactive; // Interactive device
1311  pls->dev_flush = 1; // Handles flushes
1312  pls->color = 1; // Supports color
1313  pls->dev_text = 1; // Handles text
1314  pls->dev_unicode = 1; // Wants unicode text
1315  pls->dev_clear = 0;
1316  pls->alt_unicode = 1; // Wants to handle unicode character by character
1317  pls->page = 0;
1318  pls->dev_fill0 = 1; // Supports hardware solid fills
1319  pls->dev_gradient = 1; // driver renders gradient
1320  pls->dev_arc = 1; // Supports driver-level arcs
1321  pls->plbuf_write = interactive; // Activate plot buffer
1322  pls->has_string_length = 1; // Driver supports string length calculations
1323  pls->dev_modeset = 1; // Driver supports drawing mode setting
1324 
1325  if ( pls->xlength <= 0 || pls->ylength <= 0 )
1326  {
1327  pls->xlength = PLCAIRO_DEFAULT_X;
1328  pls->ylength = PLCAIRO_DEFAULT_Y;
1329  }
1330  // Calculate ratio of (smaller) external coordinates used for cairo
1331  // devices to (larger) internal PLplot coordinates.
1332  if ( pls->xlength > pls->ylength )
1333  downscale = (double) pls->xlength / (double) ( PIXELS_X - 1 );
1334  else
1335  downscale = (double) pls->ylength / (double) PIXELS_Y;
1336  plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / downscale ), (PLINT) 0, (PLINT) ( pls->ylength / downscale ) );
1337  plP_setpxl( DPI / 25.4 / downscale, DPI / 25.4 / downscale );
1338 
1339  // Initialize font table with either enviroment variables or defaults.
1340  // This was copied from the psttf driver.
1341  for ( i = 0; i < NPANGOLOOKUP; i++ )
1342  {
1343  if ( ( a = getenv( envFamilyLookup[i] ) ) != NULL )
1344  {
1345  strncpy( familyLookup[i], a, FAMILY_LOOKUP_LEN - 1 );
1346  familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
1347  }
1348  else
1349  {
1350  strncpy( familyLookup[i], defaultFamilyLookup[i], FAMILY_LOOKUP_LEN - 1 );
1351  familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
1352  }
1353  }
1354 
1355  // Allocate a cairo stream structure
1356  aStream = malloc( sizeof ( PLCairo ) );
1357 #if defined ( PLD_xcairo )
1358  aStream->XDisplay = NULL;
1359  aStream->XWindow = 0;
1360 #endif
1361  aStream->cairoSurface = NULL;
1362  aStream->cairoContext = NULL;
1363  aStream->downscale = downscale;
1364 
1365  // Set text clipping on by default since it makes little difference in
1366  // speed for a modern cairo stack.
1367  aStream->text_clipping = 1;
1368  text_clipping = 1;
1369  text_anti_aliasing = 0; // use 'default' text aliasing by default
1370  graphics_anti_aliasing = 0; // use 'default' graphics aliasing by default
1371  rasterize_image = 1; // Enable rasterization by default
1372  set_background = 0; // Default for extcairo is that PLplot not change the background
1373  image_buffering = 1; // Default to image-based buffered rendering
1374 
1375  // Check for cairo specific options
1376  plParseDrvOpts( cairo_options );
1377 
1378  // Turn off text clipping if the user desires this
1379  if ( !text_clipping )
1380  {
1381  aStream->text_clipping = 0;
1382  }
1383 
1384  // Record users desired text and graphics aliasing and rasterization
1385  aStream->text_anti_aliasing = (short) text_anti_aliasing;
1387  aStream->rasterize_image = (short) rasterize_image;
1388  aStream->set_background = (short) set_background;
1389  aStream->image_buffering = (short) image_buffering;
1390 
1391  return aStream;
1392 }
1393 
1394 //--------------------------------------------------------------------------
1395 // set_current_context()
1396 //
1397 // Updates the cairo graphics context with the current values in
1398 // PLStream.
1399 //--------------------------------------------------------------------------
1400 
1402 {
1403  PLCairo *aStream;
1404 
1405  aStream = (PLCairo *) pls->dev;
1406  cairo_set_source_rgba( aStream->cairoContext,
1407  (double) pls->curcolor.r / 255.0,
1408  (double) pls->curcolor.g / 255.0,
1409  (double) pls->curcolor.b / 255.0,
1410  (double) pls->curcolor.a );
1411  // In Cairo, zero width lines are not hairlines, they are completely invisible.
1412  if ( pls->width <= 0. )
1413  {
1414  cairo_set_line_width( aStream->cairoContext, 1.0 );
1415  }
1416  else
1417  {
1418  cairo_set_line_width( aStream->cairoContext, (double) pls->width );
1419  }
1420 }
1421 
1422 //--------------------------------------------------------------------------
1423 // poly_line()
1424 //
1425 // Draws a multi-segmented line. It is then up to the calling function
1426 // to decide whether to just draw the line, or fill in the area
1427 // enclosed by the line.
1428 //--------------------------------------------------------------------------
1429 
1430 void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts )
1431 {
1432  int i;
1433  PLCairo *aStream;
1434 
1435  aStream = (PLCairo *) pls->dev;
1436 
1437  set_current_context( pls );
1438 
1439  cairo_move_to( aStream->cairoContext, aStream->downscale * (double) xa[0], aStream->downscale * (double) ya[0] );
1440  for ( i = 1; i < npts; i++ )
1441  {
1442  cairo_line_to( aStream->cairoContext, aStream->downscale * (double) xa[i], aStream->downscale * (double) ya[i] );
1443  }
1444 }
1445 
1446 //--------------------------------------------------------------------------
1447 // filled_polygon()
1448 //
1449 // Draws a filled polygon.
1450 //--------------------------------------------------------------------------
1451 
1452 void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts )
1453 {
1454  PLCairo *aStream;
1455 
1456  aStream = (PLCairo *) pls->dev;
1457 
1458  cairo_save( aStream->cairoContext );
1459 
1460  // Draw the polygons
1461  poly_line( pls, xa, ya, npts );
1462 
1463  cairo_set_source_rgba( aStream->cairoContext,
1464  (double) pls->curcolor.r / 255.0,
1465  (double) pls->curcolor.g / 255.0,
1466  (double) pls->curcolor.b / 255.0,
1467  (double) pls->curcolor.a );
1468 
1469  if ( cairo_get_antialias( aStream->cairoContext ) != CAIRO_ANTIALIAS_NONE )
1470  {
1471  cairo_fill_preserve( aStream->cairoContext );
1472 
1473  // These line properties make for a nicer looking polygon mesh
1474  set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
1475  // Comment out the following call to cairo_set_line width
1476  // since the hard-coded width value of 1.0 is not appropriate
1477  // for fills of small areas. Instead, use the line width that
1478  // has already been set by the user via the above call of
1479  // poly_line which in turn calls set_current_context which in
1480  // turn calls cairo_set_line_width for the user-specified
1481  // width.
1482  // cairo_set_line_width( aStream->cairoContext, 1.0 );
1483  cairo_stroke( aStream->cairoContext );
1484  }
1485  else
1486  {
1487  cairo_fill( aStream->cairoContext );
1488  }
1489 
1490  cairo_restore( aStream->cairoContext );
1491 }
1492 
1493 //--------------------------------------------------------------------------
1494 // gradient()
1495 //
1496 // Render a gradient within a polygon.
1497 //--------------------------------------------------------------------------
1498 
1499 void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
1500 {
1501  int i;
1502  PLCairo *aStream;
1503  cairo_pattern_t *linear_gradient;
1504 
1505  aStream = (PLCairo *) pls->dev;
1506 
1507  // These line properties make for a nicer looking polygon mesh
1508  set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
1509 
1510  linear_gradient = cairo_pattern_create_linear(
1511  aStream->downscale * pls->xgradient[0],
1512  aStream->downscale * pls->ygradient[0],
1513  aStream->downscale * pls->xgradient[1],
1514  aStream->downscale * pls->ygradient[1] );
1515 
1516  cairo_pattern_reference( linear_gradient );
1517  for ( i = 0; i < pls->ncol1; i++ )
1518  {
1519  cairo_pattern_add_color_stop_rgba( linear_gradient,
1520  (double) i / (double) ( pls->ncol1 - 1 ),
1521  (double) pls->cmap1[i].r / 255.,
1522  (double) pls->cmap1[i].g / 255.,
1523  (double) pls->cmap1[i].b / 255.,
1524  (double) pls->cmap1[i].a );
1525  }
1526 
1527  // Draw the polygon using the gradient.
1528  poly_line( pls, xa, ya, npts );
1529 
1530  cairo_set_source( aStream->cairoContext, linear_gradient );
1531  cairo_fill( aStream->cairoContext );
1532  cairo_pattern_destroy( linear_gradient );
1533 }
1534 
1535 //--------------------------------------------------------------------------
1536 // set_clip()
1537 //
1538 // Set the clipping region to the plot window.
1539 // NOTE: cairo_save() and cairo_restore() should probably be called before
1540 // and after this, respectively.
1541 //--------------------------------------------------------------------------
1542 
1544 {
1545  PLINT rcx[4], rcy[4];
1546  PLCairo *aStream;
1547  aStream = (PLCairo *) pls->dev;
1548 
1549  // Use PLplot core routine to get the corners of the clipping rectangle
1550  difilt_clip( rcx, rcy );
1551 
1552  // Layout the bounds of the clipping region
1553  // Should we convert PLINT to short and use the polyline routine?
1554  cairo_move_to( aStream->cairoContext,
1555  aStream->downscale * (double) rcx[0],
1556  aStream->downscale * (double) rcy[0] );
1557  cairo_line_to( aStream->cairoContext,
1558  aStream->downscale * (double) rcx[1],
1559  aStream->downscale * (double) rcy[1] );
1560  cairo_line_to( aStream->cairoContext,
1561  aStream->downscale * (double) rcx[2],
1562  aStream->downscale * (double) rcy[2] );
1563  cairo_line_to( aStream->cairoContext,
1564  aStream->downscale * (double) rcx[3],
1565  aStream->downscale * (double) rcy[3] );
1566  cairo_line_to( aStream->cairoContext,
1567  aStream->downscale * (double) rcx[0],
1568  aStream->downscale * (double) rcy[0] );
1569 
1570  // Set the clipping region
1571  cairo_clip( aStream->cairoContext );
1572 
1573  // Apparently, in some older Cairo versions, cairo_clip does not consume
1574  // the current path.
1575  cairo_new_path( aStream->cairoContext );
1576 }
1577 
1578 //--------------------------------------------------------------------------
1579 // cairo_family_check ()
1580 //
1581 // support function to help supress more than one page if family file
1582 // output not specified by the user (e.g., with the -fam command-line option).
1583 //--------------------------------------------------------------------------
1584 
1586 {
1587  if ( pls->family || pls->page == 1 )
1588  {
1589  return 0;
1590  }
1591  else
1592  {
1593  if ( !already_warned )
1594  {
1595  already_warned = 1;
1596  plwarn( "All pages after the first skipped because family file output not specified.\n" );
1597  }
1598  return 1;
1599  }
1600 }
1601 
1602 //--------------------------------------------------------------------------
1603 // arc()
1604 //
1605 // Draws an arc, possibly filled.
1606 //--------------------------------------------------------------------------
1607 
1608 void arc( PLStream *pls, arc_struct *arc_info )
1609 {
1610  PLCairo *aStream;
1611  double x, y, a, b;
1612  double angle1, angle2, rotate;
1613 
1614  set_current_context( pls );
1615 
1616  aStream = (PLCairo *) pls->dev;
1617 
1618  // Scale to the proper Cairo coordinates
1619  x = aStream->downscale * arc_info->x;
1620  y = aStream->downscale * arc_info->y;
1621  a = aStream->downscale * arc_info->a;
1622  b = aStream->downscale * arc_info->b;
1623 
1624  // Degrees to radians
1625  angle1 = arc_info->angle1 * M_PI / 180.0;
1626  angle2 = arc_info->angle2 * M_PI / 180.0;
1627  rotate = arc_info->rotate * M_PI / 180.0;
1628 
1629  cairo_save( aStream->cairoContext );
1630 
1631  // Clip the output to the plotting window
1632  set_clip( pls );
1633 
1634  // Make sure the arc is properly shaped and oriented
1635  cairo_save( aStream->cairoContext );
1636  cairo_translate( aStream->cairoContext, x, y );
1637  cairo_rotate( aStream->cairoContext, rotate );
1638  cairo_scale( aStream->cairoContext, a, b );
1639  cairo_arc( aStream->cairoContext, 0.0, 0.0, 1.0, angle1, angle2 );
1640  if ( arc_info->fill )
1641  cairo_line_to( aStream->cairoContext, 0.0, 0.0 );
1642  cairo_restore( aStream->cairoContext );
1643 
1644  cairo_set_source_rgba( aStream->cairoContext,
1645  (double) pls->curcolor.r / 255.0,
1646  (double) pls->curcolor.g / 255.0,
1647  (double) pls->curcolor.b / 255.0,
1648  (double) pls->curcolor.a );
1649  if ( arc_info->fill )
1650  {
1651  cairo_fill( aStream->cairoContext );
1652  }
1653  else
1654  {
1655  cairo_stroke( aStream->cairoContext );
1656  }
1657  cairo_restore( aStream->cairoContext );
1658 }
1659 
1660 //--------------------------------------------------------------------------
1661 // rotate_cairo_surface()
1662 //
1663 // Rotates the cairo surface to the appropriate orientation.
1664 //--------------------------------------------------------------------------
1665 
1666 void rotate_cairo_surface( PLStream *pls, float x11, float x12, float x21, float x22, float x0, float y0, PLBOOL is_xcairo )
1667 {
1668  cairo_matrix_t *matrix;
1669  PLCairo *aStream;
1670 
1671  aStream = (PLCairo *) pls->dev;
1672 
1673  matrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
1674  cairo_matrix_init( matrix, x11, x12, x21, x22, x0, y0 );
1675 #if defined ( PLD_xcairo )
1676  if ( is_xcairo )
1677  {
1678  cairo_transform( aStream->cairoContext_X, matrix );
1679  }
1680  else
1681  {
1682  cairo_transform( aStream->cairoContext, matrix );
1683  }
1684 #else
1685  cairo_transform( aStream->cairoContext, matrix );
1686 #endif
1687  free( matrix );
1688 }
1689 
1690 //--------------------------------------------------------------------------
1691 //--------------------------------------------------------------------------
1692 //
1693 // That which is common to all familying Cairo Drivers
1694 //
1695 //--------------------------------------------------------------------------
1696 //--------------------------------------------------------------------------
1697 #if defined ( PLD_pngcairo ) || defined ( PLD_svgcairo ) || defined ( PLD_epscairo )
1698 
1699 void plD_bop_cairo_fam( PLStream * );
1700 void plD_eop_cairo_fam( PLStream * );
1701 void plD_state_cairo_fam( PLStream *, PLINT );
1702 void plD_esc_cairo_fam( PLStream *, PLINT, void * );
1703 void plD_tidy_cairo_fam( PLStream * );
1704 void plD_line_cairo_fam( PLStream *, short, short, short, short );
1705 void plD_polyline_cairo_fam( PLStream *, short *, short *, PLINT );
1706 
1707 //--------------------------------------------------------------------------
1708 // plD_bop_cairo_fam()
1709 //
1710 // Familying Devices: Set up for the next page.
1711 //--------------------------------------------------------------------------
1712 
1713 void plD_bop_cairo_fam( PLStream *pls )
1714 {
1715  PLCairo *aStream;
1716 
1717  // Plot familying stuff. Not really understood, just copying gd.c
1718  plGetFam( pls );
1719 
1720  aStream = (PLCairo *) pls->dev;
1721 
1722  pls->famadv = 1;
1723  pls->page++;
1724 
1725  // Suppress multi-page output if family file output is not
1726  // specified by the user.
1727  if ( cairo_family_check( pls ) )
1728  {
1729  return;
1730  }
1731 
1732  // Fill in the window with the background color.
1733  cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
1734  cairo_set_source_rgba( aStream->cairoContext,
1735  (double) pls->cmap0[0].r / 255.0,
1736  (double) pls->cmap0[0].g / 255.0,
1737  (double) pls->cmap0[0].b / 255.0,
1738  (double) pls->cmap0[0].a );
1739  cairo_fill( aStream->cairoContext );
1740 }
1741 
1742 //--------------------------------------------------------------------------
1743 // plD_eop_cairo()
1744 //
1745 // End of page.
1746 //--------------------------------------------------------------------------
1747 
1748 void plD_eop_cairo_fam( PLStream *pls )
1749 {
1750  if ( cairo_family_check( pls ) )
1751  {
1752  return;
1753  }
1754 
1755  plD_eop_cairo( pls );
1756 }
1757 
1758 //--------------------------------------------------------------------------
1759 // plD_state_cairo_fam()
1760 //
1761 // Handle change in PLStream state (color, pen width, fill attribute, etc).
1762 //--------------------------------------------------------------------------
1763 
1764 void plD_state_cairo_fam( PLStream *pls, PLINT op )
1765 {
1766  if ( cairo_family_check( pls ) )
1767  {
1768  return;
1769  }
1770 
1771  plD_state_cairo( pls, op );
1772 }
1773 
1774 //--------------------------------------------------------------------------
1775 // plD_esc_cairo_fam()
1776 //
1777 // Generic escape function.
1778 //--------------------------------------------------------------------------
1779 
1780 void plD_esc_cairo_fam( PLStream *pls, PLINT op, void *ptr )
1781 {
1782  if ( cairo_family_check( pls ) )
1783  {
1784  return;
1785  }
1786 
1787  plD_esc_cairo( pls, op, ptr );
1788 }
1789 
1790 //--------------------------------------------------------------------------
1791 // plD_tidy_cairo_fam()
1792 //
1793 // Close graphics file or otherwise clean up.
1794 //--------------------------------------------------------------------------
1795 
1796 void plD_tidy_cairo_fam( PLStream *pls )
1797 {
1798  plD_tidy_cairo( pls );
1799 }
1800 
1801 //--------------------------------------------------------------------------
1802 // plD_line_cairo_fam()
1803 //
1804 // Draw a line.
1805 //--------------------------------------------------------------------------
1806 
1807 void plD_line_cairo_fam( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
1808 {
1809  if ( cairo_family_check( pls ) )
1810  {
1811  return;
1812  }
1813 
1814  plD_line_cairo( pls, x1a, y1a, x2a, y2a );
1815 }
1816 
1817 //--------------------------------------------------------------------------
1818 // plD_polyline_cairo_fam()
1819 //
1820 // Draw a polyline in the current color.
1821 //--------------------------------------------------------------------------
1822 
1823 void plD_polyline_cairo_fam( PLStream *pls, short *xa, short *ya, PLINT npts )
1824 {
1825  if ( cairo_family_check( pls ) )
1826  {
1827  return;
1828  }
1829 
1830  plD_polyline_cairo( pls, xa, ya, npts );
1831 }
1832 
1833 #endif
1834 //--------------------------------------------------------------------------
1835 //--------------------------------------------------------------------------
1836 //
1837 // That which is specific to the xcairo driver.
1838 //
1839 //--------------------------------------------------------------------------
1840 //--------------------------------------------------------------------------
1841 
1842 #if defined ( PLD_xcairo )
1843 
1844 static int XScreen;
1845 static Window rootWindow;
1846 
1848 void plD_init_xcairo( PLStream * );
1849 void plD_bop_xcairo( PLStream * );
1850 void plD_eop_xcairo( PLStream * );
1851 void plD_tidy_xcairo( PLStream * );
1852 void plD_esc_xcairo( PLStream *, PLINT, void * );
1853 static void xcairo_get_cursor( PLStream *, PLGraphicsIn * );
1854 
1855 //--------------------------------------------------------------------------
1856 // plD_dispatch_init_xcairo()
1857 //
1858 // xcairo dispatch table initialization.
1859 //--------------------------------------------------------------------------
1860 
1862 {
1863 #ifndef ENABLE_DYNDRIVERS
1864  pdt->pl_MenuStr = "Cairo X Windows Driver";
1865  pdt->pl_DevName = "xcairo";
1866 #endif
1868  pdt->pl_seq = 100;
1869  pdt->pl_init = (plD_init_fp) plD_init_xcairo;
1872  pdt->pl_eop = (plD_eop_fp) plD_eop_xcairo;
1873  pdt->pl_bop = (plD_bop_fp) plD_bop_xcairo;
1874  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_xcairo;
1876  pdt->pl_esc = (plD_esc_fp) plD_esc_xcairo;
1877 }
1878 
1879 //--------------------------------------------------------------------------
1880 // xcairo_init_cairo()
1881 //
1882 // Configures Cairo to use whichever X Drawable is set up in the given
1883 // stream. This is called by plD_init_xcairo() in the event we are
1884 // drawing into a plplot-managed window, and plD_esc_xcairo() if
1885 // we are using an external X Drawable.
1886 //
1887 // A return value of 0 indicates success. Currently this function only
1888 // returns 0.
1889 //--------------------------------------------------------------------------
1890 
1891 static signed int xcairo_init_cairo( PLStream *pls )
1892 {
1893  PLCairo *aStream;
1894  Visual *defaultVisual;
1895 
1896  aStream = (PLCairo *) pls->dev;
1897 
1898  // Create an cairo surface & context that are associated with the X window.
1899  defaultVisual = DefaultVisual( aStream->XDisplay, 0 );
1900 
1901  // Dimension units are pixels from cairo documentation.
1902  // This is the X window Cairo surface.
1903  aStream->cairoSurface_X = cairo_xlib_surface_create(
1904  aStream->XDisplay,
1905  aStream->XWindow,
1906  defaultVisual,
1907  pls->xlength,
1908  pls->ylength );
1909 
1910  aStream->cairoContext_X = cairo_create( aStream->cairoSurface_X );
1911 
1912  // This is the Cairo surface PLplot will actually plot to.
1913  if ( aStream->image_buffering == 0 )
1914  {
1915  aStream->cairoSurface = cairo_surface_create_similar(
1916  aStream->cairoSurface_X,
1917  CAIRO_CONTENT_COLOR_ALPHA,
1918  pls->xlength,
1919  pls->ylength );
1920 
1921  aStream->cairoContext = cairo_create( aStream->cairoSurface );
1922  }
1923  else
1924  {
1925  // Plot to an off-screen image
1926  aStream->cairoSurface =
1927  cairo_image_surface_create(
1928  CAIRO_FORMAT_ARGB32,
1929  pls->xlength,
1930  pls->ylength );
1931  aStream->cairoContext = cairo_create( aStream->cairoSurface );
1932  }
1933 
1934  // Invert the surface so that the graphs are drawn right side up.
1935  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, TRUE );
1936 
1937  // Set graphics aliasing
1938  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
1939 
1940  // Set fill rule for the case of self-intersecting boundaries.
1941  if ( pls->dev_eofill )
1942  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
1943  else
1944  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
1945 
1946  // Fill in the X window with the background color to avoid starting out
1947  // with a blank window of an unexpected color.
1948  cairo_rectangle( aStream->cairoContext_X, 0.0, 0.0, pls->xlength, pls->ylength );
1949  cairo_set_source_rgba( aStream->cairoContext_X,
1950  (double) pls->cmap0[0].r / 255.0,
1951  (double) pls->cmap0[0].g / 255.0,
1952  (double) pls->cmap0[0].b / 255.0,
1953  (double) pls->cmap0[0].a );
1954  cairo_fill( aStream->cairoContext_X );
1955 
1956  XFlush( aStream->XDisplay );
1957 
1958  return 0;
1959 }
1960 
1961 //--------------------------------------------------------------------------
1962 // plD_init_xcairo()
1963 //
1964 // Initialize Cairo X Windows device.
1965 //--------------------------------------------------------------------------
1966 
1967 void plD_init_xcairo( PLStream *pls )
1968 {
1969  PLCairo *aStream;
1970  Atom wmDelete;
1971 
1972  // Setup the PLStream and the font lookup table.
1973  aStream = stream_and_font_setup( pls, 1 );
1974 
1975  // Save the pointer to the structure in the PLplot stream
1976  pls->dev = aStream;
1977 
1978  // Create a X Window if required.
1979  if ( external_drawable != 0 )
1980  {
1981  aStream->xdrawable_mode = 1;
1982  }
1983  else
1984  {
1985  // X Windows setup
1986  aStream->XDisplay = NULL;
1987  if ( pls->FileName != NULL )
1988  aStream->XDisplay = XOpenDisplay( pls->FileName );
1989  else
1990  aStream->XDisplay = XOpenDisplay( NULL );
1991  if ( aStream->XDisplay == NULL )
1992  {
1993  plexit( "Failed to open X Windows display\n" );
1994  // some sort of error here
1995  }
1996  XScreen = DefaultScreen( aStream->XDisplay );
1997  rootWindow = RootWindow( aStream->XDisplay, XScreen );
1998 
1999  aStream->XWindow = XCreateSimpleWindow(
2000  aStream->XDisplay,
2001  rootWindow, 0, 0,
2002  (unsigned int) pls->xlength,
2003  (unsigned int) pls->ylength,
2004  1,
2005  BlackPixel( aStream->XDisplay, XScreen ),
2006  BlackPixel( aStream->XDisplay, XScreen ) );
2007 
2008  XStoreName( aStream->XDisplay, aStream->XWindow, pls->plwindow );
2009  XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
2010  XMapWindow( aStream->XDisplay, aStream->XWindow );
2011  aStream->xdrawable_mode = 0;
2012 
2013  wmDelete = XInternAtom( aStream->XDisplay, "WM_DELETE_WINDOW", True );
2014  XSetWMProtocols( aStream->XDisplay, aStream->XWindow, &wmDelete, 1 );
2015 
2016  xcairo_init_cairo( pls );
2017  }
2018 
2019  aStream->exit_event_loop = 0;
2020 }
2021 
2022 //--------------------------------------------------------------------------
2023 // blit_to_x()
2024 //
2025 //
2026 // Blit the offscreen image to the X window.
2027 //--------------------------------------------------------------------------
2028 
2029 void blit_to_x( PLStream *pls, double x, double y, double w, double h )
2030 {
2031  PLCairo *aStream;
2032 
2033  aStream = pls->dev;
2034 
2035  cairo_save( aStream->cairoContext );
2036  // "Flatten" any transparent regions to look like they were drawn over the
2037  // correct background color
2038  cairo_rectangle( aStream->cairoContext, x, y, w, h );
2039  cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_DEST_OVER );
2040  cairo_set_source_rgba( aStream->cairoContext,
2041  (double) pls->cmap0[0].r / 255.0,
2042  (double) pls->cmap0[0].g / 255.0,
2043  (double) pls->cmap0[0].b / 255.0,
2044  (double) pls->cmap0[0].a );
2045  cairo_fill( aStream->cairoContext );
2046  cairo_restore( aStream->cairoContext );
2047 
2048  cairo_save( aStream->cairoContext_X );
2049  // Copy a portion of the surface
2050  cairo_rectangle( aStream->cairoContext_X, x, y, w, h );
2051  cairo_set_operator( aStream->cairoContext_X, CAIRO_OPERATOR_SOURCE );
2052  cairo_set_source_surface( aStream->cairoContext_X,
2053  aStream->cairoSurface, 0.0, 0.0 );
2054  cairo_fill( aStream->cairoContext_X );
2055  cairo_restore( aStream->cairoContext_X );
2056 }
2057 
2058 //--------------------------------------------------------------------------
2059 // plD_bop_xcairo()
2060 //
2061 // X Windows specific start of page.
2062 //--------------------------------------------------------------------------
2063 
2064 void plD_bop_xcairo( PLStream *pls )
2065 {
2066  PLCairo *aStream;
2067 
2068  aStream = (PLCairo *) pls->dev;
2069 
2070  plD_bop_cairo( pls );
2071 
2072  if ( aStream->xdrawable_mode )
2073  return;
2074 
2075  XFlush( aStream->XDisplay );
2076 }
2077 
2078 //--------------------------------------------------------------------------
2079 // plD_eop_xcairo()
2080 //
2081 // X Windows specific end of page.
2082 //--------------------------------------------------------------------------
2083 
2084 void plD_eop_xcairo( PLStream *pls )
2085 {
2086  int number_chars;
2087  long event_mask;
2088  char event_string[10];
2089  KeySym keysym;
2090  XComposeStatus cs;
2091  XEvent event;
2092  XExposeEvent *expose;
2093  PLCairo *aStream;
2094 
2095  aStream = (PLCairo *) pls->dev;
2096 
2097  // Blit the offscreen image to the X window.
2098  blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
2099 
2100  if ( aStream->xdrawable_mode )
2101  return;
2102 
2103  // Only pause if nopause is unset.
2104  if ( pls->nopause )
2105  aStream->exit_event_loop = 1;
2106 
2107  // Loop, handling selected events, till the user elects to close the plot.
2108  event_mask = ButtonPressMask | KeyPressMask | ExposureMask;
2109  XSelectInput( aStream->XDisplay, aStream->XWindow, event_mask );
2110  while ( !aStream->exit_event_loop )
2111  {
2112  //XWindowEvent( aStream->XDisplay, aStream->XWindow, event_mask, &event );
2113  XNextEvent( aStream->XDisplay, &event );
2114  switch ( event.type )
2115  {
2116  case KeyPress:
2117  number_chars = XLookupString( (XKeyEvent *) &event, event_string, 10, &keysym, &cs );
2118  event_string[number_chars] = '\0';
2119  if ( keysym == XK_Return )
2120  {
2121  aStream->exit_event_loop = 1;
2122  }
2123  break;
2124  case ButtonPress:
2125  if ( ( (XButtonEvent *) &event )->button == Button3 )
2126  aStream->exit_event_loop = 1;
2127  break;
2128  case ClientMessage:
2129  // plexit("X Window closed");
2130  pls->stream_closed = TRUE;
2131  aStream->exit_event_loop = 1;
2132  break;
2133  case Expose:
2134  // Blit the image again after an expose event, but only for the last
2135  // available event. Otherwise multiple redraws occur needlessly.
2136  expose = (XExposeEvent *) &event;
2137  if ( expose->count == 0 )
2138  {
2139  blit_to_x( pls, expose->x, expose->y,
2140  expose->width, expose->height );
2141  }
2142  break;
2143  }
2144  }
2145  aStream->exit_event_loop = 0;
2146 }
2147 
2148 //--------------------------------------------------------------------------
2149 // plD_tidy_xcairo()
2150 //
2151 // X Windows: close graphics file or otherwise clean up.
2152 //--------------------------------------------------------------------------
2153 
2154 void plD_tidy_xcairo( PLStream *pls )
2155 {
2156  PLCairo *aStream;
2157 
2158  aStream = (PLCairo *) pls->dev;
2159 
2160  plD_tidy_cairo( pls );
2161 
2162  // Also free up the Cairo X surface and context
2163  cairo_destroy( aStream->cairoContext_X );
2164  cairo_surface_destroy( aStream->cairoSurface_X );
2165 
2166  if ( aStream->xdrawable_mode )
2167  return;
2168 
2169  // Close the window and the display.
2170  XFlush( aStream->XDisplay );
2171 
2172  XDestroyWindow( aStream->XDisplay, aStream->XWindow );
2173 
2174  XCloseDisplay( aStream->XDisplay );
2175 }
2176 
2177 //--------------------------------------------------------------------------
2178 // plD_esc_xcairo()
2179 //
2180 // Escape function, specialized for the xcairo driver
2181 //--------------------------------------------------------------------------
2182 
2183 void plD_esc_xcairo( PLStream *pls, PLINT op, void *ptr )
2184 {
2185  PLCairo *aStream;
2186 
2187  aStream = (PLCairo *) pls->dev;
2188 
2189  switch ( op )
2190  {
2191  case PLESC_FLUSH: // forced update of the window
2192  blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
2193  XFlush( aStream->XDisplay );
2194  break;
2195  case PLESC_GETC: // get cursor position
2196  blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
2197  XFlush( aStream->XDisplay );
2198  xcairo_get_cursor( pls, (PLGraphicsIn *) ptr );
2199  break;
2200  case PLESC_DEVINIT: { // Set external drawable
2201  Window rootwin;
2202  PLXcairoDrawableInfo *xinfo = (PLXcairoDrawableInfo *) ptr;
2203  signed int x, y;
2204  unsigned int w, h, b, d;
2205  if ( xinfo == NULL )
2206  {
2207  printf( "xcairo: PLESC_DEVINIT ignored, no drawable info provided\n" );
2208  return;
2209  }
2210  if ( aStream->xdrawable_mode == 0 )
2211  {
2212  printf( "xcairo: PLESC_DEVINIT called with drawable but stream not in xdrawable mode\n" );
2213  return;
2214  }
2215  aStream->XDisplay = xinfo->display;
2216  aStream->XWindow = xinfo->drawable;
2217 
2218  // Ensure plplot knows the real dimensions of the drawable
2219  XGetGeometry( aStream->XDisplay, aStream->XWindow, &rootwin,
2220  &x, &y, &w, &h, &b, &d );
2221  pls->xlength = (PLINT) w;
2222  pls->ylength = (PLINT) h;
2223  // Calculate ratio of (smaller) external coordinates used for cairo
2224  // devices to (larger) internal PLplot coordinates.
2225  if ( pls->xlength > pls->ylength )
2226  aStream->downscale = (double) pls->xlength / (double) ( PIXELS_X - 1 );
2227  else
2228  aStream->downscale = (double) pls->ylength / (double) PIXELS_Y;
2229  plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / aStream->downscale ), (PLINT) 0,
2230  (PLINT) ( pls->ylength / aStream->downscale ) );
2231 
2232  // Associate cairo with the supplied drawable
2233  xcairo_init_cairo( pls );
2234 
2235  // Recalculate dimensions and the like now that the drawable is known
2236  plbop();
2237 
2238  break;
2239  }
2240  default:
2241  plD_esc_cairo( pls, op, ptr );
2242  break;
2243  }
2244 }
2245 
2246 //--------------------------------------------------------------------------
2247 // xcairo_get_cursor()
2248 //
2249 // X Windows: returns the location of the next mouse click or key press.
2250 //--------------------------------------------------------------------------
2251 
2252 void xcairo_get_cursor( PLStream *pls, PLGraphicsIn *gin )
2253 {
2254  const char *ksname;
2255  char str[257];
2256  KeySym keysym;
2257  XEvent event;
2258  XButtonEvent *xButtonEvent;
2259  Cursor xHairCursor;
2260  PLCairo *aStream;
2261 
2262  aStream = (PLCairo *) pls->dev;
2263 
2264  // Initialize PLplot mouse event structure
2265  plGinInit( gin );
2266 
2267  // Create cross hair cursor & switch to using it
2268  xHairCursor = XCreateFontCursor( aStream->XDisplay, XC_crosshair );
2269  XDefineCursor( aStream->XDisplay, aStream->XWindow, xHairCursor );
2270 
2271  // Get the next mouse button release or key press event
2272  XSelectInput( aStream->XDisplay, aStream->XWindow, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask );
2273  XMaskEvent( aStream->XDisplay, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask, &event );
2274  XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
2275 
2276  // Update PLplot's mouse event structure
2277  xButtonEvent = (XButtonEvent *) &event;
2278  gin->state = xButtonEvent->state;
2279  gin->button = xButtonEvent->button;
2280  gin->pX = event.xbutton.x;
2281  gin->pY = pls->ylength - event.xbutton.y;
2282  gin->dX = (PLFLT) event.xbutton.x / ( (PLFLT) ( pls->xlength ) );
2283  gin->dY = (PLFLT) ( pls->ylength - event.xbutton.y ) / ( (PLFLT) ( pls->ylength ) );
2284 
2285  // Get key pressed (if any)
2286  if ( event.type == KeyPress || event.type == KeyRelease )
2287  {
2288  XLookupString( (XKeyEvent *) &event, str, 100, &keysym, NULL );
2289  if ( keysym == NoSymbol )
2290  ksname = "NoSymbol";
2291  else if ( !( ksname = XKeysymToString( keysym ) ) )
2292  ksname = "(no name)";
2293  strcpy( gin->string, ksname );
2294  // gin->string[number_chars] = '\0';
2295  switch ( keysym )
2296  {
2297  case XK_BackSpace:
2298  case XK_Tab:
2299  case XK_Linefeed:
2300  case XK_Return:
2301  case XK_Escape:
2302  case XK_Delete:
2303  gin->keysym = 0xFF & keysym;
2304  break;
2305  default:
2306  gin->keysym = (unsigned int) keysym;
2307  }
2308  }
2309  else // button press
2310  {
2311  sprintf( gin->string, "button %u", gin->button );
2312  gin->keysym = 0x20;
2313  }
2314 
2315  // Switch back to normal cursor
2316  XUndefineCursor( aStream->XDisplay, aStream->XWindow );
2317  XFlush( aStream->XDisplay );
2318 }
2319 
2320 #endif
2321 
2322 
2323 //--------------------------------------------------------------------------
2324 //--------------------------------------------------------------------------
2325 //
2326 // That which is specific to the cairo PDF driver.
2327 //
2328 //--------------------------------------------------------------------------
2329 //--------------------------------------------------------------------------
2330 
2331 #if defined ( PLD_pdfcairo )
2332 
2334 void plD_init_pdfcairo( PLStream * );
2335 
2336 //--------------------------------------------------------------------------
2337 // dispatch_init_init()
2338 //
2339 // Initialize device dispatch table
2340 //--------------------------------------------------------------------------
2341 
2342 // pdfcairo
2344 {
2345 #ifndef ENABLE_DYNDRIVERS
2346  pdt->pl_MenuStr = "Cairo PDF Driver";
2347  pdt->pl_DevName = "pdfcairo";
2348 #endif
2350  pdt->pl_seq = 101;
2351  pdt->pl_init = (plD_init_fp) plD_init_pdfcairo;
2354  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2355  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2358  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2359 }
2360 
2361 //--------------------------------------------------------------------------
2362 // plD_init_pdfcairo()
2363 //
2364 // Initialize Cairo PDF device
2365 //--------------------------------------------------------------------------
2366 
2367 void plD_init_pdfcairo( PLStream *pls )
2368 {
2369  PLCairo *aStream;
2370 
2371  // Setup the PLStream and the font lookup table
2372  aStream = stream_and_font_setup( pls, 0 );
2373 
2374  // Prompt for a file name if not already set.
2375  plOpenFile( pls );
2376 
2377  // Create an cairo surface & context for PDF file.
2378  // Dimension units are pts = 1/72 inches from cairo documentation.
2379  aStream->cairoSurface = cairo_pdf_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
2380  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2381 
2382  // Save the pointer to the structure in the PLplot stream
2383  pls->dev = aStream;
2384 
2385  // Invert the surface so that the graphs are drawn right side up.
2386  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2387 
2388  // Set graphics aliasing
2389  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2390 
2391  // Set fill rule for the case of self-intersecting boundaries.
2392  if ( pls->dev_eofill )
2393  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2394  else
2395  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2396 }
2397 
2398 #endif
2399 
2400 
2401 //--------------------------------------------------------------------------
2402 //--------------------------------------------------------------------------
2403 //
2404 // That which is specific to the cairo PS driver.
2405 //
2406 //--------------------------------------------------------------------------
2407 //--------------------------------------------------------------------------
2408 
2409 #if defined ( PLD_pscairo )
2410 
2412 void plD_init_pscairo( PLStream * );
2413 
2414 //--------------------------------------------------------------------------
2415 // dispatch_init_init()
2416 //
2417 // Initialize device dispatch table
2418 //--------------------------------------------------------------------------
2419 
2420 // pscairo
2422 {
2423 #ifndef ENABLE_DYNDRIVERS
2424  pdt->pl_MenuStr = "Cairo PS Driver";
2425  pdt->pl_DevName = "pscairo";
2426 #endif
2428  pdt->pl_seq = 102;
2429  pdt->pl_init = (plD_init_fp) plD_init_pscairo;
2432  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2433  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2436  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2437 }
2438 
2439 //--------------------------------------------------------------------------
2440 // plD_init_pscairo()
2441 //
2442 // Initialize Cairo PS device
2443 //--------------------------------------------------------------------------
2444 
2445 void plD_init_pscairo( PLStream *pls )
2446 {
2447  PLCairo *aStream;
2448 
2449  // Setup the PLStream and the font lookup table
2450  aStream = stream_and_font_setup( pls, 0 );
2451 
2452  // Prompt for a file name if not already set.
2453  plOpenFile( pls );
2454 
2455  // Create an cairo surface & context for PS file.
2456  // Dimension units are pts = 1/72 inches from cairo documentation.
2457  aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
2458  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2459 
2460  // Save the pointer to the structure in the PLplot stream
2461  pls->dev = aStream;
2462 
2463  // Handle portrait or landscape
2464  if ( pls->portrait )
2465  {
2466  plsdiori( 1 );
2467  pls->freeaspect = 1;
2468  }
2469  rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, (float) pls->ylength, (float) pls->xlength, FALSE );
2470 
2471  // Set fill rule for the case of self-intersecting boundaries.
2472  if ( pls->dev_eofill )
2473  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2474  else
2475  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2476 }
2477 
2478 #endif
2479 
2480 
2481 //--------------------------------------------------------------------------
2482 //--------------------------------------------------------------------------
2483 //
2484 // That which is specific to the cairo EPS driver.
2485 //
2486 //--------------------------------------------------------------------------
2487 //--------------------------------------------------------------------------
2488 
2489 #if defined ( PLD_epscairo )
2490 
2492 void plD_init_epscairo( PLStream * );
2493 
2494 //--------------------------------------------------------------------------
2495 // dispatch_init_init()
2496 //
2497 // Initialize device dispatch table
2498 //--------------------------------------------------------------------------
2499 
2500 // epscairo
2502 {
2503 #ifndef ENABLE_DYNDRIVERS
2504  pdt->pl_MenuStr = "Cairo EPS Driver";
2505  pdt->pl_DevName = "epscairo";
2506 #endif
2508  pdt->pl_seq = 102;
2509  pdt->pl_init = (plD_init_fp) plD_init_epscairo;
2510  pdt->pl_line = (plD_line_fp) plD_line_cairo_fam;
2511  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
2512  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo_fam;
2513  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo_fam;
2514  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo_fam;
2515  pdt->pl_state = (plD_state_fp) plD_state_cairo_fam;
2516  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo_fam;
2517 }
2518 
2519 //--------------------------------------------------------------------------
2520 // plD_init_epscairo()
2521 //
2522 // Initialize Cairo EPS device
2523 //--------------------------------------------------------------------------
2524 
2525 void plD_init_epscairo( PLStream *pls )
2526 {
2527  PLCairo *aStream;
2528 
2529  // Setup the PLStream and the font lookup table and allocate a cairo
2530  // stream structure.
2531  //
2532  // NOTE: The check below is necessary since, in family mode, this function
2533  // will be called multiple times. While you might think that it is
2534  // sufficient to update what *should* be the only pointer to the contents
2535  // of pls->dev, i.e. the pointer pls->dev itself, it appears that
2536  // something else somewhere else is also pointing to pls->dev. If you
2537  // change what pls->dev points to then you will get a "bus error", from
2538  // which I infer the existence of said bad stale pointer.
2539  //
2540  if ( pls->dev == NULL )
2541  {
2542  aStream = stream_and_font_setup( pls, 0 );
2543  }
2544  else
2545  {
2546  stream_and_font_setup( pls, 0 );
2547  aStream = pls->dev;
2548  }
2549 
2550  // Initialize family file info
2551  plFamInit( pls );
2552 
2553  // Prompt for a file name if not already set.
2554  plOpenFile( pls );
2555 
2556  // Create an cairo surface & context for EPS file.
2557  // Dimension units are pts = 1/72 inches from cairo documentation.
2558  aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
2559  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2560 
2561  // Set the PS surface to be EPS.
2562  cairo_ps_surface_set_eps( aStream->cairoSurface, 1 );
2563 
2564  // Save the pointer to the structure in the PLplot stream
2565  pls->dev = aStream;
2566 
2567  // Handle portrait or landscape
2568  if ( pls->portrait )
2569  {
2570  plsdiori( 1 );
2571  pls->freeaspect = 1;
2572  }
2573  rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, (float) pls->ylength, (float) pls->xlength, FALSE );
2574 
2575  // Set fill rule for the case of self-intersecting boundaries.
2576  if ( pls->dev_eofill )
2577  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2578  else
2579  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2580 }
2581 
2582 #endif
2583 
2584 
2585 //--------------------------------------------------------------------------
2586 //--------------------------------------------------------------------------
2587 //
2588 // That which is specific to the cairo SVG driver.
2589 //
2590 //--------------------------------------------------------------------------
2591 //--------------------------------------------------------------------------
2592 
2593 #if defined ( PLD_svgcairo )
2594 
2596 void plD_init_svgcairo( PLStream * );
2597 
2598 //--------------------------------------------------------------------------
2599 // dispatch_init_init()
2600 //
2601 // Initialize device dispatch table
2602 //--------------------------------------------------------------------------
2603 
2604 // svgcairo
2606 {
2607 #ifndef ENABLE_DYNDRIVERS
2608  pdt->pl_MenuStr = "Cairo SVG Driver";
2609  pdt->pl_DevName = "svgcairo";
2610 #endif
2612  pdt->pl_seq = 103;
2613  pdt->pl_init = (plD_init_fp) plD_init_svgcairo;
2614  pdt->pl_line = (plD_line_fp) plD_line_cairo_fam;
2615  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
2616  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo_fam;
2617  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo_fam;
2618  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo_fam;
2619  pdt->pl_state = (plD_state_fp) plD_state_cairo_fam;
2620  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo_fam;
2621 }
2622 
2623 //--------------------------------------------------------------------------
2624 // plD_init_svgcairo()
2625 //
2626 // Initialize Cairo SVG device
2627 //--------------------------------------------------------------------------
2628 
2629 void plD_init_svgcairo( PLStream *pls )
2630 {
2631  PLCairo *aStream;
2632 
2633  // Setup the PLStream and the font lookup table and allocate a cairo
2634  // stream structure.
2635  //
2636  // NOTE: The check below is necessary since, in family mode, this function
2637  // will be called multiple times. While you might think that it is
2638  // sufficient to update what *should* be the only pointer to the contents
2639  // of pls->dev, i.e. the pointer pls->dev itself, it appears that
2640  // something else somewhere else is also pointing to pls->dev. If you
2641  // change what pls->dev points to then you will get a "bus error", from
2642  // which I infer the existence of said bad stale pointer.
2643  //
2644  if ( pls->dev == NULL )
2645  {
2646  aStream = stream_and_font_setup( pls, 0 );
2647  }
2648  else
2649  {
2650  stream_and_font_setup( pls, 0 );
2651  aStream = pls->dev;
2652  }
2653 
2654  // Initialize family file info
2655  plFamInit( pls );
2656 
2657  // Prompt for a file name if not already set.
2658  plOpenFile( pls );
2659 
2660  // Save the pointer to the structure in the PLplot stream
2661  pls->dev = aStream;
2662 
2663  // Create an cairo surface & context for SVG file.
2664  // Dimension units are pts = 1/72 inches from cairo documentation.
2665  aStream->cairoSurface = cairo_svg_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
2666  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2667 
2668  // Invert the surface so that the graphs are drawn right side up.
2669  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2670 
2671  // Set graphics aliasing
2672  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2673 
2674  // Set fill rule for the case of self-intersecting boundaries.
2675  if ( pls->dev_eofill )
2676  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2677  else
2678  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2679 }
2680 
2681 #endif
2682 
2683 
2684 //--------------------------------------------------------------------------
2685 //--------------------------------------------------------------------------
2686 //
2687 // That which is specific to the cairo PNG driver.
2688 //
2689 //--------------------------------------------------------------------------
2690 //--------------------------------------------------------------------------
2691 
2692 #if defined ( PLD_pngcairo )
2693 
2695 void plD_init_pngcairo( PLStream * );
2696 void plD_eop_pngcairo( PLStream * );
2697 
2698 //--------------------------------------------------------------------------
2699 // dispatch_init_init()
2700 //
2701 // Initialize device dispatch table
2702 //--------------------------------------------------------------------------
2703 
2704 // pngcairo
2706 {
2707 #ifndef ENABLE_DYNDRIVERS
2708  pdt->pl_MenuStr = "Cairo PNG Driver";
2709  pdt->pl_DevName = "pngcairo";
2710 #endif
2712  pdt->pl_seq = 104;
2713  pdt->pl_init = (plD_init_fp) plD_init_pngcairo;
2714  pdt->pl_line = (plD_line_fp) plD_line_cairo_fam;
2715  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
2716  pdt->pl_eop = (plD_eop_fp) plD_eop_pngcairo;
2717  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo_fam;
2718  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo_fam;
2719  pdt->pl_state = (plD_state_fp) plD_state_cairo_fam;
2720  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo_fam;
2721 }
2722 
2723 //--------------------------------------------------------------------------
2724 // plD_init_pngcairo()
2725 //
2726 // Initialize Cairo PNG device
2727 //--------------------------------------------------------------------------
2728 
2729 void plD_init_pngcairo( PLStream *pls )
2730 {
2731  PLCairo *aStream;
2732 
2733  // Setup the PLStream and the font lookup table and allocate a cairo
2734  // stream structure.
2735  //
2736  // NOTE: The check below is necessary since, in family mode, this function
2737  // will be called multiple times. While you might think that it is
2738  // sufficient to update what *should* be the only pointer to the contents
2739  // of pls->dev, i.e. the pointer pls->dev itself, it appears that
2740  // something else somewhere else is also pointing to pls->dev. If you
2741  // change what pls->dev points to then you will get a "bus error", from
2742  // which I infer the existence of said bad stale pointer.
2743  //
2744  if ( pls->dev == NULL )
2745  {
2746  aStream = stream_and_font_setup( pls, 0 );
2747  }
2748  else
2749  {
2750  stream_and_font_setup( pls, 0 );
2751  aStream = pls->dev;
2752  }
2753 
2754  // Initialize family file info
2755  plFamInit( pls );
2756 
2757  // Prompt for a file name if not already set.
2758  plOpenFile( pls );
2759 
2760  // Save the pointer to the structure in the PLplot stream
2761  pls->dev = aStream;
2762 
2763  // Create a new cairo surface & context for PNG file.
2764  // Dimension units are pixels from cairo documentation.
2765  aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (int) pls->xlength, (int) pls->ylength );
2766  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2767 
2768  // Invert the surface so that the graphs are drawn right side up.
2769  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2770 
2771  // Set graphics aliasing
2772  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2773 
2774  // Set fill rule for the case of self-intersecting boundaries.
2775  if ( pls->dev_eofill )
2776  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2777  else
2778  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2779 }
2780 
2781 //--------------------------------------------------------------------------
2782 // plD_eop_pngcairo()
2783 //
2784 // PNG: End of page.
2785 //--------------------------------------------------------------------------
2786 
2787 void plD_eop_pngcairo( PLStream *pls )
2788 {
2789  PLCairo *aStream;
2790 
2791  if ( cairo_family_check( pls ) )
2792  {
2793  return;
2794  }
2795 
2796  aStream = (PLCairo *) pls->dev;
2797  cairo_surface_write_to_png_stream( aStream->cairoSurface, (cairo_write_func_t) write_to_stream, pls->OutFile );
2798 }
2799 
2800 #endif
2801 
2802 
2803 //--------------------------------------------------------------------------
2804 //--------------------------------------------------------------------------
2805 //
2806 // That which is specific to the cairo memory driver.
2807 //
2808 //--------------------------------------------------------------------------
2809 //--------------------------------------------------------------------------
2810 
2811 #if defined ( PLD_memcairo )
2812 
2814 void plD_init_memcairo( PLStream * );
2815 void plD_eop_memcairo( PLStream * );
2816 void plD_bop_memcairo( PLStream * );
2817 
2818 //--------------------------------------------------------------------------
2819 // dispatch_init_init()
2820 //
2821 // Initialize device dispatch table
2822 //--------------------------------------------------------------------------
2823 
2824 // memcairo
2826 {
2827 #ifndef ENABLE_DYNDRIVERS
2828  pdt->pl_MenuStr = "Cairo memory driver";
2829  pdt->pl_DevName = "memcairo";
2830 #endif
2832  pdt->pl_seq = 105;
2833  pdt->pl_init = (plD_init_fp) plD_init_memcairo;
2836  pdt->pl_eop = (plD_eop_fp) plD_eop_memcairo;
2837  pdt->pl_bop = (plD_bop_fp) plD_bop_memcairo;
2840  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2841 }
2842 
2843 //--------------------------------------------------------------------------
2844 // plD_bop_memcairo()
2845 //
2846 // Set up for the next page.
2847 //--------------------------------------------------------------------------
2848 
2849 void plD_bop_memcairo( PLStream * PL_UNUSED( pls ) )
2850 {
2851  // nothing to do here (we want to preserve the memory as it is)
2852 }
2853 
2854 //--------------------------------------------------------------------------
2855 // plD_init_memcairo()
2856 //
2857 // Initialize Cairo memory device
2858 //--------------------------------------------------------------------------
2859 
2860 void plD_init_memcairo( PLStream *pls )
2861 {
2862  PLCairo *aStream;
2863  int stride, i;
2864  unsigned char *cairo_mem;
2865  unsigned char *input_mem;
2866 
2867  // used for checking byte order
2868  union
2869  {
2870  int testWord;
2871  char testByte[sizeof ( int )];
2872  } endianTest;
2873  endianTest.testWord = 1;
2874 
2875  // Set the plot size to the memory buffer size, on the off chance
2876  // that they are different.
2877  pls->xlength = pls->phyxma;
2878  pls->ylength = pls->phyyma;
2879 
2880 
2881  // Setup the PLStream and the font lookup table
2882  aStream = stream_and_font_setup( pls, 0 );
2883 
2884  // Test byte order
2885  if ( endianTest.testByte[0] == 1 )
2886  aStream->bigendian = 0;
2887  else
2888  aStream->bigendian = 1;
2889 
2890  // Check that user supplied us with some memory to draw in
2891  if ( pls->dev == NULL )
2892  {
2893  plexit( "Must call plsmem first to set user plotting area!" );
2894  }
2895 
2896  // Save a pointer to the memory.
2897  aStream->memory = pls->dev;
2898 
2899  // Create a cairo surface & context. Copy data in from the input memory area
2900 
2901  // Malloc memory the way cairo likes it. Aligned on the stride computed by cairo_format_stride_for_width
2902  // and in the RGB24 format (from http://cairographics.org/manual/cairo-Image-Surfaces.html):
2903  // Each pixel is a 32-bit quantity, with the upper 8 bits unused.
2904  // Red, Green, and Blue are stored in the remaining 24 bits in that order
2905  stride = pls->xlength * 4;
2906  // stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pls->xlength); This function missing from version 1.4 :-(
2907  aStream->cairo_format_memory = (unsigned char *) calloc( (size_t) ( stride * pls->ylength ), 1 );
2908 
2909  // Copy the input data into the Cairo data format
2910  cairo_mem = aStream->cairo_format_memory;
2911  input_mem = aStream->memory;
2912 
2913  // 32 bit word order
2914  // cairo mem: Big endian: 0=A, 1=R, 2=G, 3=B
2915  // Little endian: 3=A, 2=R, 1=G, 0=B
2916 
2917  if ( aStream->bigendian )
2918  {
2919  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2920  {
2921  cairo_mem[1] = input_mem[0]; // R
2922  cairo_mem[2] = input_mem[1]; // G
2923  cairo_mem[3] = input_mem[2]; // B
2924  if ( pls->dev_mem_alpha == 1 )
2925  {
2926  cairo_mem[0] = input_mem[3];
2927  input_mem += 4;
2928  }
2929  else
2930  {
2931  input_mem += 3;
2932  }
2933  cairo_mem += 4;
2934  }
2935  }
2936  else
2937  {
2938  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2939  {
2940  cairo_mem[2] = input_mem[0]; // R
2941  cairo_mem[1] = input_mem[1]; // G
2942  cairo_mem[0] = input_mem[2]; // B
2943  if ( pls->dev_mem_alpha == 1 )
2944  {
2945  cairo_mem[3] = input_mem[3];
2946  input_mem += 4;
2947  }
2948  else
2949  {
2950  input_mem += 3;
2951  }
2952  cairo_mem += 4;
2953  }
2954  }
2955 
2956  // Create a Cairo drawing surface from the input data
2957  aStream->cairoSurface =
2958  // Dimension units are width, height of buffer image from cairo
2959  // documentation.
2960  cairo_image_surface_create_for_data( aStream->cairo_format_memory, CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength, stride );
2961  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2962 
2963  // Save the pointer to the structure in the PLplot stream.
2964  // Note that this wipes out the direct pointer to the memory buffer.
2965  pls->dev = aStream;
2966 
2967  // Invert the surface so that the graphs are drawn right side up.
2968  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2969 
2970  // Set graphics aliasing
2971  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2972 
2973  // Set fill rule for the case of self-intersecting boundaries.
2974  if ( pls->dev_eofill )
2975  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2976  else
2977  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2978 }
2979 
2980 //--------------------------------------------------------------------------
2981 // plD_eop_memcairo()
2982 //
2983 // Memory device specific end of page. This copies the contents
2984 // of the cairo surface into the user supplied memory buffer.
2985 //--------------------------------------------------------------------------
2986 
2987 void plD_eop_memcairo( PLStream *pls )
2988 {
2989  int i;
2990  unsigned char *memory;
2991  unsigned char *cairo_surface_data;
2992  PLCairo *aStream;
2993 
2994  aStream = (PLCairo *) pls->dev;
2995  memory = aStream->memory;
2996  cairo_surface_data = cairo_image_surface_get_data( aStream->cairoSurface );
2997  // 32 bit word order
2998  // cairo mem: Big endian: 0=A, 1=R, 2=G, 3=B
2999  // Little endian: 3=A, 2=R, 1=G, 0=B
3000  if ( aStream->bigendian )
3001  {
3002  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
3003  {
3004  memory[0] = cairo_surface_data[1]; // R
3005  memory[1] = cairo_surface_data[2]; // G
3006  memory[2] = cairo_surface_data[3]; // B
3007  if ( pls->dev_mem_alpha == 1 )
3008  {
3009  memory[3] = cairo_surface_data[0];
3010  memory += 4;
3011  }
3012  else
3013  {
3014  memory += 3;
3015  }
3016  cairo_surface_data += 4;
3017  }
3018  }
3019  else
3020  {
3021  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
3022  {
3023  memory[0] = cairo_surface_data[2]; // R
3024  memory[1] = cairo_surface_data[1]; // G
3025  memory[2] = cairo_surface_data[0]; // B
3026  if ( pls->dev_mem_alpha == 1 )
3027  {
3028  memory[3] = cairo_surface_data[3];
3029  memory += 4;
3030  }
3031  else
3032  {
3033  memory += 3;
3034  }
3035  cairo_surface_data += 4;
3036  }
3037  }
3038 
3039  // Free up the temporary memory malloc'ed in plD_init_memcairo
3040  free( aStream->cairo_format_memory );
3041 }
3042 
3043 #endif
3044 
3045 //--------------------------------------------------------------------------
3046 //--------------------------------------------------------------------------
3047 //
3048 // That which is specific to the cairo external context driver.
3049 //
3050 //--------------------------------------------------------------------------
3051 //--------------------------------------------------------------------------
3052 
3053 #if defined ( PLD_extcairo )
3054 
3055 void extcairo_setbackground( PLStream * );
3057 void plD_init_extcairo( PLStream * );
3058 void plD_bop_extcairo( PLStream * );
3059 void plD_eop_extcairo( PLStream * );
3060 void plD_esc_extcairo( PLStream *, PLINT, void * );
3061 void plD_tidy_extcairo( PLStream * );
3062 
3063 //--------------------------------------------------------------------------
3064 // extcairo_setbackground()
3065 //
3066 // Set the background color for the extcairo device
3067 //--------------------------------------------------------------------------
3068 
3069 void extcairo_setbackground( PLStream *pls )
3070 {
3071  PLCairo *aStream;
3072 
3073  aStream = (PLCairo *) pls->dev;
3074 
3075  // Fill the context with the background color if the user so desires.
3076  if ( aStream->cairoContext != NULL )
3077  {
3078  cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
3079  cairo_set_source_rgba( aStream->cairoContext,
3080  (double) pls->cmap0[0].r / 255.0,
3081  (double) pls->cmap0[0].g / 255.0,
3082  (double) pls->cmap0[0].b / 255.0,
3083  (double) pls->cmap0[0].a );
3084  cairo_fill( aStream->cairoContext );
3085  }
3086 }
3087 
3088 //--------------------------------------------------------------------------
3089 // dispatch_init_init()
3090 //
3091 // Initialize device dispatch table
3092 //--------------------------------------------------------------------------
3093 
3094 // extcairo
3096 {
3097 #ifndef ENABLE_DYNDRIVERS
3098  pdt->pl_MenuStr = "Cairo external context driver";
3099  pdt->pl_DevName = "extcairo";
3100 #endif
3102  pdt->pl_seq = 106;
3103  pdt->pl_init = (plD_init_fp) plD_init_extcairo;
3106  pdt->pl_bop = (plD_bop_fp) plD_bop_extcairo;
3107  pdt->pl_eop = (plD_eop_fp) plD_eop_extcairo;
3108  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_extcairo;
3110  pdt->pl_esc = (plD_esc_fp) plD_esc_extcairo;
3111 }
3112 
3113 //--------------------------------------------------------------------------
3114 // plD_init_extcairo()
3115 //
3116 // Initialize Cairo external context driver.
3117 //--------------------------------------------------------------------------
3118 
3119 void plD_init_extcairo( PLStream *pls )
3120 {
3121  PLCairo *aStream;
3122 
3123  // Setup the PLStream and the font lookup table
3124  aStream = stream_and_font_setup( pls, 0 );
3125 
3126  // Save the pointer to the structure in the PLplot stream
3127  pls->dev = aStream;
3128 }
3129 
3130 //--------------------------------------------------------------------------
3131 // plD_bop_extcairo()
3132 //
3133 // Set up for the next page.
3134 //--------------------------------------------------------------------------
3135 
3136 void plD_bop_extcairo( PLStream *pls )
3137 {
3138  PLCairo *aStream;
3139 
3140  aStream = (PLCairo *) pls->dev;
3141 
3142  // Set background if desired
3143  if ( aStream->set_background )
3144  {
3145  extcairo_setbackground( pls );
3146  }
3147 }
3148 
3149 //--------------------------------------------------------------------------
3150 // plD_eop_extcairo()
3151 //
3152 // End of page.
3153 //--------------------------------------------------------------------------
3154 
3155 void plD_eop_extcairo( PLStream * PL_UNUSED( pls ) )
3156 {
3157  // nothing to do here, we leave it to the calling program to display
3158  // (or not) the update cairo context.
3159 }
3160 
3161 //--------------------------------------------------------------------------
3162 // plD_esc_extcairo()
3163 //
3164 // The generic escape function, extended so that user can pass in
3165 // an external Cairo context to use for rendering.
3166 //--------------------------------------------------------------------------
3167 
3168 void plD_esc_extcairo( PLStream *pls, PLINT op, void *ptr )
3169 {
3170  PLCairo *aStream;
3171 
3172  aStream = (PLCairo *) pls->dev;
3173 
3174  switch ( op )
3175  {
3176  case PLESC_DEVINIT: // Set external context
3177  aStream->cairoContext = (cairo_t *) ptr;
3178  // Set graphics aliasing
3179  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
3180 
3181  // Invert the surface so that the graphs are drawn right side up.
3182  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
3183 
3184  // Should adjust plot size to fit in the given cairo context?
3185  // Cairo does not provide a way to query the dimensions of a context?
3186 
3187  // Set background if desired
3188  if ( aStream->set_background )
3189  {
3190  extcairo_setbackground( pls );
3191  }
3192 
3193  // Set fill rule for the case of self-intersecting boundaries.
3194  if ( pls->dev_eofill )
3195  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
3196  else
3197  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
3198  break;
3199  default: // Fall back on default Cairo actions
3200  plD_esc_cairo( pls, op, ptr );
3201  break;
3202  }
3203 }
3204 
3205 //--------------------------------------------------------------------------
3206 // plD_tidy_extcairo()
3207 //
3208 // This is nop, it is up to the calling program to clean up the Cairo
3209 // context, etc...
3210 //--------------------------------------------------------------------------
3211 
3212 void plD_tidy_extcairo( PLStream * PL_UNUSED( pls ) )
3213 {
3214 }
3215 
3216 #endif
3217 
3218 
3219 //--------------------------------------------------------------------------
3220 //--------------------------------------------------------------------------
3221 //
3222 // That which is specific to the cairo microsoft windows driver.
3223 //
3224 // Much of the Windows specific code here was lifted from the wingcc
3225 // driver.
3226 //
3227 //--------------------------------------------------------------------------
3228 //--------------------------------------------------------------------------
3229 
3230 #if defined ( PLD_wincairo )
3231 
3232 static char* szWndClass = "PLplot WinCairo";
3233 
3235 void plD_init_wincairo( PLStream * );
3236 //void plD_bop_extcairo( PLStream * );
3237 void plD_eop_wincairo( PLStream * );
3238 void plD_esc_wincairo( PLStream *, PLINT, void * );
3239 void plD_tidy_wincairo( PLStream * );
3240 
3241 //--------------------------------------------------------------------------
3242 // blit_to_win()
3243 //
3244 // Blit the offscreen image to the Windows window.
3245 //--------------------------------------------------------------------------
3246 
3247 void blit_to_win( PLCairo *aStream )
3248 {
3249  cairo_set_source_surface( aStream->cairoContext_win, aStream->cairoSurface, 0.0, 0.0 );
3250  cairo_paint( aStream->cairoContext_win );
3251 }
3252 
3253 //--------------------------------------------------------------------------
3254 // This is the window function for the plot window. Whenever a message is
3255 // dispatched using DispatchMessage (or sent with SendMessage) this function
3256 // gets called with the contents of the message.
3257 //--------------------------------------------------------------------------
3258 
3259 LRESULT CALLBACK PlplotCairoWndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
3260 {
3261  PLStream *pls = NULL;
3262  PLCairo *dev = NULL;
3263 
3264 //
3265 // The window carries a 32bit user defined pointer which points to the
3266 // plplot stream (pls). This is used for tracking the window.
3267 // Unfortunately, this is "attached" to the window AFTER it is created
3268 // so we can not initialise PLStream or wincairo "blindly" because
3269 // they may not yet have been initialised.
3270 // WM_CREATE is called before we get to initialise those variables, so
3271 // we wont try to set them.
3272 //
3273 
3274  if ( nMsg == WM_CREATE )
3275  {
3276  return ( 0 );
3277  }
3278  else
3279  {
3280  pls = (PLStream *) GetWindowLongPtr( hwnd, GWLP_USERDATA ); // Try to get the address to pls for this window
3281  if ( pls ) // If we got it, then we will initialise this windows plplot private data area
3282  {
3283  dev = (PLCairo *) pls->dev;
3284  }
3285  }
3286 
3287 //
3288 // Process the windows messages
3289 //
3290 // Everything except WM_CREATE is done here and it is generally hoped that
3291 // pls and dev are defined already by this stage.
3292 // That will be true MOST of the time. Some times WM_PAINT will be called
3293 // before we get to initialise the user data area of the window with the
3294 // pointer to the windows plplot stream
3295 //
3296 
3297  switch ( nMsg )
3298  {
3299  case WM_DESTROY:
3300  // if ( dev )
3301  // Debug( "WM_DESTROY\t" );
3302  PostQuitMessage( 0 );
3303  return ( 0 );
3304  break;
3305 
3306  case WM_PAINT:
3307  blit_to_win( dev );
3308  return ( 1 );
3309  break;
3310 
3311  case WM_SIZE:
3312  GetClientRect( dev->hwnd, &dev->rect );
3313  return ( 0 );
3314  break;
3315 
3316  case WM_ENTERSIZEMOVE:
3317  return ( 0 );
3318  break;
3319 
3320  case WM_EXITSIZEMOVE:
3321  return ( 0 );
3322  break;
3323 
3324  case WM_ERASEBKGND:
3325  if ( dev )
3326  {
3327  dev->oldcolour = SetBkColor( dev->hdc, RGB( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b ) );
3328  ExtTextOut( dev->hdc, 0, 0, ETO_OPAQUE, &dev->rect, "", 0, 0 );
3329  SetBkColor( dev->hdc, dev->oldcolour );
3330  }
3331  return ( 1 );
3332  break;
3333 
3334  case WM_COMMAND:
3335  return ( 0 );
3336  break;
3337  }
3338 
3339  // If we don't handle a message completely we hand it to the system
3340  // provided default window function.
3341  return DefWindowProc( hwnd, nMsg, wParam, lParam );
3342 }
3343 
3344 //--------------------------------------------------------------------------
3345 // handle_locate()
3346 //
3347 // Handle getting the cursor location.
3348 //--------------------------------------------------------------------------
3349 
3350 void
3351 handle_locate( PLStream *pls, PLGraphicsIn *gin )
3352 {
3353  int located = 0;
3354  PLCairo *aStream = (PLCairo *) pls->dev;
3355 
3356  // Initialize PLplot mouse event structure
3357  plGinInit( gin );
3358 
3359  while ( GetMessage( &aStream->msg, NULL, 0, 0 ) && !located )
3360  {
3361  TranslateMessage( &aStream->msg );
3362 
3363  switch ( (int) aStream->msg.message )
3364  {
3365  case WM_MOUSEMOVE:
3366  case WM_LBUTTONDOWN:
3367  gin->state = 1;
3368  gin->button = 1;
3369  gin->pX = LOWORD( aStream->msg.lParam );
3370  gin->pY = pls->ylength - HIWORD( aStream->msg.lParam );
3371  gin->dX = (PLFLT) LOWORD( aStream->msg.lParam ) / ( (PLFLT) pls->xlength );
3372  gin->dY = (PLFLT) ( pls->ylength - HIWORD( aStream->msg.lParam ) ) / ( (PLFLT) pls->ylength );
3373  break;
3374  case WM_CHAR:
3375  gin->keysym = aStream->msg.wParam;
3376  located = 1;
3377  break;
3378 
3379  default:
3380  DispatchMessage( &aStream->msg );
3381  break;
3382  }
3383  }
3384 }
3385 
3386 //--------------------------------------------------------------------------
3387 // dispatch_init_init()
3388 //
3389 // Initialize device dispatch table
3390 //--------------------------------------------------------------------------
3391 
3392 // extcairo
3394 {
3395 #ifndef ENABLE_DYNDRIVERS
3396  pdt->pl_MenuStr = "Cairo Microsoft Windows driver";
3397  pdt->pl_DevName = "wincairo";
3398 #endif
3400  pdt->pl_seq = 107;
3401  pdt->pl_init = (plD_init_fp) plD_init_wincairo;
3404  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
3405  pdt->pl_eop = (plD_eop_fp) plD_eop_wincairo;
3406  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wincairo;
3408  pdt->pl_esc = (plD_esc_fp) plD_esc_wincairo;
3409 }
3410 
3411 //--------------------------------------------------------------------------
3412 // plD_init_wincairo()
3413 //
3414 // Initialize Cairo Microsoft Windows driver.
3415 //--------------------------------------------------------------------------
3416 
3417 void plD_init_wincairo( PLStream *pls )
3418 {
3419  PLCairo *aStream;
3420 
3421  // Setup the PLStream and the font lookup table
3422  aStream = stream_and_font_setup( pls, 1 );
3423 
3424  // Save the pointer to the structure in the PLplot stream
3425  pls->dev = aStream;
3426 
3427  // Create window
3428  memset( &aStream->wndclass, 0, sizeof ( WNDCLASSEX ) );
3429 
3430  // This class is called WinTestWin
3431  aStream->wndclass.lpszClassName = szWndClass;
3432 
3433  // cbSize gives the size of the structure for extensibility.
3434  aStream->wndclass.cbSize = sizeof ( WNDCLASSEX );
3435 
3436  // All windows of this class redraw when resized.
3437  aStream->wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC | CS_PARENTDC;
3438 
3439  // All windows of this class use the PlplotCairoWndProc window function.
3440  aStream->wndclass.lpfnWndProc = PlplotCairoWndProc;
3441 
3442  // This class is used with the current program instance.
3443 
3444  aStream->wndclass.hInstance = GetModuleHandle( NULL );
3445 
3446  // Use standard application icon and arrow cursor provided by the OS
3447  aStream->wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
3448  aStream->wndclass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
3449  aStream->wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
3450  // Color the background white
3451  aStream->wndclass.hbrBackground = NULL;
3452 
3453  aStream->wndclass.cbWndExtra = sizeof ( pls );
3454 
3455 
3456  //
3457  // Now register the window class for use.
3458  //
3459 
3460  RegisterClassEx( &aStream->wndclass );
3461 
3462  //
3463  // Create our main window using that window class.
3464  //
3465  aStream->hwnd = CreateWindowEx( WS_EX_WINDOWEDGE + WS_EX_LEFT,
3466  szWndClass, // Class name
3467  pls->program, // Caption
3468  WS_OVERLAPPEDWINDOW, // Style
3469  pls->xoffset, // Initial x (use default)
3470  pls->yoffset, // Initial y (use default)
3471  // This is a little lame since the window border size might change.
3472  pls->xlength + 5, // Initial x size (use default)
3473  pls->ylength + 30, // Initial y size (use default)
3474  NULL, // No parent window
3475  NULL, // No menu
3476  aStream->wndclass.hInstance, // This program instance
3477  NULL // Creation parameters
3478  );
3479 
3480 
3481 //
3482 // Attach a pointer to the stream to the window's user area
3483 // this pointer will be used by the windows call back for
3484 // process this window
3485 //
3486 
3487  SetWindowLongPtr( aStream->hwnd, GWLP_USERDATA, (LONG_PTR) pls );
3488  aStream->SCRN_hdc = aStream->hdc = GetDC( aStream->hwnd );
3489 
3490 //
3491 // Setup the popup menu
3492 //
3493 
3494 //
3495 // dev->PopupMenu = CreatePopupMenu();
3496 // AppendMenu( dev->PopupMenu, MF_STRING, PopupPrint, "Print" );
3497 // AppendMenu( dev->PopupMenu, MF_STRING, PopupNextPage, "Next Page" );
3498 // AppendMenu( dev->PopupMenu, MF_STRING, PopupQuit, "Quit" );
3499 //
3500 
3501  // plD_state_wingcc( pls, PLSTATE_COLOR0 );
3502  //
3503  // Display the window which we just created (using the nShow
3504  // passed by the OS, which allows for start minimized and that
3505  // sort of thing).
3506  //
3507  ShowWindow( aStream->hwnd, SW_SHOWDEFAULT );
3508  SetForegroundWindow( aStream->hwnd );
3509 
3510 //
3511 // Now we have to find out, from windows, just how big our drawing area is
3512 // when we specified the page size earlier on, that includes the borders,
3513 // title bar etc... so now that windows has done all its initialisations,
3514 // we will ask how big the drawing area is, and tell plplot
3515 //
3516 
3517 //
3518 // GetClientRect( dev->hwnd, &dev->rect );
3519 // dev->width = dev->rect.right;
3520 // dev->height = dev->rect.bottom;
3521 //
3522 
3523 //
3524 // Initialize Cairo Surface using the windows hdc.
3525 //
3526 
3527  // This is the Win32 Cairo surface.
3528  aStream->cairoSurface_win = (cairo_surface_t *) cairo_win32_surface_create( aStream->hdc );
3529  aStream->cairoContext_win = cairo_create( aStream->cairoSurface_win );
3530 
3531  // This is the Cairo surface PLplot will actually plot to.
3532  aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength );
3533  aStream->cairoContext = cairo_create( aStream->cairoSurface );
3534 
3535  // Invert the surface so that the graphs are drawn right side up.
3536  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
3537 
3538  // Set graphics aliasing
3539  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
3540 
3541  // Set fill rule for the case of self-intersecting boundaries.
3542  if ( pls->dev_eofill )
3543  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
3544  else
3545  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
3546 }
3547 
3548 //--------------------------------------------------------------------------
3549 // plD_eop_wincairo()
3550 //
3551 // Clean up Cairo Microsoft Windows driver.
3552 //--------------------------------------------------------------------------
3553 
3554 void
3555 plD_eop_wincairo( PLStream *pls )
3556 {
3557  PLCairo *aStream = (PLCairo *) pls->dev;
3558 
3559  if ( !pls->nopause )
3560  {
3561  while ( GetMessage( &aStream->msg, NULL, 0, 0 ) )
3562  {
3563  TranslateMessage( &aStream->msg );
3564  switch ( (int) aStream->msg.message )
3565  {
3566  case WM_CHAR:
3567  if ( ( (TCHAR) ( aStream->msg.wParam ) == 13 ) ||
3568  ( (TCHAR) ( aStream->msg.wParam ) == 'q' ) ||
3569  ( (TCHAR) ( aStream->msg.wParam ) == 'Q' ) )
3570  {
3571  PostQuitMessage( 0 );
3572  }
3573  break;
3574 
3575  default:
3576  DispatchMessage( &aStream->msg );
3577  break;
3578  }
3579  }
3580  }
3581 }
3582 
3583 //--------------------------------------------------------------------------
3584 // plD_tidy_wincairo()
3585 //
3586 // Clean up Cairo Microsoft Windows driver.
3587 //--------------------------------------------------------------------------
3588 
3589 void plD_tidy_wincairo( PLStream *pls )
3590 {
3591  PLCairo *aStream = (PLCairo *) pls->dev;
3592 
3593  plD_tidy_cairo( pls );
3594 
3595  // Also free up the Cairo win32 surface and context
3596  cairo_destroy( aStream->cairoContext_win );
3597  cairo_surface_destroy( aStream->cairoSurface_win );
3598 
3599  if ( aStream != NULL )
3600  {
3601  if ( aStream->hdc != NULL )
3602  ReleaseDC( aStream->hwnd, aStream->hdc );
3603  free_mem( pls->dev );
3604  }
3605 }
3606 
3607 //--------------------------------------------------------------------------
3608 // plD_esc_wincairo()
3609 //
3610 // Escape function, specialized for the wincairo driver
3611 //--------------------------------------------------------------------------
3612 
3613 void plD_esc_wincairo( PLStream *pls, PLINT op, void *ptr )
3614 {
3615  PLCairo *aStream;
3616 
3617  aStream = (PLCairo *) pls->dev;
3618 
3619  switch ( op )
3620  {
3621  case PLESC_FLUSH:
3622  InvalidateRect( aStream->hwnd, NULL, TRUE );
3623  break;
3624  case PLESC_GETC:
3625  handle_locate( pls, (PLGraphicsIn *) ptr );
3626  break;
3627  default:
3628  plD_esc_cairo( pls, op, ptr );
3629  break;
3630  }
3631 }
3632 
3633 #endif