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  plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / aStream->downscale ), (PLINT) 0,
2190  (PLINT) ( pls->ylength / aStream->downscale ) );
2191 
2192  // Associate cairo with the supplied drawable
2193  xcairo_init_cairo( pls );
2194 
2195  // Recalculate dimensions and the like now that the drawable is known
2196  plbop();
2197 
2198  break;
2199  }
2200  default:
2201  plD_esc_cairo( pls, op, ptr );
2202  break;
2203  }
2204 }
2205 
2206 //--------------------------------------------------------------------------
2207 // xcairo_get_cursor()
2208 //
2209 // X Windows: returns the location of the next mouse click or key press.
2210 //--------------------------------------------------------------------------
2211 
2212 void xcairo_get_cursor( PLStream *pls, PLGraphicsIn *gin )
2213 {
2214  const char *ksname;
2215  char str[257];
2216  KeySym keysym;
2217  XEvent event;
2218  XButtonEvent *xButtonEvent;
2219  Cursor xHairCursor;
2220  PLCairo *aStream;
2221 
2222  aStream = (PLCairo *) pls->dev;
2223 
2224  // Initialize PLplot mouse event structure
2225  plGinInit( gin );
2226 
2227  // Create cross hair cursor & switch to using it
2228  xHairCursor = XCreateFontCursor( aStream->XDisplay, XC_crosshair );
2229  XDefineCursor( aStream->XDisplay, aStream->XWindow, xHairCursor );
2230 
2231  // Get the next mouse button release or key press event
2232  XSelectInput( aStream->XDisplay, aStream->XWindow, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask );
2233  XMaskEvent( aStream->XDisplay, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask, &event );
2234  XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
2235 
2236  // Update PLplot's mouse event structure
2237  xButtonEvent = (XButtonEvent *) &event;
2238  gin->state = xButtonEvent->state;
2239  gin->button = xButtonEvent->button;
2240  gin->pX = event.xbutton.x;
2241  gin->pY = pls->ylength - event.xbutton.y;
2242  gin->dX = (PLFLT) event.xbutton.x / ( (PLFLT) ( pls->xlength ) );
2243  gin->dY = (PLFLT) ( pls->ylength - event.xbutton.y ) / ( (PLFLT) ( pls->ylength ) );
2244 
2245  // Get key pressed (if any)
2246  if ( event.type == KeyPress || event.type == KeyRelease )
2247  {
2248  XLookupString( (XKeyEvent *) &event, str, 100, &keysym, NULL );
2249  if ( keysym == NoSymbol )
2250  ksname = "NoSymbol";
2251  else if ( !( ksname = XKeysymToString( keysym ) ) )
2252  ksname = "(no name)";
2253  strcpy( gin->string, ksname );
2254  // gin->string[number_chars] = '\0';
2255  switch ( keysym )
2256  {
2257  case XK_BackSpace:
2258  case XK_Tab:
2259  case XK_Linefeed:
2260  case XK_Return:
2261  case XK_Escape:
2262  case XK_Delete:
2263  gin->keysym = 0xFF & keysym;
2264  break;
2265  default:
2266  gin->keysym = (unsigned int) keysym;
2267  }
2268  }
2269  else // button press
2270  {
2271  sprintf( gin->string, "button %u", gin->button );
2272  gin->keysym = 0x20;
2273  }
2274 
2275  // Switch back to normal cursor
2276  XUndefineCursor( aStream->XDisplay, aStream->XWindow );
2277  XFlush( aStream->XDisplay );
2278 }
2279 
2280 #endif
2281 
2282 
2283 //--------------------------------------------------------------------------
2284 //--------------------------------------------------------------------------
2285 //
2286 // That which is specific to the cairo PDF driver.
2287 //
2288 //--------------------------------------------------------------------------
2289 //--------------------------------------------------------------------------
2290 
2291 #if defined ( PLD_pdfcairo )
2292 
2294 void plD_init_pdfcairo( PLStream * );
2295 
2296 //--------------------------------------------------------------------------
2297 // dispatch_init_init()
2298 //
2299 // Initialize device dispatch table
2300 //--------------------------------------------------------------------------
2301 
2302 // pdfcairo
2304 {
2305 #ifndef ENABLE_DYNDRIVERS
2306  pdt->pl_MenuStr = "Cairo PDF Driver";
2307  pdt->pl_DevName = "pdfcairo";
2308 #endif
2310  pdt->pl_seq = 101;
2311  pdt->pl_init = (plD_init_fp) plD_init_pdfcairo;
2314  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2315  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2318  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2319 }
2320 
2321 //--------------------------------------------------------------------------
2322 // plD_init_pdfcairo()
2323 //
2324 // Initialize Cairo PDF device
2325 //--------------------------------------------------------------------------
2326 
2327 void plD_init_pdfcairo( PLStream *pls )
2328 {
2329  PLCairo *aStream;
2330 
2331  // Setup the PLStream and the font lookup table
2332  aStream = stream_and_font_setup( pls, 0 );
2333 
2334  // Prompt for a file name if not already set.
2335  plOpenFile( pls );
2336 
2337  // Create an cairo surface & context for PDF file.
2338  // Dimension units are pts = 1/72 inches from cairo documentation.
2339  aStream->cairoSurface = cairo_pdf_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
2340  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2341 
2342  // Save the pointer to the structure in the PLplot stream
2343  pls->dev = aStream;
2344 
2345  // Invert the surface so that the graphs are drawn right side up.
2346  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2347 
2348  // Set graphics aliasing
2349  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2350 
2351  // Set fill rule for the case of self-intersecting boundaries.
2352  if ( pls->dev_eofill )
2353  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2354  else
2355  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2356 }
2357 
2358 #endif
2359 
2360 
2361 //--------------------------------------------------------------------------
2362 //--------------------------------------------------------------------------
2363 //
2364 // That which is specific to the cairo PS driver.
2365 //
2366 //--------------------------------------------------------------------------
2367 //--------------------------------------------------------------------------
2368 
2369 #if defined ( PLD_pscairo )
2370 
2372 void plD_init_pscairo( PLStream * );
2373 
2374 //--------------------------------------------------------------------------
2375 // dispatch_init_init()
2376 //
2377 // Initialize device dispatch table
2378 //--------------------------------------------------------------------------
2379 
2380 // pscairo
2382 {
2383 #ifndef ENABLE_DYNDRIVERS
2384  pdt->pl_MenuStr = "Cairo PS Driver";
2385  pdt->pl_DevName = "pscairo";
2386 #endif
2388  pdt->pl_seq = 102;
2389  pdt->pl_init = (plD_init_fp) plD_init_pscairo;
2392  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2393  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2396  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2397 }
2398 
2399 //--------------------------------------------------------------------------
2400 // plD_init_pscairo()
2401 //
2402 // Initialize Cairo PS device
2403 //--------------------------------------------------------------------------
2404 
2405 void plD_init_pscairo( PLStream *pls )
2406 {
2407  PLCairo *aStream;
2408 
2409  // Setup the PLStream and the font lookup table
2410  aStream = stream_and_font_setup( pls, 0 );
2411 
2412  // Prompt for a file name if not already set.
2413  plOpenFile( pls );
2414 
2415  // Create an cairo surface & context for PS file.
2416  // Dimension units are pts = 1/72 inches from cairo documentation.
2417  aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
2418  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2419 
2420  // Save the pointer to the structure in the PLplot stream
2421  pls->dev = aStream;
2422 
2423  // Handle portrait or landscape
2424  if ( pls->portrait )
2425  {
2426  plsdiori( 1 );
2427  pls->freeaspect = 1;
2428  }
2429  rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, (float) pls->ylength, (float) pls->xlength, FALSE );
2430 
2431  // Set fill rule for the case of self-intersecting boundaries.
2432  if ( pls->dev_eofill )
2433  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2434  else
2435  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2436 }
2437 
2438 #endif
2439 
2440 
2441 //--------------------------------------------------------------------------
2442 //--------------------------------------------------------------------------
2443 //
2444 // That which is specific to the cairo EPS driver.
2445 //
2446 //--------------------------------------------------------------------------
2447 //--------------------------------------------------------------------------
2448 
2449 #if defined ( PLD_epscairo )
2450 
2452 void plD_init_epscairo( PLStream * );
2453 
2454 //--------------------------------------------------------------------------
2455 // dispatch_init_init()
2456 //
2457 // Initialize device dispatch table
2458 //--------------------------------------------------------------------------
2459 
2460 // epscairo
2462 {
2463 #ifndef ENABLE_DYNDRIVERS
2464  pdt->pl_MenuStr = "Cairo EPS Driver";
2465  pdt->pl_DevName = "epscairo";
2466 #endif
2468  pdt->pl_seq = 102;
2469  pdt->pl_init = (plD_init_fp) plD_init_epscairo;
2470  pdt->pl_line = (plD_line_fp) plD_line_cairo_fam;
2471  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
2472  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo_fam;
2473  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo_fam;
2474  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo_fam;
2475  pdt->pl_state = (plD_state_fp) plD_state_cairo_fam;
2476  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo_fam;
2477 }
2478 
2479 //--------------------------------------------------------------------------
2480 // plD_init_epscairo()
2481 //
2482 // Initialize Cairo EPS device
2483 //--------------------------------------------------------------------------
2484 
2485 void plD_init_epscairo( PLStream *pls )
2486 {
2487  PLCairo *aStream;
2488 
2489  // Setup the PLStream and the font lookup table and allocate a cairo
2490  // stream structure.
2491  //
2492  // NOTE: The check below is necessary since, in family mode, this function
2493  // will be called multiple times. While you might think that it is
2494  // sufficient to update what *should* be the only pointer to the contents
2495  // of pls->dev, i.e. the pointer pls->dev itself, it appears that
2496  // something else somewhere else is also pointing to pls->dev. If you
2497  // change what pls->dev points to then you will get a "bus error", from
2498  // which I infer the existence of said bad stale pointer.
2499  //
2500  if ( pls->dev == NULL )
2501  {
2502  aStream = stream_and_font_setup( pls, 0 );
2503  }
2504  else
2505  {
2506  stream_and_font_setup( pls, 0 );
2507  aStream = pls->dev;
2508  }
2509 
2510  // Initialize family file info
2511  plFamInit( pls );
2512 
2513  // Prompt for a file name if not already set.
2514  plOpenFile( pls );
2515 
2516  // Create an cairo surface & context for EPS file.
2517  // Dimension units are pts = 1/72 inches from cairo documentation.
2518  aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
2519  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2520 
2521  // Set the PS surface to be EPS.
2522  cairo_ps_surface_set_eps( aStream->cairoSurface, 1 );
2523 
2524  // Save the pointer to the structure in the PLplot stream
2525  pls->dev = aStream;
2526 
2527  // Handle portrait or landscape
2528  if ( pls->portrait )
2529  {
2530  plsdiori( 1 );
2531  pls->freeaspect = 1;
2532  }
2533  rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, (float) pls->ylength, (float) pls->xlength, FALSE );
2534 
2535  // Set fill rule for the case of self-intersecting boundaries.
2536  if ( pls->dev_eofill )
2537  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2538  else
2539  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2540 }
2541 
2542 #endif
2543 
2544 
2545 //--------------------------------------------------------------------------
2546 //--------------------------------------------------------------------------
2547 //
2548 // That which is specific to the cairo SVG driver.
2549 //
2550 //--------------------------------------------------------------------------
2551 //--------------------------------------------------------------------------
2552 
2553 #if defined ( PLD_svgcairo )
2554 
2556 void plD_init_svgcairo( PLStream * );
2557 
2558 //--------------------------------------------------------------------------
2559 // dispatch_init_init()
2560 //
2561 // Initialize device dispatch table
2562 //--------------------------------------------------------------------------
2563 
2564 // svgcairo
2566 {
2567 #ifndef ENABLE_DYNDRIVERS
2568  pdt->pl_MenuStr = "Cairo SVG Driver";
2569  pdt->pl_DevName = "svgcairo";
2570 #endif
2572  pdt->pl_seq = 103;
2573  pdt->pl_init = (plD_init_fp) plD_init_svgcairo;
2574  pdt->pl_line = (plD_line_fp) plD_line_cairo_fam;
2575  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
2576  pdt->pl_eop = (plD_eop_fp) plD_eop_cairo_fam;
2577  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo_fam;
2578  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo_fam;
2579  pdt->pl_state = (plD_state_fp) plD_state_cairo_fam;
2580  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo_fam;
2581 }
2582 
2583 //--------------------------------------------------------------------------
2584 // plD_init_svgcairo()
2585 //
2586 // Initialize Cairo SVG device
2587 //--------------------------------------------------------------------------
2588 
2589 void plD_init_svgcairo( PLStream *pls )
2590 {
2591  PLCairo *aStream;
2592 
2593  // Setup the PLStream and the font lookup table and allocate a cairo
2594  // stream structure.
2595  //
2596  // NOTE: The check below is necessary since, in family mode, this function
2597  // will be called multiple times. While you might think that it is
2598  // sufficient to update what *should* be the only pointer to the contents
2599  // of pls->dev, i.e. the pointer pls->dev itself, it appears that
2600  // something else somewhere else is also pointing to pls->dev. If you
2601  // change what pls->dev points to then you will get a "bus error", from
2602  // which I infer the existence of said bad stale pointer.
2603  //
2604  if ( pls->dev == NULL )
2605  {
2606  aStream = stream_and_font_setup( pls, 0 );
2607  }
2608  else
2609  {
2610  stream_and_font_setup( pls, 0 );
2611  aStream = pls->dev;
2612  }
2613 
2614  // Initialize family file info
2615  plFamInit( pls );
2616 
2617  // Prompt for a file name if not already set.
2618  plOpenFile( pls );
2619 
2620  // Save the pointer to the structure in the PLplot stream
2621  pls->dev = aStream;
2622 
2623  // Create an cairo surface & context for SVG file.
2624  // Dimension units are pts = 1/72 inches from cairo documentation.
2625  aStream->cairoSurface = cairo_svg_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
2626  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2627 
2628  // Invert the surface so that the graphs are drawn right side up.
2629  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2630 
2631  // Set graphics aliasing
2632  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2633 
2634  // Set fill rule for the case of self-intersecting boundaries.
2635  if ( pls->dev_eofill )
2636  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2637  else
2638  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2639 }
2640 
2641 #endif
2642 
2643 
2644 //--------------------------------------------------------------------------
2645 //--------------------------------------------------------------------------
2646 //
2647 // That which is specific to the cairo PNG driver.
2648 //
2649 //--------------------------------------------------------------------------
2650 //--------------------------------------------------------------------------
2651 
2652 #if defined ( PLD_pngcairo )
2653 
2655 void plD_init_pngcairo( PLStream * );
2656 void plD_eop_pngcairo( PLStream * );
2657 
2658 //--------------------------------------------------------------------------
2659 // dispatch_init_init()
2660 //
2661 // Initialize device dispatch table
2662 //--------------------------------------------------------------------------
2663 
2664 // pngcairo
2666 {
2667 #ifndef ENABLE_DYNDRIVERS
2668  pdt->pl_MenuStr = "Cairo PNG Driver";
2669  pdt->pl_DevName = "pngcairo";
2670 #endif
2672  pdt->pl_seq = 104;
2673  pdt->pl_init = (plD_init_fp) plD_init_pngcairo;
2674  pdt->pl_line = (plD_line_fp) plD_line_cairo_fam;
2675  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
2676  pdt->pl_eop = (plD_eop_fp) plD_eop_pngcairo;
2677  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo_fam;
2678  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo_fam;
2679  pdt->pl_state = (plD_state_fp) plD_state_cairo_fam;
2680  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo_fam;
2681 }
2682 
2683 //--------------------------------------------------------------------------
2684 // plD_init_pngcairo()
2685 //
2686 // Initialize Cairo PNG device
2687 //--------------------------------------------------------------------------
2688 
2689 void plD_init_pngcairo( PLStream *pls )
2690 {
2691  PLCairo *aStream;
2692 
2693  // Setup the PLStream and the font lookup table and allocate a cairo
2694  // stream structure.
2695  //
2696  // NOTE: The check below is necessary since, in family mode, this function
2697  // will be called multiple times. While you might think that it is
2698  // sufficient to update what *should* be the only pointer to the contents
2699  // of pls->dev, i.e. the pointer pls->dev itself, it appears that
2700  // something else somewhere else is also pointing to pls->dev. If you
2701  // change what pls->dev points to then you will get a "bus error", from
2702  // which I infer the existence of said bad stale pointer.
2703  //
2704  if ( pls->dev == NULL )
2705  {
2706  aStream = stream_and_font_setup( pls, 0 );
2707  }
2708  else
2709  {
2710  stream_and_font_setup( pls, 0 );
2711  aStream = pls->dev;
2712  }
2713 
2714  // Initialize family file info
2715  plFamInit( pls );
2716 
2717  // Prompt for a file name if not already set.
2718  plOpenFile( pls );
2719 
2720  // Save the pointer to the structure in the PLplot stream
2721  pls->dev = aStream;
2722 
2723  // Create a new cairo surface & context for PNG file.
2724  // Dimension units are pixels from cairo documentation.
2725  aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (int) pls->xlength, (int) pls->ylength );
2726  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2727 
2728  // Invert the surface so that the graphs are drawn right side up.
2729  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2730 
2731  // Set graphics aliasing
2732  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2733 
2734  // Set fill rule for the case of self-intersecting boundaries.
2735  if ( pls->dev_eofill )
2736  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2737  else
2738  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2739 }
2740 
2741 //--------------------------------------------------------------------------
2742 // plD_eop_pngcairo()
2743 //
2744 // PNG: End of page.
2745 //--------------------------------------------------------------------------
2746 
2747 void plD_eop_pngcairo( PLStream *pls )
2748 {
2749  PLCairo *aStream;
2750 
2751  if ( cairo_family_check( pls ) )
2752  {
2753  return;
2754  }
2755 
2756  aStream = (PLCairo *) pls->dev;
2757  cairo_surface_write_to_png_stream( aStream->cairoSurface, (cairo_write_func_t) write_to_stream, pls->OutFile );
2758 }
2759 
2760 #endif
2761 
2762 
2763 //--------------------------------------------------------------------------
2764 //--------------------------------------------------------------------------
2765 //
2766 // That which is specific to the cairo memory driver.
2767 //
2768 //--------------------------------------------------------------------------
2769 //--------------------------------------------------------------------------
2770 
2771 #if defined ( PLD_memcairo )
2772 
2774 void plD_init_memcairo( PLStream * );
2775 void plD_eop_memcairo( PLStream * );
2776 void plD_bop_memcairo( PLStream * );
2777 
2778 //--------------------------------------------------------------------------
2779 // dispatch_init_init()
2780 //
2781 // Initialize device dispatch table
2782 //--------------------------------------------------------------------------
2783 
2784 // memcairo
2786 {
2787 #ifndef ENABLE_DYNDRIVERS
2788  pdt->pl_MenuStr = "Cairo memory driver";
2789  pdt->pl_DevName = "memcairo";
2790 #endif
2792  pdt->pl_seq = 105;
2793  pdt->pl_init = (plD_init_fp) plD_init_memcairo;
2796  pdt->pl_eop = (plD_eop_fp) plD_eop_memcairo;
2797  pdt->pl_bop = (plD_bop_fp) plD_bop_memcairo;
2800  pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2801 }
2802 
2803 //--------------------------------------------------------------------------
2804 // plD_bop_memcairo()
2805 //
2806 // Set up for the next page.
2807 //--------------------------------------------------------------------------
2808 
2809 void plD_bop_memcairo( PLStream * PL_UNUSED( pls ) )
2810 {
2811  // nothing to do here (we want to preserve the memory as it is)
2812 }
2813 
2814 //--------------------------------------------------------------------------
2815 // plD_init_memcairo()
2816 //
2817 // Initialize Cairo memory device
2818 //--------------------------------------------------------------------------
2819 
2820 void plD_init_memcairo( PLStream *pls )
2821 {
2822  PLCairo *aStream;
2823  int stride, i;
2824  unsigned char *cairo_mem;
2825  unsigned char *input_mem;
2826 
2827  // used for checking byte order
2828  union
2829  {
2830  int testWord;
2831  char testByte[sizeof ( int )];
2832  } endianTest;
2833  endianTest.testWord = 1;
2834 
2835  // Set the plot size to the memory buffer size, on the off chance
2836  // that they are different.
2837  pls->xlength = pls->phyxma;
2838  pls->ylength = pls->phyyma;
2839 
2840 
2841  // Setup the PLStream and the font lookup table
2842  aStream = stream_and_font_setup( pls, 0 );
2843 
2844  // Test byte order
2845  if ( endianTest.testByte[0] == 1 )
2846  aStream->bigendian = 0;
2847  else
2848  aStream->bigendian = 1;
2849 
2850  // Check that user supplied us with some memory to draw in
2851  if ( pls->dev == NULL )
2852  {
2853  plexit( "Must call plsmem first to set user plotting area!" );
2854  }
2855 
2856  // Save a pointer to the memory.
2857  aStream->memory = pls->dev;
2858 
2859  // Create a cairo surface & context. Copy data in from the input memory area
2860 
2861  // Malloc memory the way cairo likes it. Aligned on the stride computed by cairo_format_stride_for_width
2862  // and in the RGB24 format (from http://cairographics.org/manual/cairo-Image-Surfaces.html):
2863  // Each pixel is a 32-bit quantity, with the upper 8 bits unused.
2864  // Red, Green, and Blue are stored in the remaining 24 bits in that order
2865  stride = pls->xlength * 4;
2866  // stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pls->xlength); This function missing from version 1.4 :-(
2867  aStream->cairo_format_memory = (unsigned char *) calloc( (size_t) ( stride * pls->ylength ), 1 );
2868 
2869  // Copy the input data into the Cairo data format
2870  cairo_mem = aStream->cairo_format_memory;
2871  input_mem = aStream->memory;
2872 
2873  // 32 bit word order
2874  // cairo mem: Big endian: 0=A, 1=R, 2=G, 3=B
2875  // Little endian: 3=A, 2=R, 1=G, 0=B
2876 
2877  if ( aStream->bigendian )
2878  {
2879  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2880  {
2881  cairo_mem[1] = input_mem[0]; // R
2882  cairo_mem[2] = input_mem[1]; // G
2883  cairo_mem[3] = input_mem[2]; // B
2884  if ( pls->dev_mem_alpha == 1 )
2885  {
2886  cairo_mem[0] = input_mem[3];
2887  input_mem += 4;
2888  }
2889  else
2890  {
2891  input_mem += 3;
2892  }
2893  cairo_mem += 4;
2894  }
2895  }
2896  else
2897  {
2898  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2899  {
2900  cairo_mem[2] = input_mem[0]; // R
2901  cairo_mem[1] = input_mem[1]; // G
2902  cairo_mem[0] = input_mem[2]; // B
2903  if ( pls->dev_mem_alpha == 1 )
2904  {
2905  cairo_mem[3] = input_mem[3];
2906  input_mem += 4;
2907  }
2908  else
2909  {
2910  input_mem += 3;
2911  }
2912  cairo_mem += 4;
2913  }
2914  }
2915 
2916  // Create a Cairo drawing surface from the input data
2917  aStream->cairoSurface =
2918  // Dimension units are width, height of buffer image from cairo
2919  // documentation.
2920  cairo_image_surface_create_for_data( aStream->cairo_format_memory, CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength, stride );
2921  aStream->cairoContext = cairo_create( aStream->cairoSurface );
2922 
2923  // Save the pointer to the structure in the PLplot stream.
2924  // Note that this wipes out the direct pointer to the memory buffer.
2925  pls->dev = aStream;
2926 
2927  // Invert the surface so that the graphs are drawn right side up.
2928  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
2929 
2930  // Set graphics aliasing
2931  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2932 
2933  // Set fill rule for the case of self-intersecting boundaries.
2934  if ( pls->dev_eofill )
2935  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2936  else
2937  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2938 }
2939 
2940 //--------------------------------------------------------------------------
2941 // plD_eop_memcairo()
2942 //
2943 // Memory device specific end of page. This copies the contents
2944 // of the cairo surface into the user supplied memory buffer.
2945 //--------------------------------------------------------------------------
2946 
2947 void plD_eop_memcairo( PLStream *pls )
2948 {
2949  int i;
2950  unsigned char *memory;
2951  unsigned char *cairo_surface_data;
2952  PLCairo *aStream;
2953 
2954  aStream = (PLCairo *) pls->dev;
2955  memory = aStream->memory;
2956  cairo_surface_data = cairo_image_surface_get_data( aStream->cairoSurface );
2957  // 32 bit word order
2958  // cairo mem: Big endian: 0=A, 1=R, 2=G, 3=B
2959  // Little endian: 3=A, 2=R, 1=G, 0=B
2960  if ( aStream->bigendian )
2961  {
2962  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2963  {
2964  memory[0] = cairo_surface_data[1]; // R
2965  memory[1] = cairo_surface_data[2]; // G
2966  memory[2] = cairo_surface_data[3]; // B
2967  if ( pls->dev_mem_alpha == 1 )
2968  {
2969  memory[3] = cairo_surface_data[0];
2970  memory += 4;
2971  }
2972  else
2973  {
2974  memory += 3;
2975  }
2976  cairo_surface_data += 4;
2977  }
2978  }
2979  else
2980  {
2981  for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2982  {
2983  memory[0] = cairo_surface_data[2]; // R
2984  memory[1] = cairo_surface_data[1]; // G
2985  memory[2] = cairo_surface_data[0]; // B
2986  if ( pls->dev_mem_alpha == 1 )
2987  {
2988  memory[3] = cairo_surface_data[3];
2989  memory += 4;
2990  }
2991  else
2992  {
2993  memory += 3;
2994  }
2995  cairo_surface_data += 4;
2996  }
2997  }
2998 
2999  // Free up the temporary memory malloc'ed in plD_init_memcairo
3000  free( aStream->cairo_format_memory );
3001 }
3002 
3003 #endif
3004 
3005 //--------------------------------------------------------------------------
3006 //--------------------------------------------------------------------------
3007 //
3008 // That which is specific to the cairo external context driver.
3009 //
3010 //--------------------------------------------------------------------------
3011 //--------------------------------------------------------------------------
3012 
3013 #if defined ( PLD_extcairo )
3014 
3015 void extcairo_setbackground( PLStream * );
3017 void plD_init_extcairo( PLStream * );
3018 void plD_bop_extcairo( PLStream * );
3019 void plD_eop_extcairo( PLStream * );
3020 void plD_esc_extcairo( PLStream *, PLINT, void * );
3021 void plD_tidy_extcairo( PLStream * );
3022 
3023 //--------------------------------------------------------------------------
3024 // extcairo_setbackground()
3025 //
3026 // Set the background color for the extcairo device
3027 //--------------------------------------------------------------------------
3028 
3029 void extcairo_setbackground( PLStream *pls )
3030 {
3031  PLCairo *aStream;
3032 
3033  aStream = (PLCairo *) pls->dev;
3034 
3035  // Fill the context with the background color if the user so desires.
3036  if ( aStream->cairoContext != NULL )
3037  {
3038  cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
3039  cairo_set_source_rgba( aStream->cairoContext,
3040  (double) pls->cmap0[0].r / 255.0,
3041  (double) pls->cmap0[0].g / 255.0,
3042  (double) pls->cmap0[0].b / 255.0,
3043  (double) pls->cmap0[0].a );
3044  cairo_fill( aStream->cairoContext );
3045  }
3046 }
3047 
3048 //--------------------------------------------------------------------------
3049 // dispatch_init_init()
3050 //
3051 // Initialize device dispatch table
3052 //--------------------------------------------------------------------------
3053 
3054 // extcairo
3056 {
3057 #ifndef ENABLE_DYNDRIVERS
3058  pdt->pl_MenuStr = "Cairo external context driver";
3059  pdt->pl_DevName = "extcairo";
3060 #endif
3062  pdt->pl_seq = 106;
3063  pdt->pl_init = (plD_init_fp) plD_init_extcairo;
3066  pdt->pl_bop = (plD_bop_fp) plD_bop_extcairo;
3067  pdt->pl_eop = (plD_eop_fp) plD_eop_extcairo;
3068  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_extcairo;
3070  pdt->pl_esc = (plD_esc_fp) plD_esc_extcairo;
3071 }
3072 
3073 //--------------------------------------------------------------------------
3074 // plD_init_extcairo()
3075 //
3076 // Initialize Cairo external context driver.
3077 //--------------------------------------------------------------------------
3078 
3079 void plD_init_extcairo( PLStream *pls )
3080 {
3081  PLCairo *aStream;
3082 
3083  // Setup the PLStream and the font lookup table
3084  aStream = stream_and_font_setup( pls, 0 );
3085 
3086  // Save the pointer to the structure in the PLplot stream
3087  pls->dev = aStream;
3088 }
3089 
3090 //--------------------------------------------------------------------------
3091 // plD_bop_extcairo()
3092 //
3093 // Set up for the next page.
3094 //--------------------------------------------------------------------------
3095 
3096 void plD_bop_extcairo( PLStream *pls )
3097 {
3098  PLCairo *aStream;
3099 
3100  aStream = (PLCairo *) pls->dev;
3101 
3102  // Set background if desired
3103  if ( aStream->set_background )
3104  {
3105  extcairo_setbackground( pls );
3106  }
3107 }
3108 
3109 //--------------------------------------------------------------------------
3110 // plD_eop_extcairo()
3111 //
3112 // End of page.
3113 //--------------------------------------------------------------------------
3114 
3115 void plD_eop_extcairo( PLStream * PL_UNUSED( pls ) )
3116 {
3117  // nothing to do here, we leave it to the calling program to display
3118  // (or not) the update cairo context.
3119 }
3120 
3121 //--------------------------------------------------------------------------
3122 // plD_esc_extcairo()
3123 //
3124 // The generic escape function, extended so that user can pass in
3125 // an external Cairo context to use for rendering.
3126 //--------------------------------------------------------------------------
3127 
3128 void plD_esc_extcairo( PLStream *pls, PLINT op, void *ptr )
3129 {
3130  PLCairo *aStream;
3131 
3132  aStream = (PLCairo *) pls->dev;
3133 
3134  switch ( op )
3135  {
3136  case PLESC_DEVINIT: // Set external context
3137  aStream->cairoContext = (cairo_t *) ptr;
3138  // Set graphics aliasing
3139  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
3140 
3141  // Invert the surface so that the graphs are drawn right side up.
3142  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
3143 
3144  // Should adjust plot size to fit in the given cairo context?
3145  // Cairo does not provide a way to query the dimensions of a context?
3146 
3147  // Set background if desired
3148  if ( aStream->set_background )
3149  {
3150  extcairo_setbackground( pls );
3151  }
3152 
3153  // Set fill rule for the case of self-intersecting boundaries.
3154  if ( pls->dev_eofill )
3155  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
3156  else
3157  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
3158  break;
3159  default: // Fall back on default Cairo actions
3160  plD_esc_cairo( pls, op, ptr );
3161  break;
3162  }
3163 }
3164 
3165 //--------------------------------------------------------------------------
3166 // plD_tidy_extcairo()
3167 //
3168 // This is nop, it is up to the calling program to clean up the Cairo
3169 // context, etc...
3170 //--------------------------------------------------------------------------
3171 
3172 void plD_tidy_extcairo( PLStream * PL_UNUSED( pls ) )
3173 {
3174 }
3175 
3176 #endif
3177 
3178 
3179 //--------------------------------------------------------------------------
3180 //--------------------------------------------------------------------------
3181 //
3182 // That which is specific to the cairo microsoft windows driver.
3183 //
3184 // Much of the Windows specific code here was lifted from the wingcc
3185 // driver.
3186 //
3187 //--------------------------------------------------------------------------
3188 //--------------------------------------------------------------------------
3189 
3190 #if defined ( PLD_wincairo )
3191 
3192 static char* szWndClass = "PLplot WinCairo";
3193 
3195 void plD_init_wincairo( PLStream * );
3196 //void plD_bop_extcairo( PLStream * );
3197 void plD_eop_wincairo( PLStream * );
3198 void plD_esc_wincairo( PLStream *, PLINT, void * );
3199 void plD_tidy_wincairo( PLStream * );
3200 
3201 //--------------------------------------------------------------------------
3202 // blit_to_win()
3203 //
3204 // Blit the offscreen image to the Windows window.
3205 //--------------------------------------------------------------------------
3206 
3207 void blit_to_win( PLCairo *aStream )
3208 {
3209  cairo_set_source_surface( aStream->cairoContext_win, aStream->cairoSurface, 0.0, 0.0 );
3210  cairo_paint( aStream->cairoContext_win );
3211 }
3212 
3213 //--------------------------------------------------------------------------
3214 // This is the window function for the plot window. Whenever a message is
3215 // dispatched using DispatchMessage (or sent with SendMessage) this function
3216 // gets called with the contents of the message.
3217 //--------------------------------------------------------------------------
3218 
3219 LRESULT CALLBACK PlplotCairoWndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
3220 {
3221  PLStream *pls = NULL;
3222  PLCairo *dev = NULL;
3223 
3224 //
3225 // The window carries a 32bit user defined pointer which points to the
3226 // plplot stream (pls). This is used for tracking the window.
3227 // Unfortunately, this is "attached" to the window AFTER it is created
3228 // so we can not initialise PLStream or wincairo "blindly" because
3229 // they may not yet have been initialised.
3230 // WM_CREATE is called before we get to initialise those variables, so
3231 // we wont try to set them.
3232 //
3233 
3234  if ( nMsg == WM_CREATE )
3235  {
3236  return ( 0 );
3237  }
3238  else
3239  {
3240  pls = (PLStream *) GetWindowLong( hwnd, GWL_USERDATA ); // Try to get the address to pls for this window
3241  if ( pls ) // If we got it, then we will initialise this windows plplot private data area
3242  {
3243  dev = (PLCairo *) pls->dev;
3244  }
3245  }
3246 
3247 //
3248 // Process the windows messages
3249 //
3250 // Everything except WM_CREATE is done here and it is generally hoped that
3251 // pls and dev are defined already by this stage.
3252 // That will be true MOST of the time. Some times WM_PAINT will be called
3253 // before we get to initialise the user data area of the window with the
3254 // pointer to the windows plplot stream
3255 //
3256 
3257  switch ( nMsg )
3258  {
3259  case WM_DESTROY:
3260  // if ( dev )
3261  // Debug( "WM_DESTROY\t" );
3262  PostQuitMessage( 0 );
3263  return ( 0 );
3264  break;
3265 
3266  case WM_PAINT:
3267  blit_to_win( dev );
3268  return ( 1 );
3269  break;
3270 
3271  case WM_SIZE:
3272  GetClientRect( dev->hwnd, &dev->rect );
3273  return ( 0 );
3274  break;
3275 
3276  case WM_ENTERSIZEMOVE:
3277  return ( 0 );
3278  break;
3279 
3280  case WM_EXITSIZEMOVE:
3281  return ( 0 );
3282  break;
3283 
3284  case WM_ERASEBKGND:
3285  if ( dev )
3286  {
3287  dev->oldcolour = SetBkColor( dev->hdc, RGB( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b ) );
3288  ExtTextOut( dev->hdc, 0, 0, ETO_OPAQUE, &dev->rect, "", 0, 0 );
3289  SetBkColor( dev->hdc, dev->oldcolour );
3290  }
3291  return ( 1 );
3292  break;
3293 
3294  case WM_COMMAND:
3295  return ( 0 );
3296  break;
3297  }
3298 
3299  // If we don't handle a message completely we hand it to the system
3300  // provided default window function.
3301  return DefWindowProc( hwnd, nMsg, wParam, lParam );
3302 }
3303 
3304 //--------------------------------------------------------------------------
3305 // handle_locate()
3306 //
3307 // Handle getting the cursor location.
3308 //--------------------------------------------------------------------------
3309 
3310 void
3311 handle_locate( PLStream *pls, PLGraphicsIn *gin )
3312 {
3313  int located = 0;
3314  PLCairo *aStream = (PLCairo *) pls->dev;
3315 
3316  // Initialize PLplot mouse event structure
3317  plGinInit( gin );
3318 
3319  while ( GetMessage( &aStream->msg, NULL, 0, 0 ) && !located )
3320  {
3321  TranslateMessage( &aStream->msg );
3322 
3323  switch ( (int) aStream->msg.message )
3324  {
3325  case WM_MOUSEMOVE:
3326  case WM_LBUTTONDOWN:
3327  gin->state = 1;
3328  gin->button = 1;
3329  gin->pX = LOWORD( aStream->msg.lParam );
3330  gin->pY = pls->ylength - HIWORD( aStream->msg.lParam );
3331  gin->dX = (PLFLT) LOWORD( aStream->msg.lParam ) / ( (PLFLT) pls->xlength );
3332  gin->dY = (PLFLT) ( pls->ylength - HIWORD( aStream->msg.lParam ) ) / ( (PLFLT) pls->ylength );
3333  break;
3334  case WM_CHAR:
3335  gin->keysym = aStream->msg.wParam;
3336  located = 1;
3337  break;
3338 
3339  default:
3340  DispatchMessage( &aStream->msg );
3341  break;
3342  }
3343  }
3344 }
3345 
3346 //--------------------------------------------------------------------------
3347 // dispatch_init_init()
3348 //
3349 // Initialize device dispatch table
3350 //--------------------------------------------------------------------------
3351 
3352 // extcairo
3354 {
3355 #ifndef ENABLE_DYNDRIVERS
3356  pdt->pl_MenuStr = "Cairo Microsoft Windows driver";
3357  pdt->pl_DevName = "wincairo";
3358 #endif
3360  pdt->pl_seq = 107;
3361  pdt->pl_init = (plD_init_fp) plD_init_wincairo;
3364  pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
3365  pdt->pl_eop = (plD_eop_fp) plD_eop_wincairo;
3366  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wincairo;
3368  pdt->pl_esc = (plD_esc_fp) plD_esc_wincairo;
3369 }
3370 
3371 //--------------------------------------------------------------------------
3372 // plD_init_wincairo()
3373 //
3374 // Initialize Cairo Microsoft Windows driver.
3375 //--------------------------------------------------------------------------
3376 
3377 void plD_init_wincairo( PLStream *pls )
3378 {
3379  PLCairo *aStream;
3380 
3381  // Setup the PLStream and the font lookup table
3382  aStream = stream_and_font_setup( pls, 1 );
3383 
3384  // Save the pointer to the structure in the PLplot stream
3385  pls->dev = aStream;
3386 
3387  // Create window
3388  memset( &aStream->wndclass, 0, sizeof ( WNDCLASSEX ) );
3389 
3390  // This class is called WinTestWin
3391  aStream->wndclass.lpszClassName = szWndClass;
3392 
3393  // cbSize gives the size of the structure for extensibility.
3394  aStream->wndclass.cbSize = sizeof ( WNDCLASSEX );
3395 
3396  // All windows of this class redraw when resized.
3397  aStream->wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC | CS_PARENTDC;
3398 
3399  // All windows of this class use the PlplotCairoWndProc window function.
3400  aStream->wndclass.lpfnWndProc = PlplotCairoWndProc;
3401 
3402  // This class is used with the current program instance.
3403 
3404  aStream->wndclass.hInstance = GetModuleHandle( NULL );
3405 
3406  // Use standard application icon and arrow cursor provided by the OS
3407  aStream->wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
3408  aStream->wndclass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
3409  aStream->wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
3410  // Color the background white
3411  aStream->wndclass.hbrBackground = NULL;
3412 
3413  aStream->wndclass.cbWndExtra = sizeof ( pls );
3414 
3415 
3416  //
3417  // Now register the window class for use.
3418  //
3419 
3420  RegisterClassEx( &aStream->wndclass );
3421 
3422  //
3423  // Create our main window using that window class.
3424  //
3425  aStream->hwnd = CreateWindowEx( WS_EX_WINDOWEDGE + WS_EX_LEFT,
3426  szWndClass, // Class name
3427  pls->program, // Caption
3428  WS_OVERLAPPEDWINDOW, // Style
3429  pls->xoffset, // Initial x (use default)
3430  pls->yoffset, // Initial y (use default)
3431  // This is a little lame since the window border size might change.
3432  pls->xlength + 5, // Initial x size (use default)
3433  pls->ylength + 30, // Initial y size (use default)
3434  NULL, // No parent window
3435  NULL, // No menu
3436  aStream->wndclass.hInstance, // This program instance
3437  NULL // Creation parameters
3438  );
3439 
3440 
3441 //
3442 // Attach a pointer to the stream to the window's user area
3443 // this pointer will be used by the windows call back for
3444 // process this window
3445 //
3446 
3447  SetWindowLong( aStream->hwnd, GWL_USERDATA, (long) pls );
3448  aStream->SCRN_hdc = aStream->hdc = GetDC( aStream->hwnd );
3449 
3450 //
3451 // Setup the popup menu
3452 //
3453 
3454 //
3455 // dev->PopupMenu = CreatePopupMenu();
3456 // AppendMenu( dev->PopupMenu, MF_STRING, PopupPrint, "Print" );
3457 // AppendMenu( dev->PopupMenu, MF_STRING, PopupNextPage, "Next Page" );
3458 // AppendMenu( dev->PopupMenu, MF_STRING, PopupQuit, "Quit" );
3459 //
3460 
3461  // plD_state_wingcc( pls, PLSTATE_COLOR0 );
3462  //
3463  // Display the window which we just created (using the nShow
3464  // passed by the OS, which allows for start minimized and that
3465  // sort of thing).
3466  //
3467  ShowWindow( aStream->hwnd, SW_SHOWDEFAULT );
3468  SetForegroundWindow( aStream->hwnd );
3469 
3470 //
3471 // Now we have to find out, from windows, just how big our drawing area is
3472 // when we specified the page size earlier on, that includes the borders,
3473 // title bar etc... so now that windows has done all its initialisations,
3474 // we will ask how big the drawing area is, and tell plplot
3475 //
3476 
3477 //
3478 // GetClientRect( dev->hwnd, &dev->rect );
3479 // dev->width = dev->rect.right;
3480 // dev->height = dev->rect.bottom;
3481 //
3482 
3483 //
3484 // Initialize Cairo Surface using the windows hdc.
3485 //
3486 
3487  // This is the Win32 Cairo surface.
3488  aStream->cairoSurface_win = (cairo_surface_t *) cairo_win32_surface_create( aStream->hdc );
3489  aStream->cairoContext_win = cairo_create( aStream->cairoSurface_win );
3490 
3491  // This is the Cairo surface PLplot will actually plot to.
3492  aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength );
3493  aStream->cairoContext = cairo_create( aStream->cairoSurface );
3494 
3495  // Invert the surface so that the graphs are drawn right side up.
3496  rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
3497 
3498  // Set graphics aliasing
3499  cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
3500 
3501  // Set fill rule for the case of self-intersecting boundaries.
3502  if ( pls->dev_eofill )
3503  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
3504  else
3505  cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
3506 }
3507 
3508 //--------------------------------------------------------------------------
3509 // plD_eop_wincairo()
3510 //
3511 // Clean up Cairo Microsoft Windows driver.
3512 //--------------------------------------------------------------------------
3513 
3514 void
3515 plD_eop_wincairo( PLStream *pls )
3516 {
3517  PLCairo *aStream = (PLCairo *) pls->dev;
3518 
3519  if ( !pls->nopause )
3520  {
3521  while ( GetMessage( &aStream->msg, NULL, 0, 0 ) )
3522  {
3523  TranslateMessage( &aStream->msg );
3524  switch ( (int) aStream->msg.message )
3525  {
3526  case WM_CHAR:
3527  if ( ( (TCHAR) ( aStream->msg.wParam ) == 13 ) ||
3528  ( (TCHAR) ( aStream->msg.wParam ) == 'q' ) ||
3529  ( (TCHAR) ( aStream->msg.wParam ) == 'Q' ) )
3530  {
3531  PostQuitMessage( 0 );
3532  }
3533  break;
3534 
3535  default:
3536  DispatchMessage( &aStream->msg );
3537  break;
3538  }
3539  }
3540  }
3541 }
3542 
3543 //--------------------------------------------------------------------------
3544 // plD_tidy_wincairo()
3545 //
3546 // Clean up Cairo Microsoft Windows driver.
3547 //--------------------------------------------------------------------------
3548 
3549 void plD_tidy_wincairo( PLStream *pls )
3550 {
3551  PLCairo *aStream = (PLCairo *) pls->dev;
3552 
3553  plD_tidy_cairo( pls );
3554 
3555  // Also free up the Cairo win32 surface and context
3556  cairo_destroy( aStream->cairoContext_win );
3557  cairo_surface_destroy( aStream->cairoSurface_win );
3558 
3559  if ( aStream != NULL )
3560  {
3561  if ( aStream->hdc != NULL )
3562  ReleaseDC( aStream->hwnd, aStream->hdc );
3563  free_mem( pls->dev );
3564  }
3565 }
3566 
3567 //--------------------------------------------------------------------------
3568 // plD_esc_wincairo()
3569 //
3570 // Escape function, specialized for the wincairo driver
3571 //--------------------------------------------------------------------------
3572 
3573 void plD_esc_wincairo( PLStream *pls, PLINT op, void *ptr )
3574 {
3575  PLCairo *aStream;
3576 
3577  aStream = (PLCairo *) pls->dev;
3578 
3579  switch ( op )
3580  {
3581  case PLESC_FLUSH:
3582  InvalidateRect( aStream->hwnd, NULL, TRUE );
3583  break;
3584  case PLESC_GETC:
3585  handle_locate( pls, (PLGraphicsIn *) ptr );
3586  break;
3587  default:
3588  plD_esc_cairo( pls, op, ptr );
3589  break;
3590  }
3591 }
3592 
3593 #endif