PLplot: cairo.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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;
79 static int graphics_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;
100 cairo_t *cairoContext_raster;
101 short text_clipping;
102 short text_anti_aliasing;
103 short graphics_anti_aliasing;
104 short rasterize_image;
105 short set_background;
106 short image_buffering;
107 double downscale;
108 char *pangoMarkupString;
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;
120 PLINT level;
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
148 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_cairo =
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
197 const char *defaultFamilyLookup[NPANGOLOOKUP] = {
198 "sans",
199 "serif",
200 "monospace",
201 "sans,serif",
202 "sans,serif"
203 };
204
205 const char *envFamilyLookup[NPANGOLOOKUP] = {
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
214 char familyLookup[NPANGOLOOKUP][FAMILY_LOOKUP_LEN];
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
243 PLCairo *stream_and_font_setup( PLStream *, int );
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
384 void plD_bop_cairo( PLStream *pls )
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
482 void plD_eop_cairo( PLStream *pls )
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
497 void plD_tidy_cairo( PLStream *pls )
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
519 void plD_state_cairo( PLStream * PL_UNUSED( pls ), PLINT PL_UNUSED( op ) )
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;
1374 aStream->graphics_anti_aliasing = (short) graphics_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
1389 void set_current_context( PLStream *pls )
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
1573 int cairo_family_check( PLStream *pls )
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
1835 void plD_dispatch_init_xcairo( PLDispatchTable *pdt );
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
1849 void plD_dispatch_init_xcairo( PLDispatchTable *pdt )
1850 {
1851 #ifndef ENABLE_DYNDRIVERS
1852 pdt->pl_MenuStr = "Cairo X Windows Driver";
1853 pdt->pl_DevName = "xcairo";
1854 #endif
1855 pdt->pl_type = plDevType_Interactive;
1856 pdt->pl_seq = 100;
1857 pdt->pl_init = (plD_init_fp) plD_init_xcairo;
1858 pdt->pl_line = (plD_line_fp) plD_line_cairo;
1859 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
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;
1863 pdt->pl_state = (plD_state_fp) plD_state_cairo;
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
2293 void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt );
2294 void plD_init_pdfcairo( PLStream * );
2295
2296 //--------------------------------------------------------------------------
2297 // dispatch_init_init()
2298 //
2299 // Initialize device dispatch table
2300 //--------------------------------------------------------------------------
2301
2302 // pdfcairo
2303 void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt )
2304 {
2305 #ifndef ENABLE_DYNDRIVERS
2306 pdt->pl_MenuStr = "Cairo PDF Driver";
2307 pdt->pl_DevName = "pdfcairo";
2308 #endif
2309 pdt->pl_type = plDevType_FileOriented;
2310 pdt->pl_seq = 101;
2311 pdt->pl_init = (plD_init_fp) plD_init_pdfcairo;
2312 pdt->pl_line = (plD_line_fp) plD_line_cairo;
2313 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2314 pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2315 pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2316 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2317 pdt->pl_state = (plD_state_fp) plD_state_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
2371 void plD_dispatch_init_pscairo( PLDispatchTable *pdt );
2372 void plD_init_pscairo( PLStream * );
2373
2374 //--------------------------------------------------------------------------
2375 // dispatch_init_init()
2376 //
2377 // Initialize device dispatch table
2378 //--------------------------------------------------------------------------
2379
2380 // pscairo
2381 void plD_dispatch_init_pscairo( PLDispatchTable *pdt )
2382 {
2383 #ifndef ENABLE_DYNDRIVERS
2384 pdt->pl_MenuStr = "Cairo PS Driver";
2385 pdt->pl_DevName = "pscairo";
2386 #endif
2387 pdt->pl_type = plDevType_FileOriented;
2388 pdt->pl_seq = 102;
2389 pdt->pl_init = (plD_init_fp) plD_init_pscairo;
2390 pdt->pl_line = (plD_line_fp) plD_line_cairo;
2391 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2392 pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2393 pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2394 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2395 pdt->pl_state = (plD_state_fp) plD_state_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
2451 void plD_dispatch_init_epscairo( PLDispatchTable *pdt );
2452 void plD_init_epscairo( PLStream * );
2453
2454 //--------------------------------------------------------------------------
2455 // dispatch_init_init()
2456 //
2457 // Initialize device dispatch table
2458 //--------------------------------------------------------------------------
2459
2460 // epscairo
2461 void plD_dispatch_init_epscairo( PLDispatchTable *pdt )
2462 {
2463 #ifndef ENABLE_DYNDRIVERS
2464 pdt->pl_MenuStr = "Cairo EPS Driver";
2465 pdt->pl_DevName = "epscairo";
2466 #endif
2467 pdt->pl_type = plDevType_FileOriented;
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
2555 void plD_dispatch_init_svgcairo( PLDispatchTable *pdt );
2556 void plD_init_svgcairo( PLStream * );
2557
2558 //--------------------------------------------------------------------------
2559 // dispatch_init_init()
2560 //
2561 // Initialize device dispatch table
2562 //--------------------------------------------------------------------------
2563
2564 // svgcairo
2565 void plD_dispatch_init_svgcairo( PLDispatchTable *pdt )
2566 {
2567 #ifndef ENABLE_DYNDRIVERS
2568 pdt->pl_MenuStr = "Cairo SVG Driver";
2569 pdt->pl_DevName = "svgcairo";
2570 #endif
2571 pdt->pl_type = plDevType_FileOriented;
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
2654 void plD_dispatch_init_pngcairo( PLDispatchTable *pdt );
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
2665 void plD_dispatch_init_pngcairo( PLDispatchTable *pdt )
2666 {
2667 #ifndef ENABLE_DYNDRIVERS
2668 pdt->pl_MenuStr = "Cairo PNG Driver";
2669 pdt->pl_DevName = "pngcairo";
2670 #endif
2671 pdt->pl_type = plDevType_FileOriented;
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
2773 void plD_dispatch_init_memcairo( PLDispatchTable *pdt );
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
2785 void plD_dispatch_init_memcairo( PLDispatchTable *pdt )
2786 {
2787 #ifndef ENABLE_DYNDRIVERS
2788 pdt->pl_MenuStr = "Cairo memory driver";
2789 pdt->pl_DevName = "memcairo";
2790 #endif
2791 pdt->pl_type = plDevType_FileOriented;
2792 pdt->pl_seq = 105;
2793 pdt->pl_init = (plD_init_fp) plD_init_memcairo;
2794 pdt->pl_line = (plD_line_fp) plD_line_cairo;
2795 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2796 pdt->pl_eop = (plD_eop_fp) plD_eop_memcairo;
2797 pdt->pl_bop = (plD_bop_fp) plD_bop_memcairo;
2798 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2799 pdt->pl_state = (plD_state_fp) plD_state_cairo;
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 * );
3016 void plD_dispatch_init_extcairo( PLDispatchTable *pdt );
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
3055 void plD_dispatch_init_extcairo( PLDispatchTable *pdt )
3056 {
3057 #ifndef ENABLE_DYNDRIVERS
3058 pdt->pl_MenuStr = "Cairo external context driver";
3059 pdt->pl_DevName = "extcairo";
3060 #endif
3061 pdt->pl_type = plDevType_Interactive;
3062 pdt->pl_seq = 106;
3063 pdt->pl_init = (plD_init_fp) plD_init_extcairo;
3064 pdt->pl_line = (plD_line_fp) plD_line_cairo;
3065 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
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;
3069 pdt->pl_state = (plD_state_fp) plD_state_cairo;
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
3194 void plD_dispatch_init_wincairo( PLDispatchTable *pdt );
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
3353 void plD_dispatch_init_wincairo( PLDispatchTable *pdt )
3354 {
3355 #ifndef ENABLE_DYNDRIVERS
3356 pdt->pl_MenuStr = "Cairo Microsoft Windows driver";
3357 pdt->pl_DevName = "wincairo";
3358 #endif
3359 pdt->pl_type = plDevType_Interactive;
3360 pdt->pl_seq = 107;
3361 pdt->pl_init = (plD_init_fp) plD_init_wincairo;
3362 pdt->pl_line = (plD_line_fp) plD_line_cairo;
3363 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
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;
3367 pdt->pl_state = (plD_state_fp) plD_state_cairo;
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