3
// Graphics drivers that are based on the Cairo / Pango Libraries.
5
// Copyright (C) 2008 Hazen Babcock
6
// Copyright (C) 2009, 2010 Hezekiah M. Carty
8
// This file is part of PLplot.
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.
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.
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
26
//--------------------------------------------------------------------------
28
//--------------------------------------------------------------------------
35
#include <pango/pangocairo.h>
37
// PLplot header files (must occur before driver-dependent includes)
43
// Driver-dependent includes
44
#if defined ( PLD_xcairo )
45
#include <cairo-xlib.h>
48
#include <X11/Xutil.h>
49
#include <X11/cursorfont.h>
50
#include <X11/keysym.h>
52
#if defined ( PLD_pdfcairo )
53
#include <cairo-pdf.h>
55
#if defined ( PLD_pscairo )
58
#if defined ( PLD_svgcairo )
59
#include <cairo-svg.h>
61
#if defined ( PLD_wincairo )
65
//--------------------------------------------------------------------------
66
// Constants & global (to this file) variables
67
//--------------------------------------------------------------------------
70
#define PLCAIRO_DEFAULT_X 720
71
#define PLCAIRO_DEFAULT_Y 540
73
#define MAX_STRING_LEN 500
74
#define MAX_MARKUP_LEN MAX_STRING_LEN * 10
76
static int text_clipping;
77
static int text_anti_aliasing;
78
static int graphics_anti_aliasing;
79
static int external_drawable;
80
static int rasterize_image;
81
static int set_background;
82
static int image_buffering;
84
static DrvOpt cairo_options[] = { { "text_clipping", DRV_INT, &text_clipping, "Use text clipping (text_clipping=0|1)" },
85
{ "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)" },
86
{ "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" },
87
{ "external_drawable", DRV_INT, &external_drawable, "Plot to external X drawable" },
88
{ "rasterize_image", DRV_INT, &rasterize_image, "Raster or vector image rendering (rasterize_image=0|1)" },
89
{ "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" },
90
{ "image_buffering", DRV_INT, &image_buffering, "Buffered offscreen rendering for the xcairo device (image_buffering=0|1)." },
91
{ NULL, DRV_INT, NULL, NULL } };
95
cairo_surface_t *cairoSurface;
96
cairo_t *cairoContext;
97
cairo_surface_t *cairoSurface_raster;
98
cairo_t *cairoContext_raster;
100
short text_anti_aliasing;
101
short graphics_anti_aliasing;
102
short rasterize_image;
103
short set_background;
104
short image_buffering;
106
char *pangoMarkupString;
110
// These are arguments for plP_script_scale which must be retained
111
// in aStream for the alt_unicode approach. level has an
112
// identical meaning to upDown above, but it is incremented and
113
// decremented in plP_script_scale as well as other places in the
114
// code so the only safe thing to do is to treat level separately
116
PLFLT old_sscale, sscale, old_soffset, soffset;
119
#if defined ( PLD_xcairo )
120
cairo_surface_t *cairoSurface_X;
121
cairo_t *cairoContext_X;
122
short exit_event_loop;
125
unsigned int xdrawable_mode;
127
#if defined ( PLD_memcairo )
128
unsigned char *memory;
129
unsigned char *cairo_format_memory;
132
#if defined ( PLD_wincairo )
133
cairo_surface_t *cairoSurface_win;
134
cairo_t *cairoContext_win;
145
PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_cairo =
146
#if defined ( PLD_xcairo )
147
"xcairo:Cairo X Windows Driver:1:cairo:100:xcairo\n"
149
#if defined ( PLD_pdfcairo )
150
"pdfcairo:Cairo PDF Driver:0:cairo:101:pdfcairo\n"
152
#if defined ( PLD_pscairo )
153
"pscairo:Cairo PS Driver:0:cairo:102:pscairo\n"
155
#if defined ( PLD_svgcairo )
156
"svgcairo:Cairo SVG Driver:0:cairo:103:svgcairo\n"
158
#if defined ( PLD_pngcairo )
159
"pngcairo:Cairo PNG Driver:0:cairo:104:pngcairo\n"
161
#if defined ( PLD_memcairo )
162
"memcairo:Cairo Memory Driver:0:cairo:105:memcairo\n"
164
#if defined ( PLD_extcairo )
165
"extcairo:Cairo External Context Driver:0:cairo:106:extcairo\n"
167
#if defined ( PLD_wincairo )
168
"wincairo:Cairo Microscoft Windows Driver:0:cairo:107:wincairo\n"
173
// Structure for passing external drawables to xcairo devices via
174
// the PLESC_DEVINIT escape function.
176
#if defined ( PLD_xcairo )
181
} PLXcairoDrawableInfo;
184
//--------------------------------------------------------------------------
185
// Font style and weight lookup tables (copied
186
// from the psttf driver).
187
//--------------------------------------------------------------------------
189
#define NPANGOLOOKUP 5
191
const char *defaultFamilyLookup[NPANGOLOOKUP] = {
199
const char *envFamilyLookup[NPANGOLOOKUP] = {
200
"PLPLOT_FREETYPE_SANS_FAMILY",
201
"PLPLOT_FREETYPE_SERIF_FAMILY",
202
"PLPLOT_FREETYPE_MONO_FAMILY",
203
"PLPLOT_FREETYPE_SCRIPT_FAMILY",
204
"PLPLOT_FREETYPE_SYMBOL_FAMILY"
207
#define FAMILY_LOOKUP_LEN 1024
208
char familyLookup[NPANGOLOOKUP][FAMILY_LOOKUP_LEN];
212
const char *weightLookup[2] = {
217
const char *styleLookup[3] = {
224
//--------------------------------------------------------------------------
225
//--------------------------------------------------------------------------
227
// That which is common to all the Cairo Drivers
229
//--------------------------------------------------------------------------
230
//--------------------------------------------------------------------------
232
//--------------------------------------------------------------------------
233
// function declarations
234
//--------------------------------------------------------------------------
238
PLCairo *stream_and_font_setup( PLStream *, int );
239
cairo_status_t write_to_stream( void *, unsigned char *, unsigned int );
240
void set_clip( PLStream *pls );
244
static void proc_str( PLStream *, EscText * );
245
static void text_begin_cairo( PLStream *pls, EscText *args );
246
static void text_char_cairo( PLStream *pls, EscText *args );
247
static void text_esc_cairo( PLStream *pls, EscText *args );
248
static void text_end_cairo( PLStream *pls, EscText *args );
249
static char *ucs4_to_pango_markup_format( PLUNICODE *, int, float );
250
static void open_span_tag( char *, PLUNICODE, float, int );
251
static void close_span_tag( char *, int );
252
static char *rise_span_tag( int, float, float, float );
256
static void set_current_context( PLStream * );
257
static void poly_line( PLStream *, short *, short *, PLINT );
258
static void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts );
259
static void gradient( PLStream *pls, short *xa, short *ya, PLINT npts );
260
static void arc( PLStream *, arc_struct * );
261
static void rotate_cairo_surface( PLStream *, float, float, float, float, float, float, PLBOOL );
262
// Rasterization of plotted material
263
static void start_raster( PLStream* );
264
static void end_raster( PLStream* );
265
// Get/set drawing mode
266
static void set_mode( PLStream*, PLINT* );
267
static void get_mode( PLStream*, PLINT* );
269
// PLplot interface functions
272
void plD_bop_cairo( PLStream * );
273
void plD_eop_cairo( PLStream * );
274
void plD_state_cairo( PLStream *, PLINT );
275
void plD_esc_cairo( PLStream *, PLINT, void * );
276
void plD_tidy_cairo( PLStream * );
277
void plD_line_cairo( PLStream *, short, short, short, short );
278
void plD_polyline_cairo( PLStream *, short *, short *, PLINT );
280
//--------------------------------------------------------------------------
283
// Set up off-screen rasterized rendering
284
//--------------------------------------------------------------------------
286
void start_raster( PLStream *pls )
289
cairo_surface_t *tmp_sfc;
290
cairo_t *tmp_context;
292
aStream = (PLCairo *) pls->dev;
294
// Do not use the external surface if the user says not to
295
if ( !aStream->rasterize_image )
298
// Create an image surface and context for the offscreen rendering
299
aStream->cairoSurface_raster =
301
// cairo_surface_create_similar( aStream->cairoSurface,
302
// CAIRO_CONTENT_COLOR,
303
// pls->xlength, pls->ylength );
305
cairo_image_surface_create( CAIRO_FORMAT_ARGB32,
306
pls->xlength, pls->ylength );
307
aStream->cairoContext_raster = cairo_create( aStream->cairoSurface_raster );
309
// Disable antialiasing for the raster surface. The output seems to look
311
cairo_set_antialias( aStream->cairoContext_raster, CAIRO_ANTIALIAS_NONE );
313
// Swap the raster and main plot surfaces and contexts
314
tmp_sfc = aStream->cairoSurface;
315
tmp_context = aStream->cairoContext;
316
aStream->cairoSurface = aStream->cairoSurface_raster;
317
aStream->cairoContext = aStream->cairoContext_raster;
318
// Save the main plot surface and context for when we are finished
319
aStream->cairoSurface_raster = tmp_sfc;
320
aStream->cairoContext_raster = tmp_context;
323
//--------------------------------------------------------------------------
326
// Finish off-screen rasterized rendering and copy the result on to the
327
// main plot surface.
328
//--------------------------------------------------------------------------
330
void end_raster( PLStream *pls )
333
cairo_surface_t *tmp_sfc;
334
cairo_t *tmp_context;
336
aStream = (PLCairo *) pls->dev;
338
// TODO FIXME: This should really only copy the used portion of the
341
// Do not use the external surface if the user says not to
342
if ( !aStream->rasterize_image )
345
// Some Cairo devices support delayed device setup (eg: xcairo with
346
// external drawable and extcairo with an external context).
347
if ( aStream->cairoContext == NULL )
348
plexit( "Can not plot to a Cairo device with no context" );
350
// Restore the main plot surface and context for future plotting
351
tmp_sfc = aStream->cairoSurface;
352
tmp_context = aStream->cairoContext;
353
aStream->cairoSurface = aStream->cairoSurface_raster;
354
aStream->cairoContext = aStream->cairoContext_raster;
355
aStream->cairoSurface_raster = tmp_sfc;
356
aStream->cairoContext_raster = tmp_context;
358
// Blit the raster surface on to the main plot
359
cairo_set_source_surface( aStream->cairoContext, aStream->cairoSurface_raster, 0.0, 0.0 );
360
cairo_paint( aStream->cairoContext );
362
// Free the now extraneous surface and context
363
cairo_destroy( aStream->cairoContext_raster );
364
cairo_surface_destroy( aStream->cairoSurface_raster );
367
//--------------------------------------------------------------------------
370
// Set up for the next page.
371
//--------------------------------------------------------------------------
373
void plD_bop_cairo( PLStream *pls )
377
aStream = (PLCairo *) pls->dev;
379
// Some Cairo devices support delayed device setup (eg: xcairo with
380
// external drawable and extcairo with an external context).
381
if ( aStream->cairoContext == NULL )
384
// Fill in the window with the background color.
385
cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
386
if ( (double) pls->cmap0[0].a < 1.0 )
388
cairo_set_source_rgba( aStream->cairoContext, 1.0, 1.0, 1.0, 1.0 );
389
cairo_fill_preserve( aStream->cairoContext );
391
cairo_set_source_rgba( aStream->cairoContext,
392
(double) pls->cmap0[0].r / 255.0,
393
(double) pls->cmap0[0].g / 255.0,
394
(double) pls->cmap0[0].b / 255.0,
395
(double) pls->cmap0[0].a );
396
cairo_fill( aStream->cairoContext );
399
//--------------------------------------------------------------------------
402
// Draw a line in the current color from (x1,y1) to (x2,y2).
403
//--------------------------------------------------------------------------
405
//--------------------------------------------------------------------------
406
// (get|set)_line_properties
408
// (Get|Set) the current Cairo line drawing properties.
409
//--------------------------------------------------------------------------
410
void get_line_properties( PLCairo *aStream, cairo_line_join_t *join, cairo_line_cap_t *cap )
412
*join = cairo_get_line_join( aStream->cairoContext );
413
*cap = cairo_get_line_cap( aStream->cairoContext );
416
void set_line_properties( PLCairo *aStream, cairo_line_join_t join, cairo_line_cap_t cap )
418
cairo_set_line_join( aStream->cairoContext, join );
419
cairo_set_line_cap( aStream->cairoContext, cap );
422
void plD_line_cairo( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
426
aStream = (PLCairo *) pls->dev;
428
set_current_context( pls );
430
cairo_save( aStream->cairoContext );
432
set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_ROUND );
434
cairo_move_to( aStream->cairoContext, aStream->downscale * (double) x1a, aStream->downscale * (double) y1a );
435
cairo_line_to( aStream->cairoContext, aStream->downscale * (double) x2a, aStream->downscale * (double) y2a );
437
cairo_stroke( aStream->cairoContext );
439
cairo_restore( aStream->cairoContext );
442
//--------------------------------------------------------------------------
443
// plD_polyline_cairo()
445
// Draw a polyline in the current color.
446
//--------------------------------------------------------------------------
448
void plD_polyline_cairo( PLStream *pls, short *xa, short *ya, PLINT npts )
452
aStream = (PLCairo *) pls->dev;
454
cairo_save( aStream->cairoContext );
456
set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
458
poly_line( pls, xa, ya, npts );
460
cairo_stroke( aStream->cairoContext );
462
cairo_restore( aStream->cairoContext );
465
//--------------------------------------------------------------------------
468
// Generic end of page.
469
//--------------------------------------------------------------------------
471
void plD_eop_cairo( PLStream *pls )
475
aStream = (PLCairo *) pls->dev;
477
cairo_show_page( aStream->cairoContext );
480
//--------------------------------------------------------------------------
483
// General: Close graphics file or otherwise clean up.
484
//--------------------------------------------------------------------------
486
void plD_tidy_cairo( PLStream *pls )
490
aStream = (PLCairo *) pls->dev;
492
// Free the cairo context and surface.
493
cairo_destroy( aStream->cairoContext );
494
cairo_surface_destroy( aStream->cairoSurface );
499
//--------------------------------------------------------------------------
502
// Handle change in PLStream state (color, pen width, fill attribute, etc).
504
// Nothing is done here because these attributes are acquired from
505
// PLStream for each element that is drawn.
506
//--------------------------------------------------------------------------
508
void plD_state_cairo( PLStream *pls, PLINT op )
512
//--------------------------------------------------------------------------
515
// Generic escape function.
516
//--------------------------------------------------------------------------
518
void plD_esc_cairo( PLStream *pls, PLINT op, void *ptr )
522
aStream = (PLCairo *) pls->dev;
526
case PLESC_FILL: // filled polygon
527
filled_polygon( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
529
case PLESC_GRADIENT: // render a gradient within a polygon.
530
gradient( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
533
if ( !pls->alt_unicode )
535
proc_str( pls, (EscText *) ptr );
538
case PLESC_BEGIN_TEXT: // get ready to get a handle a string of text
539
text_begin_cairo( pls, (EscText *) ptr );
541
case PLESC_TEXT_CHAR: // handle a character of text to display
542
text_char_cairo( pls, (EscText *) ptr );
544
case PLESC_CONTROL_CHAR: // handle a control character (super/subscript of fontchange)
545
text_esc_cairo( pls, (EscText *) ptr );
547
case PLESC_END_TEXT: // finish a string of text
548
text_end_cairo( pls, (EscText *) ptr );
550
case PLESC_START_RASTERIZE: // Start offscreen/rasterized rendering
553
case PLESC_END_RASTERIZE: // End offscreen/rasterized rendering
556
case PLESC_ARC: // Draw an arc, either filled or outline
557
arc( pls, (arc_struct *) ptr );
559
case PLESC_MODESET: // Set drawing mode
560
set_mode( pls, (int *) ptr );
562
case PLESC_MODEGET: // Get drawing mode
563
get_mode( pls, (int *) ptr );
569
//--------------------------------------------------------------------------
573
//--------------------------------------------------------------------------
574
void set_mode( PLStream *pls, PLINT *mode )
578
aStream = (PLCairo *) pls->dev;
582
case PL_DRAWMODE_UNKNOWN: // Invalid - do nothing
584
case PL_DRAWMODE_DEFAULT:
585
cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_OVER );
587
case PL_DRAWMODE_REPLACE:
588
cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_SOURCE );
590
case PL_DRAWMODE_XOR:
591
cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_XOR );
597
//--------------------------------------------------------------------------
601
//--------------------------------------------------------------------------
602
void get_mode( PLStream *pls, PLINT *mode )
607
aStream = (PLCairo *) pls->dev;
609
op = cairo_get_operator( aStream->cairoContext );
613
case CAIRO_OPERATOR_OVER:
614
*mode = PL_DRAWMODE_DEFAULT;
616
case CAIRO_OPERATOR_SOURCE:
617
*mode = PL_DRAWMODE_REPLACE;
619
case CAIRO_OPERATOR_XOR:
620
*mode = PL_DRAWMODE_XOR;
623
*mode = PL_DRAWMODE_UNKNOWN;
628
//--------------------------------------------------------------------------
629
// text_begin_cairo()
632
//--------------------------------------------------------------------------
634
void text_begin_cairo( PLStream *pls, EscText *args )
639
aStream = (PLCairo *) pls->dev;
642
aStream->pangoMarkupString = (char *) malloc( sizeof ( char ) * MAX_MARKUP_LEN );
643
// Calculate the font size (in points since DPI = 72).
644
aStream->fontSize = pls->chrht * DPI / 25.4;
645
for ( i = 0; i < MAX_MARKUP_LEN; i++ )
647
aStream->pangoMarkupString[i] = 0;
649
open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, 0 );
652
//--------------------------------------------------------------------------
656
//--------------------------------------------------------------------------
658
void text_char_cairo( PLStream *pls, EscText *args )
663
aStream = (PLCairo *) pls->dev;
664
// make sure we are not too close to the end of the string
665
if ( strlen( aStream->pangoMarkupString ) < ( MAX_MARKUP_LEN - 50 ) )
667
switch ( args->n_char )
670
strncat( aStream->pangoMarkupString, "&", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
673
strncat( aStream->pangoMarkupString, "<", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
676
strncat( aStream->pangoMarkupString, ">", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
679
ucs4_to_utf8( args->n_char, utf8 );
680
strncat( aStream->pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
686
//--------------------------------------------------------------------------
689
// A font change, superscript, subscript, etc...
690
//--------------------------------------------------------------------------
692
void text_esc_cairo( PLStream *pls, EscText *args )
696
aStream = (PLCairo *) pls->dev;
697
switch ( args->n_ctrl_char )
699
case PLTEXT_FONTCHANGE:
700
close_span_tag( aStream->pangoMarkupString, aStream->upDown );
701
open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, aStream->upDown );
703
case PLTEXT_SUPERSCRIPT:
704
if ( aStream->upDown < 0 )
706
strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
711
plP_script_scale( TRUE, &aStream->level,
712
&aStream->old_sscale, &aStream->sscale, &aStream->old_soffset, &aStream->soffset );
713
strncat( aStream->pangoMarkupString,
714
rise_span_tag( TRUE, aStream->fontSize, aStream->sscale, aStream->soffset ),
715
MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
719
case PLTEXT_SUBSCRIPT:
720
if ( aStream->upDown > 0 )
722
strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
727
plP_script_scale( FALSE, &aStream->level,
728
&aStream->old_sscale, &aStream->sscale, &aStream->old_soffset, &aStream->soffset );
729
strncat( aStream->pangoMarkupString,
730
rise_span_tag( FALSE, aStream->fontSize, aStream->sscale, aStream->soffset ),
731
MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
738
//--------------------------------------------------------------------------
741
// Draw the text and clean up.
742
//--------------------------------------------------------------------------
744
void text_end_cairo( PLStream *pls, EscText *args )
746
int textXExtent, textYExtent, baseline;
747
PLFLT rotation, shear, stride, cos_rot, sin_rot, cos_shear, sin_shear;
748
cairo_matrix_t *cairoTransformMatrix;
749
cairo_font_options_t *cairoFontOptions;
750
PangoContext *context;
754
aStream = (PLCairo *) pls->dev;
756
set_current_context( pls );
758
// Close the last span tag.
759
close_span_tag( aStream->pangoMarkupString, aStream->upDown );
761
// printf("%s\n", aStream->pangoMarkupString);
763
// Create the Pango text layout so we can figure out how big it is
764
layout = pango_cairo_create_layout( aStream->cairoContext );
765
pango_layout_set_markup( layout, aStream->pangoMarkupString, -1 );
766
pango_layout_get_pixel_size( layout, &textXExtent, &textYExtent );
767
baseline = pango_layout_get_baseline( layout );
769
// If asked, set the string length (in mm) and return
770
if ( pls->get_string_length )
772
pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
777
context = pango_layout_get_context( layout );
778
cairoFontOptions = cairo_font_options_create();
779
cairo_font_options_set_antialias( cairoFontOptions, aStream->text_anti_aliasing );
780
pango_cairo_context_set_font_options( context, cairoFontOptions );
781
pango_layout_context_changed( layout );
782
cairo_font_options_destroy( cairoFontOptions );
784
// Save current transform matrix & clipping region
785
cairo_save( aStream->cairoContext );
787
// Set up the clipping region if we are doing text clipping
788
if ( aStream->text_clipping )
793
// Move to the string reference point
794
cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
796
// Invert the coordinate system so that the text is drawn right side up
797
cairoTransformMatrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
798
cairo_matrix_init( cairoTransformMatrix, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
799
cairo_transform( aStream->cairoContext, cairoTransformMatrix );
801
// Extract rotation angle and shear from the PLplot tranformation matrix.
802
// Compute sines and cosines of the angles as an optimization.
803
plRotationShear( args->xform, &rotation, &shear, &stride );
804
rotation -= pls->diorot * PI / 2.0;
805
cos_rot = cos( rotation );
806
sin_rot = sin( rotation );
807
cos_shear = cos( shear );
808
sin_shear = sin( shear );
810
// Apply the transform matrix
811
cairo_matrix_init( cairoTransformMatrix,
814
cos_rot * sin_shear + sin_rot * cos_shear,
815
-sin_rot * sin_shear + cos_rot * cos_shear,
817
cairo_transform( aStream->cairoContext, cairoTransformMatrix );
818
free( cairoTransformMatrix );
820
// Move to the text starting point
821
// printf("baseline %d %d\n", baseline, textYExtent);
822
cairo_rel_move_to( aStream->cairoContext,
823
(double) ( -1.0 * args->just * (double) textXExtent ),
824
(double) 0.5 * aStream->fontSize - baseline / 1024.0 );
827
pango_cairo_show_layout( aStream->cairoContext, layout );
829
// Restore the transform matrix to its state prior to the text transform.
830
cairo_restore( aStream->cairoContext );
832
// Free the layout object and the markup string.
833
g_object_unref( layout );
834
free( aStream->pangoMarkupString );
837
//--------------------------------------------------------------------------
840
// Processes strings for display.
841
//--------------------------------------------------------------------------
843
void proc_str( PLStream *pls, EscText *args )
846
int textXExtent, textYExtent, baseline;
847
char *textWithPangoMarkup;
848
PLFLT rotation, shear, stride, cos_rot, sin_rot, cos_shear, sin_shear;
849
cairo_matrix_t *cairoTransformMatrix;
850
cairo_font_options_t *cairoFontOptions;
851
PangoContext *context;
855
aStream = (PLCairo *) pls->dev;
857
set_current_context( pls );
859
// Check that we got unicode, warning message and return if not
860
if ( args->unicode_array_len == 0 )
862
printf( "Non unicode string passed to a cairo driver, ignoring\n" );
866
// Check that unicode string isn't longer then the max we allow
867
if ( args->unicode_array_len >= MAX_STRING_LEN )
869
printf( "Sorry, the cairo drivers only handles strings of length < %d\n", MAX_STRING_LEN );
873
// Calculate the font size (in points since DPI = 72).
874
fontSize = pls->chrht * DPI / 25.4;
876
// Convert the escape characters into the appropriate Pango markup
877
textWithPangoMarkup = ucs4_to_pango_markup_format( args->unicode_array, args->unicode_array_len, fontSize );
879
// Create the Pango text layout so we can figure out how big it is
880
layout = pango_cairo_create_layout( aStream->cairoContext );
881
pango_layout_set_markup( layout, textWithPangoMarkup, -1 );
882
pango_layout_get_pixel_size( layout, &textXExtent, &textYExtent );
883
baseline = pango_layout_get_baseline( layout );
885
// If asked, set the string length (in mm) and return
886
if ( pls->get_string_length )
888
pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
893
context = pango_layout_get_context( layout );
894
cairoFontOptions = cairo_font_options_create();
895
cairo_font_options_set_antialias( cairoFontOptions, aStream->text_anti_aliasing );
896
pango_cairo_context_set_font_options( context, cairoFontOptions );
897
pango_layout_context_changed( layout );
898
cairo_font_options_destroy( cairoFontOptions );
900
// Save current transform matrix & clipping region
901
cairo_save( aStream->cairoContext );
903
// Set up the clipping region if we are doing text clipping
904
if ( aStream->text_clipping )
909
// Move to the string reference point
910
cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
912
// Invert the coordinate system so that the text is drawn right side up
913
cairoTransformMatrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
914
cairo_matrix_init( cairoTransformMatrix, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
915
cairo_transform( aStream->cairoContext, cairoTransformMatrix );
917
// Extract rotation angle and shear from the PLplot tranformation matrix.
918
// Compute sines and cosines of the angles as an optimization.
919
plRotationShear( args->xform, &rotation, &shear, &stride );
920
rotation -= pls->diorot * PI / 2.0;
921
cos_rot = cos( rotation );
922
sin_rot = sin( rotation );
923
cos_shear = cos( shear );
924
sin_shear = sin( shear );
926
// Apply the transform matrix
927
cairo_matrix_init( cairoTransformMatrix,
930
cos_rot * sin_shear + sin_rot * cos_shear,
931
-sin_rot * sin_shear + cos_rot * cos_shear,
933
cairo_transform( aStream->cairoContext, cairoTransformMatrix );
934
free( cairoTransformMatrix );
936
// printf("baseline (ps) %d %d %f\n", baseline, textYExtent, aStream->fontSize);
937
// Move to the text starting point
938
cairo_rel_move_to( aStream->cairoContext,
939
(double) ( -1.0 * args->just * (double) textXExtent ),
940
(double) 0.5 * fontSize - baseline / 1024.0 );
943
pango_cairo_show_layout( aStream->cairoContext, layout );
945
// Restore the transform matrix to its state prior to the text transform.
946
cairo_restore( aStream->cairoContext );
948
// Free the layout object and the markup string.
949
g_object_unref( layout );
950
free( textWithPangoMarkup );
953
//--------------------------------------------------------------------------
954
// ucs4_to_pango_markup_format()
956
// Converts the plplot string (in ucs4) to a utf8 string that includes
959
// http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html
960
//--------------------------------------------------------------------------
962
char *ucs4_to_pango_markup_format( PLUNICODE *ucs4, int ucs4Len, float fontSize )
969
char *pangoMarkupString;
970
PLFLT old_sscale, sscale, old_soffset, soffset;
973
// Will this be big enough? We might have lots of markup.
974
pangoMarkupString = (char *) malloc( sizeof ( char ) * MAX_MARKUP_LEN );
975
for ( i = 0; i < MAX_MARKUP_LEN; i++ )
977
pangoMarkupString[i] = 0;
980
// Get PLplot escape character
981
plgesc( &plplotEsc );
983
// Get the curent font and open the first span tag
985
open_span_tag( pangoMarkupString, fci, fontSize, 0 );
987
// Parse the string to generate the tags
989
while ( i < ucs4Len )
991
// Try to avoid going off the end of the string
992
if ( strlen( pangoMarkupString ) > ( MAX_MARKUP_LEN - 50 ) )
996
if ( ucs4[i] < PL_FCI_MARK ) // not a font change
998
if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
999
{ // we have to handle "<", ">" and "&" separately since they throw off the XML
1003
strncat( pangoMarkupString, "&", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1006
strncat( pangoMarkupString, "<", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1009
strncat( pangoMarkupString, ">", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1012
ucs4_to_utf8( ucs4[i], utf8 );
1013
strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1020
if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
1022
ucs4_to_utf8( ucs4[i], utf8 );
1023
strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1029
if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
1033
strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1038
plP_script_scale( TRUE, &level,
1039
&old_sscale, &sscale, &old_soffset, &soffset );
1040
strncat( pangoMarkupString,
1041
rise_span_tag( TRUE, fontSize, sscale, soffset ),
1042
MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1046
if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
1050
strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1055
plP_script_scale( FALSE, &level,
1056
&old_sscale, &sscale, &old_soffset, &soffset );
1057
strncat( pangoMarkupString,
1058
rise_span_tag( FALSE, fontSize, sscale, soffset ),
1059
MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1066
else // a font change
1068
close_span_tag( pangoMarkupString, upDown );
1069
open_span_tag( pangoMarkupString, ucs4[i], fontSize, upDown );
1074
// Close the last span tag.
1075
close_span_tag( pangoMarkupString, upDown );
1077
// printf("%s\n", pangoMarkupString);
1079
return pangoMarkupString;
1082
//--------------------------------------------------------------------------
1085
// 1. Opens a span tag with the appropriate font description given the
1087
// 2. Add the appropriate number of <sub> or <sup> tags to bring us
1088
// back to our current sub/super-script level.
1089
//--------------------------------------------------------------------------
1091
void open_span_tag( char *pangoMarkupString, PLUNICODE fci, float fontSize, int upDown )
1093
unsigned char fontFamily, fontStyle, fontWeight;
1094
char openTag[TAG_LEN];
1096
PLFLT old_sscale, sscale, old_soffset, soffset;
1099
// Generate the font info for the open tag & concatenate this
1100
// onto the markup string.
1101
plP_fci2hex( fci, &fontFamily, PL_FCI_FAMILY );
1102
plP_fci2hex( fci, &fontStyle, PL_FCI_STYLE );
1103
plP_fci2hex( fci, &fontWeight, PL_FCI_WEIGHT );
1105
// From http://library.gnome.org/devel/pango/unstable/PangoMarkupFormat.html
1106
// size = font size in 1024ths of a point.
1107
snprintf( openTag, TAG_LEN, "<span font_desc=\"%s\" size=\"%d\" ", familyLookup[fontFamily], (int) ( fontSize * 1024. ) );
1108
strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1110
snprintf( openTag, TAG_LEN, "style=\"%s\" ", styleLookup[fontStyle] );
1111
strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1113
snprintf( openTag, TAG_LEN, "weight=\"%s\">", weightLookup[fontWeight] );
1114
strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1116
// Move to the right superscript/subscript level
1117
for ( upDown_level = 0; upDown_level < upDown; upDown_level++ )
1119
plP_script_scale( TRUE, &level,
1120
&old_sscale, &sscale, &old_soffset, &soffset );
1121
strncat( pangoMarkupString,
1122
rise_span_tag( TRUE, fontSize, sscale, soffset ),
1123
MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1125
for ( upDown_level = 0; upDown_level > upDown; upDown_level-- )
1127
plP_script_scale( FALSE, &level,
1128
&old_sscale, &sscale, &old_soffset, &soffset );
1129
strncat( pangoMarkupString,
1130
rise_span_tag( FALSE, fontSize, sscale, soffset ),
1131
MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1135
//--------------------------------------------------------------------------
1138
// Close a span tag & brings us down to zero sub/super-script level.
1139
//--------------------------------------------------------------------------
1141
void close_span_tag( char *pangoMarkupString, int upDown )
1145
while ( upDown > 0 )
1147
strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1153
while ( upDown < 0 )
1155
strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1160
strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
1163
// 0.8 mimics the offset of first superscript/subscript level implemented
1164
// in plstr (plsym.c) for Hershey fonts. Indeed when comparing with
1165
// -dev xwin results this factor appears to offset the centers of the
1166
// letters appropriately (but not their edges since different font sizes
1168
# define RISE_FACTOR 0.8
1170
//--------------------------------------------------------------------------
1173
// Create a rise span tag w/ appropriate font size & baseline offset
1174
// fontSize is the baseline font size in points (1/72 of an inch),
1175
// multiplier is a scaling factor for that font size for superscript
1176
// or subscript, and rise is the vertical offset (in units of font
1177
// size) for that superscript or subscript.
1179
//--------------------------------------------------------------------------
1181
char *rise_span_tag( int ifsuperscript, float fontSize, float multiplier, float rise )
1184
static char tag[100];
1186
// http://developer.gnome.org/pango/unstable/PangoMarkupFormat.html says
1187
// rise should be in units of 10000 em's, but empricial evidence shows
1188
// it is in units of 1024th of a point. Therefore, since FontSize
1189
// is in points, a rise of 1024. * fontSize corresponds a rise of
1190
// a full character height.
1191
rise = 1024. * fontSize * RISE_FACTOR * rise;
1193
// This is the correction for the difference between baseline and
1194
// middle coordinate systems. This offset should be
1195
// 0.5*(fontSize - superscript/subscript fontSize).
1196
offset = 1024. * 0.5 * fontSize * ( 1.0 - multiplier );
1198
if ( ifsuperscript )
1200
sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
1201
(int) ( rise + offset ), (int) ( fontSize * 1024. * multiplier ) );
1205
sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
1206
(int) -( rise - offset ), (int) ( fontSize * 1024. * multiplier ) );
1212
//--------------------------------------------------------------------------
1213
// write_to_stream()
1215
// Writes data to a open file stream. This function is passed to the
1216
// Cairo file IO devices.
1217
//--------------------------------------------------------------------------
1219
cairo_status_t write_to_stream( void *filePointer, unsigned char *data, unsigned int length )
1223
bytes_written = fwrite( data, 1, length, (FILE *) filePointer );
1224
if ( bytes_written == length )
1226
return CAIRO_STATUS_SUCCESS;
1230
return CAIRO_STATUS_WRITE_ERROR;
1234
//--------------------------------------------------------------------------
1235
// stream_and_font_setup()
1237
// Initializes the PLStream structure for the cairo devices.
1238
// Initializes the font lookup table.
1239
// Checks for cairo specific user options.
1240
// Returns a new PLCairo structure.
1241
//--------------------------------------------------------------------------
1243
PLCairo *stream_and_font_setup( PLStream *pls, int interactive )
1252
pls->termin = interactive; // Interactive device
1253
pls->dev_flush = 1; // Handles flushes
1254
pls->color = 1; // Supports color
1255
pls->dev_text = 1; // Handles text
1256
pls->dev_unicode = 1; // Wants unicode text
1258
pls->alt_unicode = 1; // Wants to handle unicode character by character
1260
pls->dev_fill0 = 1; // Supports hardware solid fills
1261
pls->dev_gradient = 1; // driver renders gradient
1262
pls->dev_arc = 1; // Supports driver-level arcs
1263
pls->plbuf_write = interactive; // Activate plot buffer
1264
pls->has_string_length = 1; // Driver supports string length calculations
1265
pls->dev_modeset = 1; // Driver supports drawing mode setting
1267
if ( pls->xlength <= 0 || pls->ylength <= 0 )
1269
pls->xlength = PLCAIRO_DEFAULT_X;
1270
pls->ylength = PLCAIRO_DEFAULT_Y;
1272
// Calculate ratio of (smaller) external coordinates used for cairo
1273
// devices to (larger) internal PLplot coordinates.
1274
if ( pls->xlength > pls->ylength )
1275
downscale = (double) pls->xlength / (double) ( PIXELS_X - 1 );
1277
downscale = (double) pls->ylength / (double) PIXELS_Y;
1278
plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / downscale ), (PLINT) 0, (PLINT) ( pls->ylength / downscale ) );
1279
plP_setpxl( DPI / 25.4 / downscale, DPI / 25.4 / downscale );
1281
// Initialize font table with either enviroment variables or defaults.
1282
// This was copied from the psttf driver.
1283
for ( i = 0; i < NPANGOLOOKUP; i++ )
1285
if ( ( a = getenv( envFamilyLookup[i] ) ) != NULL )
1287
strncpy( familyLookup[i], a, FAMILY_LOOKUP_LEN - 1 );
1288
familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
1292
strncpy( familyLookup[i], defaultFamilyLookup[i], FAMILY_LOOKUP_LEN - 1 );
1293
familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
1297
// Allocate a cairo stream structure
1298
aStream = malloc( sizeof ( PLCairo ) );
1299
#if defined ( PLD_xcairo )
1300
aStream->XDisplay = NULL;
1301
aStream->XWindow = -1;
1303
aStream->cairoSurface = NULL;
1304
aStream->cairoContext = NULL;
1305
aStream->downscale = downscale;
1307
// Set text clipping on by default since it makes little difference in
1308
// speed for a modern cairo stack.
1309
aStream->text_clipping = 1;
1311
text_anti_aliasing = 0; // use 'default' text aliasing by default
1312
graphics_anti_aliasing = 0; // use 'default' graphics aliasing by default
1313
rasterize_image = 1; // Enable rasterization by default
1314
set_background = 0; // Default for extcairo is that PLplot not change the background
1315
image_buffering = 1; // Default to image-based buffered rendering
1317
// Check for cairo specific options
1318
plParseDrvOpts( cairo_options );
1320
// Turn off text clipping if the user desires this
1321
if ( !text_clipping )
1323
aStream->text_clipping = 0;
1326
// Record users desired text and graphics aliasing and rasterization
1327
aStream->text_anti_aliasing = text_anti_aliasing;
1328
aStream->graphics_anti_aliasing = graphics_anti_aliasing;
1329
aStream->rasterize_image = rasterize_image;
1330
aStream->set_background = set_background;
1331
aStream->image_buffering = image_buffering;
1336
//--------------------------------------------------------------------------
1337
// set_current_context()
1339
// Updates the cairo graphics context with the current values in
1341
//--------------------------------------------------------------------------
1343
void set_current_context( PLStream *pls )
1347
aStream = (PLCairo *) pls->dev;
1348
cairo_set_source_rgba( aStream->cairoContext,
1349
(double) pls->curcolor.r / 255.0,
1350
(double) pls->curcolor.g / 255.0,
1351
(double) pls->curcolor.b / 255.0,
1352
(double) pls->curcolor.a );
1353
// In Cairo, zero width lines are not hairlines, they are completely invisible.
1354
if ( pls->width < 1 )
1356
cairo_set_line_width( aStream->cairoContext, 1.0 );
1360
cairo_set_line_width( aStream->cairoContext, (double) pls->width );
1364
//--------------------------------------------------------------------------
1367
// Draws a multi-segmented line. It is then up to the calling function
1368
// to decide whether to just draw the line, or fill in the area
1369
// enclosed by the line.
1370
//--------------------------------------------------------------------------
1372
void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts )
1377
aStream = (PLCairo *) pls->dev;
1379
set_current_context( pls );
1381
cairo_move_to( aStream->cairoContext, aStream->downscale * (double) xa[0], aStream->downscale * (double) ya[0] );
1382
for ( i = 1; i < npts; i++ )
1384
cairo_line_to( aStream->cairoContext, aStream->downscale * (double) xa[i], aStream->downscale * (double) ya[i] );
1388
//--------------------------------------------------------------------------
1391
// Draws a filled polygon.
1392
//--------------------------------------------------------------------------
1394
void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts )
1399
aStream = (PLCairo *) pls->dev;
1401
cairo_save( aStream->cairoContext );
1403
// Draw the polygons
1404
poly_line( pls, xa, ya, npts );
1406
cairo_set_source_rgba( aStream->cairoContext,
1407
(double) pls->curcolor.r / 255.0,
1408
(double) pls->curcolor.g / 255.0,
1409
(double) pls->curcolor.b / 255.0,
1410
(double) pls->curcolor.a );
1412
if ( cairo_get_antialias( aStream->cairoContext ) != CAIRO_ANTIALIAS_NONE )
1414
cairo_fill_preserve( aStream->cairoContext );
1416
// These line properties make for a nicer looking polygon mesh
1417
set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
1418
cairo_set_line_width( aStream->cairoContext, 1.0 );
1419
cairo_stroke( aStream->cairoContext );
1423
cairo_fill( aStream->cairoContext );
1426
cairo_restore( aStream->cairoContext );
1429
//--------------------------------------------------------------------------
1432
// Render a gradient within a polygon.
1433
//--------------------------------------------------------------------------
1435
void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
1439
cairo_pattern_t *linear_gradient;
1441
aStream = (PLCairo *) pls->dev;
1443
// These line properties make for a nicer looking polygon mesh
1444
set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
1446
linear_gradient = cairo_pattern_create_linear(
1447
aStream->downscale * pls->xgradient[0],
1448
aStream->downscale * pls->ygradient[0],
1449
aStream->downscale * pls->xgradient[1],
1450
aStream->downscale * pls->ygradient[1] );
1452
cairo_pattern_reference( linear_gradient );
1453
for ( i = 0; i < pls->ncol1; i++ )
1455
cairo_pattern_add_color_stop_rgba( linear_gradient,
1456
(double) i / (double) ( pls->ncol1 - 1 ),
1457
(double) pls->cmap1[i].r / 255.,
1458
(double) pls->cmap1[i].g / 255.,
1459
(double) pls->cmap1[i].b / 255.,
1460
(double) pls->cmap1[i].a );
1463
// Draw the polygon using the gradient.
1464
poly_line( pls, xa, ya, npts );
1466
cairo_set_source( aStream->cairoContext, linear_gradient );
1467
cairo_fill( aStream->cairoContext );
1468
cairo_pattern_destroy( linear_gradient );
1471
//--------------------------------------------------------------------------
1474
// Set the clipping region to the plot window.
1475
// NOTE: cairo_save() and cairo_restore() should probably be called before
1476
// and after this, respectively.
1477
//--------------------------------------------------------------------------
1479
void set_clip( PLStream *pls )
1481
PLINT rcx[4], rcy[4];
1483
aStream = (PLCairo *) pls->dev;
1485
// Use PLplot core routine to get the corners of the clipping rectangle
1486
difilt_clip( rcx, rcy );
1488
// Layout the bounds of the clipping region
1489
// Should we convert PLINT to short and use the polyline routine?
1490
cairo_move_to( aStream->cairoContext,
1491
aStream->downscale * (double) rcx[0],
1492
aStream->downscale * (double) rcy[0] );
1493
cairo_line_to( aStream->cairoContext,
1494
aStream->downscale * (double) rcx[1],
1495
aStream->downscale * (double) rcy[1] );
1496
cairo_line_to( aStream->cairoContext,
1497
aStream->downscale * (double) rcx[2],
1498
aStream->downscale * (double) rcy[2] );
1499
cairo_line_to( aStream->cairoContext,
1500
aStream->downscale * (double) rcx[3],
1501
aStream->downscale * (double) rcy[3] );
1502
cairo_line_to( aStream->cairoContext,
1503
aStream->downscale * (double) rcx[0],
1504
aStream->downscale * (double) rcy[0] );
1506
// Set the clipping region
1507
cairo_clip( aStream->cairoContext );
1509
// Apparently, in some older Cairo versions, cairo_clip does not consume
1510
// the current path.
1511
cairo_new_path( aStream->cairoContext );
1514
//--------------------------------------------------------------------------
1517
// Draws an arc, possibly filled.
1518
//--------------------------------------------------------------------------
1520
void arc( PLStream *pls, arc_struct *arc_info )
1524
double angle1, angle2, rotate;
1526
set_current_context( pls );
1528
aStream = (PLCairo *) pls->dev;
1530
// Scale to the proper Cairo coordinates
1531
x = aStream->downscale * arc_info->x;
1532
y = aStream->downscale * arc_info->y;
1533
a = aStream->downscale * arc_info->a;
1534
b = aStream->downscale * arc_info->b;
1536
// Degrees to radians
1537
angle1 = arc_info->angle1 * M_PI / 180.0;
1538
angle2 = arc_info->angle2 * M_PI / 180.0;
1539
rotate = arc_info->rotate * M_PI / 180.0;
1541
cairo_save( aStream->cairoContext );
1543
// Clip the output to the plotting window
1546
// Make sure the arc is properly shaped and oriented
1547
cairo_save( aStream->cairoContext );
1548
cairo_translate( aStream->cairoContext, x, y );
1549
cairo_rotate( aStream->cairoContext, rotate );
1550
cairo_scale( aStream->cairoContext, a, b );
1551
cairo_arc( aStream->cairoContext, 0.0, 0.0, 1.0, angle1, angle2 );
1552
if ( arc_info->fill )
1553
cairo_line_to( aStream->cairoContext, 0.0, 0.0 );
1554
cairo_restore( aStream->cairoContext );
1556
cairo_set_source_rgba( aStream->cairoContext,
1557
(double) pls->curcolor.r / 255.0,
1558
(double) pls->curcolor.g / 255.0,
1559
(double) pls->curcolor.b / 255.0,
1560
(double) pls->curcolor.a );
1561
if ( arc_info->fill )
1563
cairo_fill( aStream->cairoContext );
1567
cairo_stroke( aStream->cairoContext );
1569
cairo_restore( aStream->cairoContext );
1572
//--------------------------------------------------------------------------
1573
// rotate_cairo_surface()
1575
// Rotates the cairo surface to the appropriate orientation.
1576
//--------------------------------------------------------------------------
1578
void rotate_cairo_surface( PLStream *pls, float x11, float x12, float x21, float x22, float x0, float y0, PLBOOL is_xcairo )
1580
cairo_matrix_t *matrix;
1583
aStream = (PLCairo *) pls->dev;
1585
matrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
1586
cairo_matrix_init( matrix, x11, x12, x21, x22, x0, y0 );
1587
#if defined ( PLD_xcairo )
1590
cairo_transform( aStream->cairoContext_X, matrix );
1594
cairo_transform( aStream->cairoContext, matrix );
1597
cairo_transform( aStream->cairoContext, matrix );
1602
//--------------------------------------------------------------------------
1603
//--------------------------------------------------------------------------
1605
// That which is common to all familying Cairo Drivers
1607
//--------------------------------------------------------------------------
1608
//--------------------------------------------------------------------------
1609
#if defined ( PLD_pngcairo ) || defined ( PLD_svgcairo )
1611
void plD_bop_famcairo( PLStream * );
1612
//--------------------------------------------------------------------------
1613
// plD_bop_famcairo()
1615
// Familying Devices: Set up for the next page.
1616
//--------------------------------------------------------------------------
1618
void plD_bop_famcairo( PLStream *pls )
1622
aStream = (PLCairo *) pls->dev;
1624
// Plot familying stuff. Not really understood, just copying gd.c
1629
// Fill in the window with the background color.
1630
cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
1631
cairo_set_source_rgba( aStream->cairoContext,
1632
(double) pls->cmap0[0].r / 255.0,
1633
(double) pls->cmap0[0].g / 255.0,
1634
(double) pls->cmap0[0].b / 255.0,
1635
(double) pls->cmap0[0].a );
1636
cairo_fill( aStream->cairoContext );
1640
//--------------------------------------------------------------------------
1641
//--------------------------------------------------------------------------
1643
// That which is specific to the xcairo driver.
1645
//--------------------------------------------------------------------------
1646
//--------------------------------------------------------------------------
1648
#if defined ( PLD_xcairo )
1651
static Window rootWindow;
1653
void plD_dispatch_init_xcairo( PLDispatchTable *pdt );
1654
void plD_init_xcairo( PLStream * );
1655
void plD_bop_xcairo( PLStream * );
1656
void plD_eop_xcairo( PLStream * );
1657
void plD_tidy_xcairo( PLStream * );
1658
void plD_esc_xcairo( PLStream *, PLINT, void * );
1659
static void xcairo_get_cursor( PLStream *, PLGraphicsIn * );
1661
//--------------------------------------------------------------------------
1662
// plD_dispatch_init_xcairo()
1664
// xcairo dispatch table initialization.
1665
//--------------------------------------------------------------------------
1667
void plD_dispatch_init_xcairo( PLDispatchTable *pdt )
1669
#ifndef ENABLE_DYNDRIVERS
1670
pdt->pl_MenuStr = "Cairo X Windows Driver";
1671
pdt->pl_DevName = "xcairo";
1673
pdt->pl_type = plDevType_Interactive;
1675
pdt->pl_init = (plD_init_fp) plD_init_xcairo;
1676
pdt->pl_line = (plD_line_fp) plD_line_cairo;
1677
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
1678
pdt->pl_eop = (plD_eop_fp) plD_eop_xcairo;
1679
pdt->pl_bop = (plD_bop_fp) plD_bop_xcairo;
1680
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_xcairo;
1681
pdt->pl_state = (plD_state_fp) plD_state_cairo;
1682
pdt->pl_esc = (plD_esc_fp) plD_esc_xcairo;
1685
//--------------------------------------------------------------------------
1686
// xcairo_init_cairo()
1688
// Configures Cairo to use whichever X Drawable is set up in the given
1689
// stream. This is called by plD_init_xcairo() in the event we are
1690
// drawing into a plplot-managed window, and plD_esc_xcairo() if
1691
// we are using an external X Drawable.
1693
// A return value of 0 indicates success. Currently this function only
1695
//--------------------------------------------------------------------------
1697
static signed int xcairo_init_cairo( PLStream *pls )
1700
Visual *defaultVisual;
1702
aStream = (PLCairo *) pls->dev;
1704
// Create an cairo surface & context that are associated with the X window.
1705
defaultVisual = DefaultVisual( aStream->XDisplay, 0 );
1706
// Dimension units are pixels from cairo documentation.
1707
// This is the X window Cairo surface.
1708
aStream->cairoSurface_X = cairo_xlib_surface_create( aStream->XDisplay, aStream->XWindow, defaultVisual, pls->xlength, pls->ylength );
1709
aStream->cairoContext_X = cairo_create( aStream->cairoSurface_X );
1710
// This is the Cairo surface PLplot will actually plot to.
1711
if ( aStream->image_buffering == 0 )
1713
aStream->cairoSurface = cairo_surface_create_similar( aStream->cairoSurface_X, CAIRO_CONTENT_COLOR_ALPHA, pls->xlength, pls->ylength );
1714
aStream->cairoContext = cairo_create( aStream->cairoSurface );
1718
// Plot to an off-screen image
1719
aStream->cairoSurface =
1720
cairo_image_surface_create( CAIRO_FORMAT_ARGB32,
1721
pls->xlength, pls->ylength );
1722
aStream->cairoContext = cairo_create( aStream->cairoSurface );
1725
// Invert the surface so that the graphs are drawn right side up.
1726
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, TRUE );
1728
// Set graphics aliasing
1729
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
1731
// Set fill rule for the case of self-intersecting boundaries.
1732
if ( pls->dev_eofill )
1733
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
1735
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
1737
// Fill in the X window with the background color to avoid starting out
1738
// with a blank window of an unexpected color.
1739
cairo_rectangle( aStream->cairoContext_X, 0.0, 0.0, pls->xlength, pls->ylength );
1740
cairo_set_source_rgba( aStream->cairoContext_X,
1741
(double) pls->cmap0[0].r / 255.0,
1742
(double) pls->cmap0[0].g / 255.0,
1743
(double) pls->cmap0[0].b / 255.0,
1744
(double) pls->cmap0[0].a );
1745
cairo_fill( aStream->cairoContext_X );
1747
XFlush( aStream->XDisplay );
1752
//--------------------------------------------------------------------------
1753
// plD_init_xcairo()
1755
// Initialize Cairo X Windows device.
1756
//--------------------------------------------------------------------------
1758
void plD_init_xcairo( PLStream *pls )
1763
// Setup the PLStream and the font lookup table.
1764
aStream = stream_and_font_setup( pls, 1 );
1766
// Save the pointer to the structure in the PLplot stream
1769
// Create a X Window if required.
1770
if ( external_drawable != 0 )
1772
aStream->xdrawable_mode = 1;
1777
aStream->XDisplay = NULL;
1778
aStream->XDisplay = XOpenDisplay( NULL );
1779
if ( aStream->XDisplay == NULL )
1781
printf( "Failed to open X Windows display\n" );
1782
// some sort of error here
1784
XScreen = DefaultScreen( aStream->XDisplay );
1785
rootWindow = RootWindow( aStream->XDisplay, XScreen );
1787
aStream->XWindow = XCreateSimpleWindow( aStream->XDisplay, rootWindow, 0, 0, pls->xlength, pls->ylength,
1788
1, BlackPixel( aStream->XDisplay, XScreen ), BlackPixel( aStream->XDisplay, XScreen ) );
1789
XStoreName( aStream->XDisplay, aStream->XWindow, pls->plwindow );
1790
XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
1791
XMapWindow( aStream->XDisplay, aStream->XWindow );
1792
aStream->xdrawable_mode = 0;
1794
wmDelete = XInternAtom( aStream->XDisplay, "WM_DELETE_WINDOW", True );
1795
XSetWMProtocols( aStream->XDisplay, aStream->XWindow, &wmDelete, 1 );
1797
xcairo_init_cairo( pls );
1800
aStream->exit_event_loop = 0;
1803
//--------------------------------------------------------------------------
1807
// Blit the offscreen image to the X window.
1808
//--------------------------------------------------------------------------
1810
void blit_to_x( PLStream *pls, double x, double y, double w, double h )
1816
cairo_save( aStream->cairoContext );
1817
// "Flatten" any transparent regions to look like they were drawn over the
1818
// correct background color
1819
cairo_rectangle( aStream->cairoContext, x, y, w, h );
1820
cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_DEST_OVER );
1821
cairo_set_source_rgba( aStream->cairoContext,
1822
(double) pls->cmap0[0].r / 255.0,
1823
(double) pls->cmap0[0].g / 255.0,
1824
(double) pls->cmap0[0].b / 255.0,
1825
(double) pls->cmap0[0].a );
1826
cairo_fill( aStream->cairoContext );
1827
cairo_restore( aStream->cairoContext );
1829
cairo_save( aStream->cairoContext_X );
1830
// Copy a portion of the surface
1831
cairo_rectangle( aStream->cairoContext_X, x, y, w, h );
1832
cairo_set_operator( aStream->cairoContext_X, CAIRO_OPERATOR_SOURCE );
1833
cairo_set_source_surface( aStream->cairoContext_X,
1834
aStream->cairoSurface, 0.0, 0.0 );
1835
cairo_fill( aStream->cairoContext_X );
1836
cairo_restore( aStream->cairoContext_X );
1839
//--------------------------------------------------------------------------
1842
// X Windows specific start of page.
1843
//--------------------------------------------------------------------------
1845
void plD_bop_xcairo( PLStream *pls )
1849
aStream = (PLCairo *) pls->dev;
1851
plD_bop_cairo( pls );
1853
if ( aStream->xdrawable_mode )
1856
XFlush( aStream->XDisplay );
1859
//--------------------------------------------------------------------------
1862
// X Windows specific end of page.
1863
//--------------------------------------------------------------------------
1865
void plD_eop_xcairo( PLStream *pls )
1869
char event_string[10];
1873
XExposeEvent *expose;
1875
char helpmsg[] = " - Press Enter or right-click to continue";
1878
aStream = (PLCairo *) pls->dev;
1880
// Blit the offscreen image to the X window.
1881
blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
1883
if ( aStream->xdrawable_mode )
1886
// Only pause if nopause is unset.
1888
aStream->exit_event_loop = 1;
1890
// Loop, handling selected events, till the user elects to close the plot.
1891
event_mask = ButtonPressMask | KeyPressMask | ExposureMask;
1892
XSelectInput( aStream->XDisplay, aStream->XWindow, event_mask );
1893
while ( !aStream->exit_event_loop )
1895
//XWindowEvent( aStream->XDisplay, aStream->XWindow, event_mask, &event );
1896
XNextEvent( aStream->XDisplay, &event );
1897
switch ( event.type )
1900
number_chars = XLookupString( (XKeyEvent *) &event, event_string, 10, &keysym, &cs );
1901
event_string[number_chars] = '\0';
1902
if ( keysym == XK_Return )
1904
aStream->exit_event_loop = 1;
1908
if ( ( (XButtonEvent *) &event )->button == Button3 )
1909
aStream->exit_event_loop = 1;
1912
// plexit("X Window closed");
1913
pls->stream_closed = TRUE;
1914
aStream->exit_event_loop = 1;
1917
// Blit the image again after an expose event, but only for the last
1918
// available event. Otherwise multiple redraws occur needlessly.
1919
expose = (XExposeEvent *) &event;
1920
if ( expose->count == 0 )
1922
blit_to_x( pls, expose->x, expose->y,
1923
expose->width, expose->height );
1928
aStream->exit_event_loop = 0;
1931
//--------------------------------------------------------------------------
1932
// plD_tidy_xcairo()
1934
// X Windows: close graphics file or otherwise clean up.
1935
//--------------------------------------------------------------------------
1937
void plD_tidy_xcairo( PLStream *pls )
1941
aStream = (PLCairo *) pls->dev;
1943
plD_tidy_cairo( pls );
1945
// Also free up the Cairo X surface and context
1946
cairo_destroy( aStream->cairoContext_X );
1947
cairo_surface_destroy( aStream->cairoSurface_X );
1949
if ( aStream->xdrawable_mode )
1952
// Close the window and the display.
1953
XFlush( aStream->XDisplay );
1955
XDestroyWindow( aStream->XDisplay, aStream->XWindow );
1957
XCloseDisplay( aStream->XDisplay );
1960
//--------------------------------------------------------------------------
1963
// Escape function, specialized for the xcairo driver
1964
//--------------------------------------------------------------------------
1966
void plD_esc_xcairo( PLStream *pls, PLINT op, void *ptr )
1970
aStream = (PLCairo *) pls->dev;
1974
case PLESC_FLUSH: // forced update of the window
1975
blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
1976
XFlush( aStream->XDisplay );
1978
case PLESC_GETC: // get cursor position
1979
blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
1980
XFlush( aStream->XDisplay );
1981
xcairo_get_cursor( pls, (PLGraphicsIn *) ptr );
1983
case PLESC_DEVINIT: { // Set external drawable
1985
PLXcairoDrawableInfo *xinfo = (PLXcairoDrawableInfo *) ptr;
1987
unsigned int w, h, b, d;
1988
if ( xinfo == NULL )
1990
printf( "xcairo: PLESC_DEVINIT ignored, no drawable info provided\n" );
1993
if ( aStream->xdrawable_mode == 0 )
1995
printf( "xcairo: PLESC_DEVINIT called with drawable but stream not in xdrawable mode\n" );
1998
aStream->XDisplay = xinfo->display;
1999
aStream->XWindow = xinfo->drawable;
2001
// Ensure plplot knows the real dimensions of the drawable
2002
XGetGeometry( aStream->XDisplay, aStream->XWindow, &rootwin,
2003
&x, &y, &w, &h, &b, &d );
2006
plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / aStream->downscale ), (PLINT) 0,
2007
(PLINT) ( pls->ylength / aStream->downscale ) );
2009
// Associate cairo with the supplied drawable
2010
xcairo_init_cairo( pls );
2012
// Recalculate dimensions and the like now that the drawable is known
2018
plD_esc_cairo( pls, op, ptr );
2023
//--------------------------------------------------------------------------
2024
// xcairo_get_cursor()
2026
// X Windows: returns the location of the next mouse click or key press.
2027
//--------------------------------------------------------------------------
2029
void xcairo_get_cursor( PLStream *pls, PLGraphicsIn *gin )
2037
XButtonEvent *xButtonEvent;
2041
aStream = (PLCairo *) pls->dev;
2043
// Initialize PLplot mouse event structure
2046
// Create cross hair cursor & switch to using it
2047
xHairCursor = XCreateFontCursor( aStream->XDisplay, XC_crosshair );
2048
XDefineCursor( aStream->XDisplay, aStream->XWindow, xHairCursor );
2050
// Get the next mouse button release or key press event
2051
XSelectInput( aStream->XDisplay, aStream->XWindow, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask );
2052
XMaskEvent( aStream->XDisplay, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask, &event );
2053
XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
2055
// Update PLplot's mouse event structure
2056
xButtonEvent = (XButtonEvent *) &event;
2057
gin->state = xButtonEvent->state;
2058
gin->button = xButtonEvent->button;
2059
gin->pX = event.xbutton.x;
2060
gin->pY = pls->ylength - event.xbutton.y;
2061
gin->dX = (PLFLT) event.xbutton.x / ( (PLFLT) ( pls->xlength ) );
2062
gin->dY = (PLFLT) ( pls->ylength - event.xbutton.y ) / ( (PLFLT) ( pls->ylength ) );
2064
// Get key pressed (if any)
2065
if ( event.type == KeyPress || event.type == KeyRelease )
2067
number_chars = XLookupString( (XKeyEvent *) &event, str, 100, &keysym, NULL );
2068
if ( keysym == NoSymbol )
2069
ksname = "NoSymbol";
2070
else if ( !( ksname = XKeysymToString( keysym ) ) )
2071
ksname = "(no name)";
2072
strcpy( gin->string, ksname );
2073
// gin->string[number_chars] = '\0';
2082
gin->keysym = 0xFF & keysym;
2085
gin->keysym = keysym;
2088
else // button press
2090
sprintf( gin->string, "button %u", gin->button );
2094
// Switch back to normal cursor
2095
XUndefineCursor( aStream->XDisplay, aStream->XWindow );
2096
XFlush( aStream->XDisplay );
2102
//--------------------------------------------------------------------------
2103
//--------------------------------------------------------------------------
2105
// That which is specific to the cairo PDF driver.
2107
//--------------------------------------------------------------------------
2108
//--------------------------------------------------------------------------
2110
#if defined ( PLD_pdfcairo )
2112
void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt );
2113
void plD_init_pdfcairo( PLStream * );
2115
//--------------------------------------------------------------------------
2116
// dispatch_init_init()
2118
// Initialize device dispatch table
2119
//--------------------------------------------------------------------------
2122
void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt )
2124
#ifndef ENABLE_DYNDRIVERS
2125
pdt->pl_MenuStr = "Cairo PDF Driver";
2126
pdt->pl_DevName = "pdfcairo";
2128
pdt->pl_type = plDevType_FileOriented;
2130
pdt->pl_init = (plD_init_fp) plD_init_pdfcairo;
2131
pdt->pl_line = (plD_line_fp) plD_line_cairo;
2132
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2133
pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2134
pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2135
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2136
pdt->pl_state = (plD_state_fp) plD_state_cairo;
2137
pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2140
//--------------------------------------------------------------------------
2141
// plD_init_pdfcairo()
2143
// Initialize Cairo PDF device
2144
//--------------------------------------------------------------------------
2146
void plD_init_pdfcairo( PLStream *pls )
2150
// Setup the PLStream and the font lookup table
2151
aStream = stream_and_font_setup( pls, 0 );
2153
// Prompt for a file name if not already set.
2156
// Create an cairo surface & context for PDF file.
2157
// Dimension units are pts = 1/72 inches from cairo documentation.
2158
aStream->cairoSurface = cairo_pdf_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
2159
aStream->cairoContext = cairo_create( aStream->cairoSurface );
2161
// Save the pointer to the structure in the PLplot stream
2164
// Invert the surface so that the graphs are drawn right side up.
2165
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
2167
// Set graphics aliasing
2168
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2170
// Set fill rule for the case of self-intersecting boundaries.
2171
if ( pls->dev_eofill )
2172
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2174
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2180
//--------------------------------------------------------------------------
2181
//--------------------------------------------------------------------------
2183
// That which is specific to the cairo PS driver.
2185
//--------------------------------------------------------------------------
2186
//--------------------------------------------------------------------------
2188
#if defined ( PLD_pscairo )
2190
void plD_dispatch_init_pscairo( PLDispatchTable *pdt );
2191
void plD_init_pscairo( PLStream * );
2193
//--------------------------------------------------------------------------
2194
// dispatch_init_init()
2196
// Initialize device dispatch table
2197
//--------------------------------------------------------------------------
2200
void plD_dispatch_init_pscairo( PLDispatchTable *pdt )
2202
#ifndef ENABLE_DYNDRIVERS
2203
pdt->pl_MenuStr = "Cairo PS Driver";
2204
pdt->pl_DevName = "pscairo";
2206
pdt->pl_type = plDevType_FileOriented;
2208
pdt->pl_init = (plD_init_fp) plD_init_pscairo;
2209
pdt->pl_line = (plD_line_fp) plD_line_cairo;
2210
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2211
pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2212
pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
2213
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2214
pdt->pl_state = (plD_state_fp) plD_state_cairo;
2215
pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2218
//--------------------------------------------------------------------------
2219
// plD_init_pscairo()
2221
// Initialize Cairo PS device
2222
//--------------------------------------------------------------------------
2224
void plD_init_pscairo( PLStream *pls )
2228
// Setup the PLStream and the font lookup table
2229
aStream = stream_and_font_setup( pls, 0 );
2231
// Prompt for a file name if not already set.
2234
// Create an cairo surface & context for PS file.
2235
// Dimension units are pts = 1/72 inches from cairo documentation.
2236
aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
2237
aStream->cairoContext = cairo_create( aStream->cairoSurface );
2239
// Save the pointer to the structure in the PLplot stream
2242
// Handle portrait or landscape
2243
if ( pls->portrait )
2246
pls->freeaspect = 1;
2248
rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, pls->ylength, pls->xlength, FALSE );
2250
// Set fill rule for the case of self-intersecting boundaries.
2251
if ( pls->dev_eofill )
2252
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2254
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2260
//--------------------------------------------------------------------------
2261
//--------------------------------------------------------------------------
2263
// That which is specific to the cairo SVG driver.
2265
//--------------------------------------------------------------------------
2266
//--------------------------------------------------------------------------
2268
#if defined ( PLD_svgcairo )
2270
void plD_dispatch_init_svgcairo( PLDispatchTable *pdt );
2271
void plD_init_svgcairo( PLStream * );
2273
//--------------------------------------------------------------------------
2274
// dispatch_init_init()
2276
// Initialize device dispatch table
2277
//--------------------------------------------------------------------------
2280
void plD_dispatch_init_svgcairo( PLDispatchTable *pdt )
2282
#ifndef ENABLE_DYNDRIVERS
2283
pdt->pl_MenuStr = "Cairo SVG Driver";
2284
pdt->pl_DevName = "svgcairo";
2286
pdt->pl_type = plDevType_FileOriented;
2288
pdt->pl_init = (plD_init_fp) plD_init_svgcairo;
2289
pdt->pl_line = (plD_line_fp) plD_line_cairo;
2290
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2291
pdt->pl_eop = (plD_eop_fp) plD_eop_cairo;
2292
pdt->pl_bop = (plD_bop_fp) plD_bop_famcairo;
2293
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2294
pdt->pl_state = (plD_state_fp) plD_state_cairo;
2295
pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2298
//--------------------------------------------------------------------------
2299
// plD_init_svgcairo()
2301
// Initialize Cairo SVG device
2302
//--------------------------------------------------------------------------
2304
void plD_init_svgcairo( PLStream *pls )
2308
// Setup the PLStream and the font lookup table and allocate a cairo
2309
// stream structure.
2311
// NOTE: The check below is necessary since, in family mode, this function
2312
// will be called multiple times. While you might think that it is
2313
// sufficient to update what *should* be the only pointer to the contents
2314
// of pls->dev, i.e. the pointer pls->dev itself, it appears that
2315
// something else somewhere else is also pointing to pls->dev. If you
2316
// change what pls->dev points to then you will get a "bus error", from
2317
// which I infer the existence of said bad stale pointer.
2319
if ( pls->dev == NULL )
2321
aStream = stream_and_font_setup( pls, 0 );
2325
stream_and_font_setup( pls, 0 );
2329
// Initialize family file info
2332
// Prompt for a file name if not already set.
2335
// Save the pointer to the structure in the PLplot stream
2338
// Create an cairo surface & context for SVG file.
2339
// Dimension units are pts = 1/72 inches from cairo documentation.
2340
aStream->cairoSurface = cairo_svg_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
2341
aStream->cairoContext = cairo_create( aStream->cairoSurface );
2343
// Invert the surface so that the graphs are drawn right side up.
2344
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
2346
// Set graphics aliasing
2347
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2349
// Set fill rule for the case of self-intersecting boundaries.
2350
if ( pls->dev_eofill )
2351
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2353
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2359
//--------------------------------------------------------------------------
2360
//--------------------------------------------------------------------------
2362
// That which is specific to the cairo PNG driver.
2364
//--------------------------------------------------------------------------
2365
//--------------------------------------------------------------------------
2367
#if defined ( PLD_pngcairo )
2369
void plD_dispatch_init_pngcairo( PLDispatchTable *pdt );
2370
void plD_init_pngcairo( PLStream * );
2371
void plD_eop_pngcairo( PLStream * );
2373
//--------------------------------------------------------------------------
2374
// dispatch_init_init()
2376
// Initialize device dispatch table
2377
//--------------------------------------------------------------------------
2380
void plD_dispatch_init_pngcairo( PLDispatchTable *pdt )
2382
#ifndef ENABLE_DYNDRIVERS
2383
pdt->pl_MenuStr = "Cairo PNG Driver";
2384
pdt->pl_DevName = "pngcairo";
2386
pdt->pl_type = plDevType_FileOriented;
2388
pdt->pl_init = (plD_init_fp) plD_init_pngcairo;
2389
pdt->pl_line = (plD_line_fp) plD_line_cairo;
2390
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2391
pdt->pl_eop = (plD_eop_fp) plD_eop_pngcairo;
2392
pdt->pl_bop = (plD_bop_fp) plD_bop_famcairo;
2393
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2394
pdt->pl_state = (plD_state_fp) plD_state_cairo;
2395
pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2398
//--------------------------------------------------------------------------
2399
// plD_init_pngcairo()
2401
// Initialize Cairo PNG device
2402
//--------------------------------------------------------------------------
2404
void plD_init_pngcairo( PLStream *pls )
2408
// Setup the PLStream and the font lookup table and allocate a cairo
2409
// stream structure.
2411
// NOTE: The check below is necessary since, in family mode, this function
2412
// will be called multiple times. While you might think that it is
2413
// sufficient to update what *should* be the only pointer to the contents
2414
// of pls->dev, i.e. the pointer pls->dev itself, it appears that
2415
// something else somewhere else is also pointing to pls->dev. If you
2416
// change what pls->dev points to then you will get a "bus error", from
2417
// which I infer the existence of said bad stale pointer.
2419
if ( pls->dev == NULL )
2421
aStream = stream_and_font_setup( pls, 0 );
2425
stream_and_font_setup( pls, 0 );
2429
// Initialize family file info
2432
// Prompt for a file name if not already set.
2435
// Save the pointer to the structure in the PLplot stream
2438
// Create a new cairo surface & context for PNG file.
2439
// Dimension units are pixels from cairo documentation.
2440
aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (double) pls->xlength, (double) pls->ylength );
2441
aStream->cairoContext = cairo_create( aStream->cairoSurface );
2443
// Invert the surface so that the graphs are drawn right side up.
2444
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
2446
// Set graphics aliasing
2447
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2449
// Set fill rule for the case of self-intersecting boundaries.
2450
if ( pls->dev_eofill )
2451
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2453
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2456
//--------------------------------------------------------------------------
2457
// plD_eop_pngcairo()
2459
// PNG: End of page.
2460
//--------------------------------------------------------------------------
2462
void plD_eop_pngcairo( PLStream *pls )
2466
aStream = (PLCairo *) pls->dev;
2467
cairo_surface_write_to_png_stream( aStream->cairoSurface, (cairo_write_func_t) write_to_stream, pls->OutFile );
2473
//--------------------------------------------------------------------------
2474
//--------------------------------------------------------------------------
2476
// That which is specific to the cairo memory driver.
2478
//--------------------------------------------------------------------------
2479
//--------------------------------------------------------------------------
2481
#if defined ( PLD_memcairo )
2483
void plD_dispatch_init_memcairo( PLDispatchTable *pdt );
2484
void plD_init_memcairo( PLStream * );
2485
void plD_eop_memcairo( PLStream * );
2486
void plD_bop_memcairo( PLStream * );
2488
//--------------------------------------------------------------------------
2489
// dispatch_init_init()
2491
// Initialize device dispatch table
2492
//--------------------------------------------------------------------------
2495
void plD_dispatch_init_memcairo( PLDispatchTable *pdt )
2497
#ifndef ENABLE_DYNDRIVERS
2498
pdt->pl_MenuStr = "Cairo memory driver";
2499
pdt->pl_DevName = "memcairo";
2501
pdt->pl_type = plDevType_FileOriented;
2503
pdt->pl_init = (plD_init_fp) plD_init_memcairo;
2504
pdt->pl_line = (plD_line_fp) plD_line_cairo;
2505
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2506
pdt->pl_eop = (plD_eop_fp) plD_eop_memcairo;
2507
pdt->pl_bop = (plD_bop_fp) plD_bop_memcairo;
2508
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_cairo;
2509
pdt->pl_state = (plD_state_fp) plD_state_cairo;
2510
pdt->pl_esc = (plD_esc_fp) plD_esc_cairo;
2513
//--------------------------------------------------------------------------
2514
// plD_bop_memcairo()
2516
// Set up for the next page.
2517
//--------------------------------------------------------------------------
2519
void plD_bop_memcairo( PLStream *pls )
2521
// nothing to do here (we want to preserve the memory as it is)
2524
//--------------------------------------------------------------------------
2525
// plD_init_memcairo()
2527
// Initialize Cairo memory device
2528
//--------------------------------------------------------------------------
2530
void plD_init_memcairo( PLStream *pls )
2534
unsigned char *cairo_mem;
2535
unsigned char *input_mem;
2537
// used for checking byte order
2541
char testByte[sizeof ( int )];
2543
endianTest.testWord = 1;
2545
// Set the plot size to the memory buffer size, on the off chance
2546
// that they are different.
2547
pls->xlength = pls->phyxma;
2548
pls->ylength = pls->phyyma;
2551
// Setup the PLStream and the font lookup table
2552
aStream = stream_and_font_setup( pls, 0 );
2555
if ( endianTest.testByte[0] == 1 )
2556
aStream->bigendian = 0;
2558
aStream->bigendian = 1;
2560
// Check that user supplied us with some memory to draw in
2561
if ( pls->dev == NULL )
2563
plexit( "Must call plsmem first to set user plotting area!" );
2566
// Save a pointer to the memory.
2567
aStream->memory = pls->dev;
2569
// Create a cairo surface & context. Copy data in from the input memory area
2571
// Malloc memory the way cairo likes it. Aligned on the stride computed by cairo_format_stride_for_width
2572
// and in the RGB24 format (from http://cairographics.org/manual/cairo-Image-Surfaces.html):
2573
// Each pixel is a 32-bit quantity, with the upper 8 bits unused.
2574
// Red, Green, and Blue are stored in the remaining 24 bits in that order
2575
stride = pls->xlength * 4;
2576
// stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pls->xlength); This function missing from version 1.4 :-(
2577
aStream->cairo_format_memory = (unsigned char *) calloc( stride * pls->ylength, 1 );
2579
// Copy the input data into the Cairo data format
2580
cairo_mem = aStream->cairo_format_memory;
2581
input_mem = aStream->memory;
2583
// 32 bit word order
2584
// cairo mem: Big endian: 0=A, 1=R, 2=G, 3=B
2585
// Little endian: 3=A, 2=R, 1=G, 0=B
2587
if ( aStream->bigendian )
2589
for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2591
cairo_mem[1] = input_mem[0]; // R
2592
cairo_mem[2] = input_mem[1]; // G
2593
cairo_mem[3] = input_mem[2]; // B
2594
if ( pls->dev_mem_alpha == 1 )
2596
cairo_mem[0] = input_mem[3];
2608
for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2610
cairo_mem[2] = input_mem[0]; // R
2611
cairo_mem[1] = input_mem[1]; // G
2612
cairo_mem[0] = input_mem[2]; // B
2613
if ( pls->dev_mem_alpha == 1 )
2615
cairo_mem[3] = input_mem[3];
2626
// Create a Cairo drawing surface from the input data
2627
aStream->cairoSurface =
2628
// Dimension units are width, height of buffer image from cairo
2630
cairo_image_surface_create_for_data( aStream->cairo_format_memory, CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength, stride );
2631
aStream->cairoContext = cairo_create( aStream->cairoSurface );
2633
// Save the pointer to the structure in the PLplot stream.
2634
// Note that this wipes out the direct pointer to the memory buffer.
2637
// Invert the surface so that the graphs are drawn right side up.
2638
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
2640
// Set graphics aliasing
2641
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2643
// Set fill rule for the case of self-intersecting boundaries.
2644
if ( pls->dev_eofill )
2645
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2647
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2650
//--------------------------------------------------------------------------
2651
// plD_eop_memcairo()
2653
// Memory device specific end of page. This copies the contents
2654
// of the cairo surface into the user supplied memory buffer.
2655
//--------------------------------------------------------------------------
2657
void plD_eop_memcairo( PLStream *pls )
2660
unsigned char *memory;
2661
unsigned char *cairo_surface_data;
2664
aStream = (PLCairo *) pls->dev;
2665
memory = aStream->memory;
2666
cairo_surface_data = cairo_image_surface_get_data( aStream->cairoSurface );
2667
// 32 bit word order
2668
// cairo mem: Big endian: 0=A, 1=R, 2=G, 3=B
2669
// Little endian: 3=A, 2=R, 1=G, 0=B
2670
if ( aStream->bigendian )
2672
for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2674
memory[0] = cairo_surface_data[1]; // R
2675
memory[1] = cairo_surface_data[2]; // G
2676
memory[2] = cairo_surface_data[3]; // B
2677
if ( pls->dev_mem_alpha == 1 )
2679
memory[3] = cairo_surface_data[0];
2686
cairo_surface_data += 4;
2691
for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
2693
memory[0] = cairo_surface_data[2]; // R
2694
memory[1] = cairo_surface_data[1]; // G
2695
memory[2] = cairo_surface_data[0]; // B
2696
if ( pls->dev_mem_alpha == 1 )
2698
memory[3] = cairo_surface_data[3];
2705
cairo_surface_data += 4;
2709
// Free up the temporary memory malloc'ed in plD_init_memcairo
2710
free( aStream->cairo_format_memory );
2715
//--------------------------------------------------------------------------
2716
//--------------------------------------------------------------------------
2718
// That which is specific to the cairo external context driver.
2720
//--------------------------------------------------------------------------
2721
//--------------------------------------------------------------------------
2723
#if defined ( PLD_extcairo )
2725
void extcairo_setbackground( PLStream * );
2726
void plD_dispatch_init_extcairo( PLDispatchTable *pdt );
2727
void plD_init_extcairo( PLStream * );
2728
void plD_bop_extcairo( PLStream * );
2729
void plD_eop_extcairo( PLStream * );
2730
void plD_esc_extcairo( PLStream *, PLINT, void * );
2731
void plD_tidy_extcairo( PLStream * );
2733
//--------------------------------------------------------------------------
2734
// extcairo_setbackground()
2736
// Set the background color for the extcairo device
2737
//--------------------------------------------------------------------------
2739
void extcairo_setbackground( PLStream *pls )
2743
aStream = (PLCairo *) pls->dev;
2745
// Fill the context with the background color if the user so desires.
2746
if ( aStream->cairoContext != NULL )
2748
cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
2749
cairo_set_source_rgba( aStream->cairoContext,
2750
(double) pls->cmap0[0].r / 255.0,
2751
(double) pls->cmap0[0].g / 255.0,
2752
(double) pls->cmap0[0].b / 255.0,
2753
(double) pls->cmap0[0].a );
2754
cairo_fill( aStream->cairoContext );
2758
//--------------------------------------------------------------------------
2759
// dispatch_init_init()
2761
// Initialize device dispatch table
2762
//--------------------------------------------------------------------------
2765
void plD_dispatch_init_extcairo( PLDispatchTable *pdt )
2767
#ifndef ENABLE_DYNDRIVERS
2768
pdt->pl_MenuStr = "Cairo external context driver";
2769
pdt->pl_DevName = "extcairo";
2771
pdt->pl_type = plDevType_Interactive;
2773
pdt->pl_init = (plD_init_fp) plD_init_extcairo;
2774
pdt->pl_line = (plD_line_fp) plD_line_cairo;
2775
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
2776
pdt->pl_bop = (plD_bop_fp) plD_bop_extcairo;
2777
pdt->pl_eop = (plD_eop_fp) plD_eop_extcairo;
2778
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_extcairo;
2779
pdt->pl_state = (plD_state_fp) plD_state_cairo;
2780
pdt->pl_esc = (plD_esc_fp) plD_esc_extcairo;
2783
//--------------------------------------------------------------------------
2784
// plD_init_extcairo()
2786
// Initialize Cairo external context driver.
2787
//--------------------------------------------------------------------------
2789
void plD_init_extcairo( PLStream *pls )
2793
// Setup the PLStream and the font lookup table
2794
aStream = stream_and_font_setup( pls, 0 );
2796
// Save the pointer to the structure in the PLplot stream
2800
//--------------------------------------------------------------------------
2801
// plD_bop_extcairo()
2803
// Set up for the next page.
2804
//--------------------------------------------------------------------------
2806
void plD_bop_extcairo( PLStream *pls )
2810
aStream = (PLCairo *) pls->dev;
2812
// Set background if desired
2813
if ( aStream->set_background )
2815
extcairo_setbackground( pls );
2819
//--------------------------------------------------------------------------
2820
// plD_eop_extcairo()
2823
//--------------------------------------------------------------------------
2825
void plD_eop_extcairo( PLStream *pls )
2827
// nothing to do here, we leave it to the calling program to display
2828
// (or not) the update cairo context.
2831
//--------------------------------------------------------------------------
2832
// plD_esc_extcairo()
2834
// The generic escape function, extended so that user can pass in
2835
// an external Cairo context to use for rendering.
2836
//--------------------------------------------------------------------------
2838
void plD_esc_extcairo( PLStream *pls, PLINT op, void *ptr )
2842
aStream = (PLCairo *) pls->dev;
2846
case PLESC_DEVINIT: // Set external context
2847
aStream->cairoContext = (cairo_t *) ptr;
2848
// Set graphics aliasing
2849
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
2851
// Invert the surface so that the graphs are drawn right side up.
2852
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
2854
// Should adjust plot size to fit in the given cairo context?
2855
// Cairo does not provide a way to query the dimensions of a context?
2857
// Set background if desired
2858
if ( aStream->set_background )
2860
extcairo_setbackground( pls );
2863
// Set fill rule for the case of self-intersecting boundaries.
2864
if ( pls->dev_eofill )
2865
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
2867
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
2869
default: // Fall back on default Cairo actions
2870
plD_esc_cairo( pls, op, ptr );
2875
//--------------------------------------------------------------------------
2876
// plD_tidy_extcairo()
2878
// This is nop, it is up to the calling program to clean up the Cairo
2880
//--------------------------------------------------------------------------
2882
void plD_tidy_extcairo( PLStream *pls )
2889
//--------------------------------------------------------------------------
2890
//--------------------------------------------------------------------------
2892
// That which is specific to the cairo microsoft windows driver.
2894
// Much of the Windows specific code here was lifted from the wingcc
2897
//--------------------------------------------------------------------------
2898
//--------------------------------------------------------------------------
2900
#if defined ( PLD_wincairo )
2902
static char* szWndClass = "PLplot WinCairo";
2904
void plD_dispatch_init_wincairo( PLDispatchTable *pdt );
2905
void plD_init_wincairo( PLStream * );
2906
//void plD_bop_extcairo( PLStream * );
2907
void plD_eop_wincairo( PLStream * );
2908
void plD_esc_wincairo( PLStream *, PLINT, void * );
2909
void plD_tidy_wincairo( PLStream * );
2911
//--------------------------------------------------------------------------
2914
// Blit the offscreen image to the Windows window.
2915
//--------------------------------------------------------------------------
2917
void blit_to_win( PLCairo *aStream )
2919
cairo_set_source_surface( aStream->cairoContext_win, aStream->cairoSurface, 0.0, 0.0 );
2920
cairo_paint( aStream->cairoContext_win );
2923
//--------------------------------------------------------------------------
2924
// This is the window function for the plot window. Whenever a message is
2925
// dispatched using DispatchMessage (or sent with SendMessage) this function
2926
// gets called with the contents of the message.
2927
//--------------------------------------------------------------------------
2929
LRESULT CALLBACK PlplotCairoWndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
2931
PLStream *pls = NULL;
2932
PLCairo *dev = NULL;
2935
// The window carries a 32bit user defined pointer which points to the
2936
// plplot stream (pls). This is used for tracking the window.
2937
// Unfortunately, this is "attached" to the window AFTER it is created
2938
// so we can not initialise PLStream or wincairo "blindly" because
2939
// they may not yet have been initialised.
2940
// WM_CREATE is called before we get to initialise those variables, so
2941
// we wont try to set them.
2944
if ( nMsg == WM_CREATE )
2950
pls = (PLStream *) GetWindowLong( hwnd, GWL_USERDATA ); // Try to get the address to pls for this window
2951
if ( pls ) // If we got it, then we will initialise this windows plplot private data area
2953
dev = (PLCairo *) pls->dev;
2958
// Process the windows messages
2960
// Everything except WM_CREATE is done here and it is generally hoped that
2961
// pls and dev are defined already by this stage.
2962
// That will be true MOST of the time. Some times WM_PAINT will be called
2963
// before we get to initialise the user data area of the window with the
2964
// pointer to the windows plplot stream
2971
// Debug( "WM_DESTROY\t" );
2972
PostQuitMessage( 0 );
2982
GetClientRect( dev->hwnd, &dev->rect );
2986
case WM_ENTERSIZEMOVE:
2990
case WM_EXITSIZEMOVE:
2997
dev->oldcolour = SetBkColor( dev->hdc, RGB( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b ) );
2998
ExtTextOut( dev->hdc, 0, 0, ETO_OPAQUE, &dev->rect, "", 0, 0 );
2999
SetBkColor( dev->hdc, dev->oldcolour );
3009
// If we don't handle a message completely we hand it to the system
3010
// provided default window function.
3011
return DefWindowProc( hwnd, nMsg, wParam, lParam );
3014
//--------------------------------------------------------------------------
3017
// Handle getting the cursor location.
3018
//--------------------------------------------------------------------------
3021
handle_locate( PLStream *pls, PLGraphicsIn *gin )
3024
PLCairo *aStream = (PLCairo *) pls->dev;
3026
// Initialize PLplot mouse event structure
3029
while ( GetMessage( &aStream->msg, NULL, 0, 0 ) && !located )
3031
TranslateMessage( &aStream->msg );
3033
switch ( (int) aStream->msg.message )
3036
case WM_LBUTTONDOWN:
3039
gin->pX = LOWORD( aStream->msg.lParam );
3040
gin->pY = pls->ylength - HIWORD( aStream->msg.lParam );
3041
gin->dX = (PLFLT) LOWORD( aStream->msg.lParam ) / ( (PLFLT) pls->xlength );
3042
gin->dY = (PLFLT) ( pls->ylength - HIWORD( aStream->msg.lParam ) ) / ( (PLFLT) pls->ylength );
3045
gin->keysym = aStream->msg.wParam;
3050
DispatchMessage( &aStream->msg );
3056
//--------------------------------------------------------------------------
3057
// dispatch_init_init()
3059
// Initialize device dispatch table
3060
//--------------------------------------------------------------------------
3063
void plD_dispatch_init_wincairo( PLDispatchTable *pdt )
3065
#ifndef ENABLE_DYNDRIVERS
3066
pdt->pl_MenuStr = "Cairo Microsoft Windows driver";
3067
pdt->pl_DevName = "wincairo";
3069
pdt->pl_type = plDevType_Interactive;
3071
pdt->pl_init = (plD_init_fp) plD_init_wincairo;
3072
pdt->pl_line = (plD_line_fp) plD_line_cairo;
3073
pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
3074
pdt->pl_bop = (plD_bop_fp) plD_bop_cairo;
3075
pdt->pl_eop = (plD_eop_fp) plD_eop_wincairo;
3076
pdt->pl_tidy = (plD_tidy_fp) plD_tidy_wincairo;
3077
pdt->pl_state = (plD_state_fp) plD_state_cairo;
3078
pdt->pl_esc = (plD_esc_fp) plD_esc_wincairo;
3081
//--------------------------------------------------------------------------
3082
// plD_init_wincairo()
3084
// Initialize Cairo Microsoft Windows driver.
3085
//--------------------------------------------------------------------------
3087
void plD_init_wincairo( PLStream *pls )
3091
// Setup the PLStream and the font lookup table
3092
aStream = stream_and_font_setup( pls, 1 );
3094
// Save the pointer to the structure in the PLplot stream
3098
memset( &aStream->wndclass, 0, sizeof ( WNDCLASSEX ) );
3100
// This class is called WinTestWin
3101
aStream->wndclass.lpszClassName = szWndClass;
3103
// cbSize gives the size of the structure for extensibility.
3104
aStream->wndclass.cbSize = sizeof ( WNDCLASSEX );
3106
// All windows of this class redraw when resized.
3107
aStream->wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC | CS_PARENTDC;
3109
// All windows of this class use the PlplotCairoWndProc window function.
3110
aStream->wndclass.lpfnWndProc = PlplotCairoWndProc;
3112
// This class is used with the current program instance.
3114
aStream->wndclass.hInstance = GetModuleHandle( NULL );
3116
// Use standard application icon and arrow cursor provided by the OS
3117
aStream->wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
3118
aStream->wndclass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
3119
aStream->wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
3120
// Color the background white
3121
aStream->wndclass.hbrBackground = NULL;
3123
aStream->wndclass.cbWndExtra = sizeof ( pls );
3127
// Now register the window class for use.
3130
RegisterClassEx( &aStream->wndclass );
3133
// Create our main window using that window class.
3135
aStream->hwnd = CreateWindowEx( WS_EX_WINDOWEDGE + WS_EX_LEFT,
3136
szWndClass, // Class name
3137
pls->program, // Caption
3138
WS_OVERLAPPEDWINDOW, // Style
3139
pls->xoffset, // Initial x (use default)
3140
pls->yoffset, // Initial y (use default)
3141
// This is a little lame since the window border size might change.
3142
pls->xlength + 5, // Initial x size (use default)
3143
pls->ylength + 30, // Initial y size (use default)
3144
NULL, // No parent window
3146
aStream->wndclass.hInstance, // This program instance
3147
NULL // Creation parameters
3152
// Attach a pointer to the stream to the window's user area
3153
// this pointer will be used by the windows call back for
3154
// process this window
3157
SetWindowLong( aStream->hwnd, GWL_USERDATA, (long) pls );
3158
aStream->SCRN_hdc = aStream->hdc = GetDC( aStream->hwnd );
3161
// Setup the popup menu
3165
// dev->PopupMenu = CreatePopupMenu();
3166
// AppendMenu( dev->PopupMenu, MF_STRING, PopupPrint, "Print" );
3167
// AppendMenu( dev->PopupMenu, MF_STRING, PopupNextPage, "Next Page" );
3168
// AppendMenu( dev->PopupMenu, MF_STRING, PopupQuit, "Quit" );
3171
// plD_state_wingcc( pls, PLSTATE_COLOR0 );
3173
// Display the window which we just created (using the nShow
3174
// passed by the OS, which allows for start minimized and that
3177
ShowWindow( aStream->hwnd, SW_SHOWDEFAULT );
3178
SetForegroundWindow( aStream->hwnd );
3181
// Now we have to find out, from windows, just how big our drawing area is
3182
// when we specified the page size earlier on, that includes the borders,
3183
// title bar etc... so now that windows has done all its initialisations,
3184
// we will ask how big the drawing area is, and tell plplot
3188
// GetClientRect( dev->hwnd, &dev->rect );
3189
// dev->width = dev->rect.right;
3190
// dev->height = dev->rect.bottom;
3194
// Initialize Cairo Surface using the windows hdc.
3197
// This is the Win32 Cairo surface.
3198
aStream->cairoSurface_win = (cairo_surface_t *) cairo_win32_surface_create( aStream->hdc );
3199
aStream->cairoContext_win = cairo_create( aStream->cairoSurface_win );
3201
// This is the Cairo surface PLplot will actually plot to.
3202
aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength );
3203
aStream->cairoContext = cairo_create( aStream->cairoSurface );
3205
// Invert the surface so that the graphs are drawn right side up.
3206
rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
3208
// Set graphics aliasing
3209
cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
3211
// Set fill rule for the case of self-intersecting boundaries.
3212
if ( pls->dev_eofill )
3213
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
3215
cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
3218
//--------------------------------------------------------------------------
3219
// plD_eop_wincairo()
3221
// Clean up Cairo Microsoft Windows driver.
3222
//--------------------------------------------------------------------------
3225
plD_eop_wincairo( PLStream *pls )
3227
PLCairo *aStream = (PLCairo *) pls->dev;
3229
if ( !pls->nopause )
3231
while ( GetMessage( &aStream->msg, NULL, 0, 0 ) )
3233
TranslateMessage( &aStream->msg );
3234
switch ( (int) aStream->msg.message )
3237
if ( ( (TCHAR) ( aStream->msg.wParam ) == 13 ) ||
3238
( (TCHAR) ( aStream->msg.wParam ) == 'q' ) ||
3239
( (TCHAR) ( aStream->msg.wParam ) == 'Q' ) )
3241
PostQuitMessage( 0 );
3246
DispatchMessage( &aStream->msg );
3253
//--------------------------------------------------------------------------
3254
// plD_tidy_wincairo()
3256
// Clean up Cairo Microsoft Windows driver.
3257
//--------------------------------------------------------------------------
3259
void plD_tidy_wincairo( PLStream *pls )
3261
PLCairo *aStream = (PLCairo *) pls->dev;
3263
plD_tidy_cairo( pls );
3265
// Also free up the Cairo win32 surface and context
3266
cairo_destroy( aStream->cairoContext_win );
3267
cairo_surface_destroy( aStream->cairoSurface_win );
3269
if ( aStream != NULL )
3271
if ( aStream->hdc != NULL )
3272
ReleaseDC( aStream->hwnd, aStream->hdc );
3273
free_mem( pls->dev );
3277
//--------------------------------------------------------------------------
3278
// plD_esc_wincairo()
3280
// Escape function, specialized for the wincairo driver
3281
//--------------------------------------------------------------------------
3283
void plD_esc_wincairo( PLStream *pls, PLINT op, void *ptr )
3287
aStream = (PLCairo *) pls->dev;
3292
InvalidateRect( aStream->hwnd, NULL, TRUE );
3295
handle_locate( pls, (PLGraphicsIn *) ptr );
3298
plD_esc_cairo( pls, op, ptr );