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