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