~uhh-ssd/+junk/humidity_readout

« back to all changes in this revision

Viewing changes to plplot/plplot-5.9.9/drivers/cairo.c

  • Committer: Joachim Erfle
  • Date: 2013-07-24 13:53:41 UTC
  • Revision ID: joachim.erfle@desy.de-20130724135341-1qojpp701zsn009p
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// June 2, 2007
 
2
//
 
3
// Graphics drivers that are based on the Cairo / Pango Libraries.
 
4
//
 
5
// Copyright (C) 2008 Hazen Babcock
 
6
// Copyright (C) 2009, 2010 Hezekiah M. Carty
 
7
//
 
8
// This file is part of PLplot.
 
9
//
 
10
// PLplot is free software; you can redistribute it and/or modify
 
11
// it under the terms of the GNU Library General Public License as published
 
12
// by the Free Software Foundation; either version 2 of the License, or
 
13
// (at your option) any later version.
 
14
//
 
15
// PLplot is distributed in the hope that it will be useful,
 
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
// GNU Library General Public License for more details.
 
19
//
 
20
// You should have received a copy of the GNU Library General Public License
 
21
// along with PLplot; if not, write to the Free Software
 
22
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
23
//
 
24
//
 
25
 
 
26
//--------------------------------------------------------------------------
 
27
// Header files
 
28
//--------------------------------------------------------------------------
 
29
 
 
30
#include <stdio.h>
 
31
#include <string.h>
 
32
#include <math.h>
 
33
 
 
34
#include <cairo.h>
 
35
#include <pango/pangocairo.h>
 
36
 
 
37
// PLplot header files (must occur before driver-dependent includes)
 
38
 
 
39
#include "plDevs.h"
 
40
#include "plplotP.h"
 
41
#include "drivers.h"
 
42
 
 
43
// Driver-dependent includes
 
44
#if defined ( PLD_xcairo )
 
45
#include <cairo-xlib.h>
 
46
#include <X11/X.h>
 
47
#include <X11/Xlib.h>
 
48
#include <X11/Xutil.h>
 
49
#include <X11/cursorfont.h>
 
50
#include <X11/keysym.h>
 
51
#endif
 
52
#if defined ( PLD_pdfcairo )
 
53
#include <cairo-pdf.h>
 
54
#endif
 
55
#if defined ( PLD_pscairo )
 
56
#include <cairo-ps.h>
 
57
#endif
 
58
#if defined ( PLD_svgcairo )
 
59
#include <cairo-svg.h>
 
60
#endif
 
61
#if defined ( PLD_wincairo )
 
62
#include <windows.h>
 
63
#endif
 
64
 
 
65
//--------------------------------------------------------------------------
 
66
// Constants & global (to this file) variables
 
67
//--------------------------------------------------------------------------
 
68
 
 
69
#define DPI                  72
 
70
#define PLCAIRO_DEFAULT_X    720
 
71
#define PLCAIRO_DEFAULT_Y    540
 
72
 
 
73
#define MAX_STRING_LEN       500
 
74
#define MAX_MARKUP_LEN       MAX_STRING_LEN * 10
 
75
 
 
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;
 
83
 
 
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                                                                                                                                                                                                                             } };
 
92
 
 
93
typedef struct
 
94
{
 
95
    cairo_surface_t *cairoSurface;
 
96
    cairo_t         *cairoContext;
 
97
    cairo_surface_t *cairoSurface_raster;
 
98
    cairo_t         *cairoContext_raster;
 
99
    short           text_clipping;
 
100
    short           text_anti_aliasing;
 
101
    short           graphics_anti_aliasing;
 
102
    short           rasterize_image;
 
103
    short           set_background;
 
104
    short           image_buffering;
 
105
    double          downscale;
 
106
    char            *pangoMarkupString;
 
107
    short           upDown;
 
108
    float           fontSize;
 
109
 
 
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
 
115
    // from upDown.
 
116
    PLFLT           old_sscale, sscale, old_soffset, soffset;
 
117
    PLINT           level;
 
118
 
 
119
#if defined ( PLD_xcairo )
 
120
    cairo_surface_t *cairoSurface_X;
 
121
    cairo_t         *cairoContext_X;
 
122
    short           exit_event_loop;
 
123
    Display         *XDisplay;
 
124
    Window          XWindow;
 
125
    unsigned int    xdrawable_mode;
 
126
#endif
 
127
#if defined ( PLD_memcairo )
 
128
    unsigned char   *memory;
 
129
    unsigned char   *cairo_format_memory;
 
130
    char            bigendian;
 
131
#endif
 
132
#if defined ( PLD_wincairo )
 
133
    cairo_surface_t *cairoSurface_win;
 
134
    cairo_t         *cairoContext_win;
 
135
    WNDCLASSEX      wndclass;
 
136
    HWND            hwnd;
 
137
    MSG             msg;
 
138
    HDC             hdc;
 
139
    HDC             SCRN_hdc;
 
140
    COLORREF        oldcolour;
 
141
    RECT            rect;
 
142
#endif
 
143
} PLCairo;
 
144
 
 
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"
 
148
#endif
 
149
#if defined ( PLD_pdfcairo )
 
150
    "pdfcairo:Cairo PDF Driver:0:cairo:101:pdfcairo\n"
 
151
#endif
 
152
#if defined ( PLD_pscairo )
 
153
    "pscairo:Cairo PS Driver:0:cairo:102:pscairo\n"
 
154
#endif
 
155
#if defined ( PLD_svgcairo )
 
156
    "svgcairo:Cairo SVG Driver:0:cairo:103:svgcairo\n"
 
157
#endif
 
158
#if defined ( PLD_pngcairo )
 
159
    "pngcairo:Cairo PNG Driver:0:cairo:104:pngcairo\n"
 
160
#endif
 
161
#if defined ( PLD_memcairo )
 
162
    "memcairo:Cairo Memory Driver:0:cairo:105:memcairo\n"
 
163
#endif
 
164
#if defined ( PLD_extcairo )
 
165
    "extcairo:Cairo External Context Driver:0:cairo:106:extcairo\n"
 
166
#endif
 
167
#if defined ( PLD_wincairo )
 
168
    "wincairo:Cairo Microscoft Windows Driver:0:cairo:107:wincairo\n"
 
169
#endif
 
170
;
 
171
 
 
172
//
 
173
// Structure for passing external drawables to xcairo devices via
 
174
// the PLESC_DEVINIT escape function.
 
175
//
 
176
#if defined ( PLD_xcairo )
 
177
typedef struct
 
178
{
 
179
    Display  *display;
 
180
    Drawable drawable;
 
181
} PLXcairoDrawableInfo;
 
182
#endif
 
183
 
 
184
//--------------------------------------------------------------------------
 
185
// Font style and weight lookup tables (copied
 
186
// from the psttf driver).
 
187
//--------------------------------------------------------------------------
 
188
 
 
189
#define NPANGOLOOKUP    5
 
190
 
 
191
const char *defaultFamilyLookup[NPANGOLOOKUP] = {
 
192
    "sans",
 
193
    "serif",
 
194
    "monospace",
 
195
    "sans,serif",
 
196
    "sans,serif"
 
197
};
 
198
 
 
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"
 
205
};
 
206
 
 
207
#define FAMILY_LOOKUP_LEN    1024
 
208
char familyLookup[NPANGOLOOKUP][FAMILY_LOOKUP_LEN];
 
209
 
 
210
#define TAG_LEN              200
 
211
 
 
212
const char *weightLookup[2] = {
 
213
    "normal",
 
214
    "bold"
 
215
};
 
216
 
 
217
const char *styleLookup[3] = {
 
218
    "normal",
 
219
    "italic",
 
220
    "oblique"
 
221
};
 
222
 
 
223
 
 
224
//--------------------------------------------------------------------------
 
225
//--------------------------------------------------------------------------
 
226
//
 
227
// That which is common to all the Cairo Drivers
 
228
//
 
229
//--------------------------------------------------------------------------
 
230
//--------------------------------------------------------------------------
 
231
 
 
232
//--------------------------------------------------------------------------
 
233
// function declarations
 
234
//--------------------------------------------------------------------------
 
235
 
 
236
// General
 
237
 
 
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 );
 
241
 
 
242
// String processing
 
243
 
 
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 );
 
253
 
 
254
// Graphics
 
255
 
 
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* );
 
268
 
 
269
// PLplot interface functions
 
270
 
 
271
// general
 
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 );
 
279
 
 
280
//--------------------------------------------------------------------------
 
281
// start_raster()
 
282
//
 
283
// Set up off-screen rasterized rendering
 
284
//--------------------------------------------------------------------------
 
285
 
 
286
void start_raster( PLStream *pls )
 
287
{
 
288
    PLCairo         *aStream;
 
289
    cairo_surface_t *tmp_sfc;
 
290
    cairo_t         *tmp_context;
 
291
 
 
292
    aStream = (PLCairo *) pls->dev;
 
293
 
 
294
    // Do not use the external surface if the user says not to
 
295
    if ( !aStream->rasterize_image )
 
296
        return;
 
297
 
 
298
    // Create an image surface and context for the offscreen rendering
 
299
    aStream->cairoSurface_raster =
 
300
        //
 
301
        //  cairo_surface_create_similar( aStream->cairoSurface,
 
302
        //                                CAIRO_CONTENT_COLOR,
 
303
        //                                pls->xlength, pls->ylength );
 
304
        //
 
305
        cairo_image_surface_create( CAIRO_FORMAT_ARGB32,
 
306
            pls->xlength, pls->ylength );
 
307
    aStream->cairoContext_raster = cairo_create( aStream->cairoSurface_raster );
 
308
 
 
309
    // Disable antialiasing for the raster surface.  The output seems to look
 
310
    // better that way.
 
311
    cairo_set_antialias( aStream->cairoContext_raster, CAIRO_ANTIALIAS_NONE );
 
312
 
 
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;
 
321
}
 
322
 
 
323
//--------------------------------------------------------------------------
 
324
// end_raster()
 
325
//
 
326
// Finish off-screen rasterized rendering and copy the result on to the
 
327
// main plot surface.
 
328
//--------------------------------------------------------------------------
 
329
 
 
330
void end_raster( PLStream *pls )
 
331
{
 
332
    PLCairo         *aStream;
 
333
    cairo_surface_t *tmp_sfc;
 
334
    cairo_t         *tmp_context;
 
335
 
 
336
    aStream = (PLCairo *) pls->dev;
 
337
 
 
338
    // TODO FIXME: This should really only copy the used portion of the
 
339
    // offscreen pixmap.
 
340
 
 
341
    // Do not use the external surface if the user says not to
 
342
    if ( !aStream->rasterize_image )
 
343
        return;
 
344
 
 
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" );
 
349
 
 
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;
 
357
 
 
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 );
 
361
 
 
362
    // Free the now extraneous surface and context
 
363
    cairo_destroy( aStream->cairoContext_raster );
 
364
    cairo_surface_destroy( aStream->cairoSurface_raster );
 
365
}
 
366
 
 
367
//--------------------------------------------------------------------------
 
368
// plD_bop_cairo()
 
369
//
 
370
// Set up for the next page.
 
371
//--------------------------------------------------------------------------
 
372
 
 
373
void plD_bop_cairo( PLStream *pls )
 
374
{
 
375
    PLCairo *aStream;
 
376
 
 
377
    aStream = (PLCairo *) pls->dev;
 
378
 
 
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 )
 
382
        return;
 
383
 
 
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 )
 
387
    {
 
388
        cairo_set_source_rgba( aStream->cairoContext, 1.0, 1.0, 1.0, 1.0 );
 
389
        cairo_fill_preserve( aStream->cairoContext );
 
390
    }
 
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 );
 
397
}
 
398
 
 
399
//--------------------------------------------------------------------------
 
400
// plD_line_cairo()
 
401
//
 
402
// Draw a line in the current color from (x1,y1) to (x2,y2).
 
403
//--------------------------------------------------------------------------
 
404
 
 
405
//--------------------------------------------------------------------------
 
406
// (get|set)_line_properties
 
407
//
 
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 )
 
411
{
 
412
    *join = cairo_get_line_join( aStream->cairoContext );
 
413
    *cap  = cairo_get_line_cap( aStream->cairoContext );
 
414
}
 
415
 
 
416
void set_line_properties( PLCairo *aStream, cairo_line_join_t join, cairo_line_cap_t cap )
 
417
{
 
418
    cairo_set_line_join( aStream->cairoContext, join );
 
419
    cairo_set_line_cap( aStream->cairoContext, cap );
 
420
}
 
421
 
 
422
void plD_line_cairo( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
 
423
{
 
424
    PLCairo *aStream;
 
425
 
 
426
    aStream = (PLCairo *) pls->dev;
 
427
 
 
428
    set_current_context( pls );
 
429
 
 
430
    cairo_save( aStream->cairoContext );
 
431
 
 
432
    set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_ROUND );
 
433
 
 
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 );
 
436
 
 
437
    cairo_stroke( aStream->cairoContext );
 
438
 
 
439
    cairo_restore( aStream->cairoContext );
 
440
}
 
441
 
 
442
//--------------------------------------------------------------------------
 
443
// plD_polyline_cairo()
 
444
//
 
445
// Draw a polyline in the current color.
 
446
//--------------------------------------------------------------------------
 
447
 
 
448
void plD_polyline_cairo( PLStream *pls, short *xa, short *ya, PLINT npts )
 
449
{
 
450
    PLCairo *aStream;
 
451
 
 
452
    aStream = (PLCairo *) pls->dev;
 
453
 
 
454
    cairo_save( aStream->cairoContext );
 
455
 
 
456
    set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
 
457
 
 
458
    poly_line( pls, xa, ya, npts );
 
459
 
 
460
    cairo_stroke( aStream->cairoContext );
 
461
 
 
462
    cairo_restore( aStream->cairoContext );
 
463
}
 
464
 
 
465
//--------------------------------------------------------------------------
 
466
// plD_eop_cairo()
 
467
//
 
468
// Generic end of page.
 
469
//--------------------------------------------------------------------------
 
470
 
 
471
void plD_eop_cairo( PLStream *pls )
 
472
{
 
473
    PLCairo *aStream;
 
474
 
 
475
    aStream = (PLCairo *) pls->dev;
 
476
 
 
477
    cairo_show_page( aStream->cairoContext );
 
478
}
 
479
 
 
480
//--------------------------------------------------------------------------
 
481
// plD_tidy_cairo()
 
482
//
 
483
// General: Close graphics file or otherwise clean up.
 
484
//--------------------------------------------------------------------------
 
485
 
 
486
void plD_tidy_cairo( PLStream *pls )
 
487
{
 
488
    PLCairo *aStream;
 
489
 
 
490
    aStream = (PLCairo *) pls->dev;
 
491
 
 
492
    // Free the cairo context and surface.
 
493
    cairo_destroy( aStream->cairoContext );
 
494
    cairo_surface_destroy( aStream->cairoSurface );
 
495
 
 
496
    plCloseFile( pls );
 
497
}
 
498
 
 
499
//--------------------------------------------------------------------------
 
500
// plD_state_cairo()
 
501
//
 
502
// Handle change in PLStream state (color, pen width, fill attribute, etc).
 
503
//
 
504
// Nothing is done here because these attributes are acquired from
 
505
// PLStream for each element that is drawn.
 
506
//--------------------------------------------------------------------------
 
507
 
 
508
void plD_state_cairo( PLStream *pls, PLINT op )
 
509
{
 
510
}
 
511
 
 
512
//--------------------------------------------------------------------------
 
513
// plD_esc_cairo()
 
514
//
 
515
// Generic escape function.
 
516
//--------------------------------------------------------------------------
 
517
 
 
518
void plD_esc_cairo( PLStream *pls, PLINT op, void *ptr )
 
519
{
 
520
    PLCairo *aStream;
 
521
 
 
522
    aStream = (PLCairo *) pls->dev;
 
523
 
 
524
    switch ( op )
 
525
    {
 
526
    case PLESC_FILL:     // filled polygon
 
527
        filled_polygon( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
 
528
        break;
 
529
    case PLESC_GRADIENT:     // render a gradient within a polygon.
 
530
        gradient( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
 
531
        break;
 
532
    case PLESC_HAS_TEXT:
 
533
        if ( !pls->alt_unicode )
 
534
        {
 
535
            proc_str( pls, (EscText *) ptr );
 
536
        }
 
537
        break;
 
538
    case PLESC_BEGIN_TEXT: // get ready to get a handle a string of text
 
539
        text_begin_cairo( pls, (EscText *) ptr );
 
540
        break;
 
541
    case PLESC_TEXT_CHAR: // handle a character of text to display
 
542
        text_char_cairo( pls, (EscText *) ptr );
 
543
        break;
 
544
    case PLESC_CONTROL_CHAR: // handle a control character (super/subscript of fontchange)
 
545
        text_esc_cairo( pls, (EscText *) ptr );
 
546
        break;
 
547
    case PLESC_END_TEXT: // finish a string of text
 
548
        text_end_cairo( pls, (EscText *) ptr );
 
549
        break;
 
550
    case PLESC_START_RASTERIZE: // Start offscreen/rasterized rendering
 
551
        start_raster( pls );
 
552
        break;
 
553
    case PLESC_END_RASTERIZE: // End offscreen/rasterized rendering
 
554
        end_raster( pls );
 
555
        break;
 
556
    case PLESC_ARC: // Draw an arc, either filled or outline
 
557
        arc( pls, (arc_struct *) ptr );
 
558
        break;
 
559
    case PLESC_MODESET: // Set drawing mode
 
560
        set_mode( pls, (int *) ptr );
 
561
        break;
 
562
    case PLESC_MODEGET: // Get drawing mode
 
563
        get_mode( pls, (int *) ptr );
 
564
        break;
 
565
    }
 
566
}
 
567
 
 
568
 
 
569
//--------------------------------------------------------------------------
 
570
// set_mode
 
571
//
 
572
// Set drawing mode.
 
573
//--------------------------------------------------------------------------
 
574
void set_mode( PLStream *pls, PLINT *mode )
 
575
{
 
576
    PLCairo *aStream;
 
577
 
 
578
    aStream = (PLCairo *) pls->dev;
 
579
 
 
580
    switch ( *mode )
 
581
    {
 
582
    case PL_DRAWMODE_UNKNOWN: // Invalid - do nothing
 
583
        break;
 
584
    case PL_DRAWMODE_DEFAULT:
 
585
        cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_OVER );
 
586
        break;
 
587
    case PL_DRAWMODE_REPLACE:
 
588
        cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_SOURCE );
 
589
        break;
 
590
    case PL_DRAWMODE_XOR:
 
591
        cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_XOR );
 
592
        break;
 
593
    }
 
594
    return;
 
595
}
 
596
 
 
597
//--------------------------------------------------------------------------
 
598
// get_mode
 
599
//
 
600
// Get drawing mode.
 
601
//--------------------------------------------------------------------------
 
602
void get_mode( PLStream *pls, PLINT *mode )
 
603
{
 
604
    PLCairo          *aStream;
 
605
    cairo_operator_t op;
 
606
 
 
607
    aStream = (PLCairo *) pls->dev;
 
608
 
 
609
    op = cairo_get_operator( aStream->cairoContext );
 
610
 
 
611
    switch ( op )
 
612
    {
 
613
    case CAIRO_OPERATOR_OVER:
 
614
        *mode = PL_DRAWMODE_DEFAULT;
 
615
        break;
 
616
    case CAIRO_OPERATOR_SOURCE:
 
617
        *mode = PL_DRAWMODE_REPLACE;
 
618
        break;
 
619
    case CAIRO_OPERATOR_XOR:
 
620
        *mode = PL_DRAWMODE_XOR;
 
621
        break;
 
622
    default:
 
623
        *mode = PL_DRAWMODE_UNKNOWN;
 
624
    }
 
625
    return;
 
626
}
 
627
 
 
628
//--------------------------------------------------------------------------
 
629
// text_begin_cairo()
 
630
//
 
631
// Begin text.
 
632
//--------------------------------------------------------------------------
 
633
 
 
634
void text_begin_cairo( PLStream *pls, EscText *args )
 
635
{
 
636
    int     i;
 
637
    PLCairo *aStream;
 
638
 
 
639
    aStream                    = (PLCairo *) pls->dev;
 
640
    aStream->upDown            = 0;
 
641
    aStream->level             = 0;
 
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++ )
 
646
    {
 
647
        aStream->pangoMarkupString[i] = 0;
 
648
    }
 
649
    open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, 0 );
 
650
}
 
651
 
 
652
//--------------------------------------------------------------------------
 
653
// text_char_cairo()
 
654
//
 
655
// Add text.
 
656
//--------------------------------------------------------------------------
 
657
 
 
658
void text_char_cairo( PLStream *pls, EscText *args )
 
659
{
 
660
    char    utf8[5];
 
661
    PLCairo *aStream;
 
662
 
 
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 ) )
 
666
    {
 
667
        switch ( args->n_char )
 
668
        {
 
669
        case 38:
 
670
            strncat( aStream->pangoMarkupString, "&#38;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
 
671
            break;
 
672
        case 60:
 
673
            strncat( aStream->pangoMarkupString, "&#60;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
 
674
            break;
 
675
        case 62:
 
676
            strncat( aStream->pangoMarkupString, "&#62;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
 
677
            break;
 
678
        default:
 
679
            ucs4_to_utf8( args->n_char, utf8 );
 
680
            strncat( aStream->pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
 
681
            break;
 
682
        }
 
683
    }
 
684
}
 
685
 
 
686
//--------------------------------------------------------------------------
 
687
// text_esc_cairo()
 
688
//
 
689
// A font change, superscript, subscript, etc...
 
690
//--------------------------------------------------------------------------
 
691
 
 
692
void text_esc_cairo( PLStream *pls, EscText *args )
 
693
{
 
694
    PLCairo *aStream;
 
695
 
 
696
    aStream = (PLCairo *) pls->dev;
 
697
    switch ( args->n_ctrl_char )
 
698
    {
 
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 );
 
702
        break;
 
703
    case PLTEXT_SUPERSCRIPT:
 
704
        if ( aStream->upDown < 0 )
 
705
        {
 
706
            strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
 
707
            aStream->level++;
 
708
        }
 
709
        else
 
710
        {
 
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 ) );
 
716
        }
 
717
        aStream->upDown++;
 
718
        break;
 
719
    case PLTEXT_SUBSCRIPT:
 
720
        if ( aStream->upDown > 0 )
 
721
        {
 
722
            strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
 
723
            aStream->level--;
 
724
        }
 
725
        else
 
726
        {
 
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 ) );
 
732
        }
 
733
        aStream->upDown--;
 
734
        break;
 
735
    }
 
736
}
 
737
 
 
738
//--------------------------------------------------------------------------
 
739
// text_end_cairo()
 
740
//
 
741
// Draw the text and clean up.
 
742
//--------------------------------------------------------------------------
 
743
 
 
744
void text_end_cairo( PLStream *pls, EscText *args )
 
745
{
 
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;
 
751
    PangoLayout          *layout;
 
752
    PLCairo              *aStream;
 
753
 
 
754
    aStream = (PLCairo *) pls->dev;
 
755
 
 
756
    set_current_context( pls );
 
757
 
 
758
    // Close the last span tag.
 
759
    close_span_tag( aStream->pangoMarkupString, aStream->upDown );
 
760
 
 
761
    // printf("%s\n", aStream->pangoMarkupString);
 
762
 
 
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 );
 
768
 
 
769
    // If asked, set the string length (in mm) and return
 
770
    if ( pls->get_string_length )
 
771
    {
 
772
        pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
 
773
        return;
 
774
    }
 
775
 
 
776
    // Set font aliasing
 
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 );
 
783
 
 
784
    // Save current transform matrix & clipping region
 
785
    cairo_save( aStream->cairoContext );
 
786
 
 
787
    // Set up the clipping region if we are doing text clipping
 
788
    if ( aStream->text_clipping )
 
789
    {
 
790
        set_clip( pls );
 
791
    }
 
792
 
 
793
    // Move to the string reference point
 
794
    cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
 
795
 
 
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 );
 
800
 
 
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 );
 
809
 
 
810
    // Apply the transform matrix
 
811
    cairo_matrix_init( cairoTransformMatrix,
 
812
        cos_rot * stride,
 
813
        -sin_rot * stride,
 
814
        cos_rot * sin_shear + sin_rot * cos_shear,
 
815
        -sin_rot * sin_shear + cos_rot * cos_shear,
 
816
        0, 0 );
 
817
    cairo_transform( aStream->cairoContext, cairoTransformMatrix );
 
818
    free( cairoTransformMatrix );
 
819
 
 
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 );
 
825
 
 
826
    // Render the text
 
827
    pango_cairo_show_layout( aStream->cairoContext, layout );
 
828
 
 
829
    // Restore the transform matrix to its state prior to the text transform.
 
830
    cairo_restore( aStream->cairoContext );
 
831
 
 
832
    // Free the layout object and the markup string.
 
833
    g_object_unref( layout );
 
834
    free( aStream->pangoMarkupString );
 
835
}
 
836
 
 
837
//--------------------------------------------------------------------------
 
838
// proc_str()
 
839
//
 
840
// Processes strings for display.
 
841
//--------------------------------------------------------------------------
 
842
 
 
843
void proc_str( PLStream *pls, EscText *args )
 
844
{
 
845
    float fontSize;
 
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;
 
852
    PangoLayout          *layout;
 
853
    PLCairo              *aStream;
 
854
 
 
855
    aStream = (PLCairo *) pls->dev;
 
856
 
 
857
    set_current_context( pls );
 
858
 
 
859
    // Check that we got unicode, warning message and return if not
 
860
    if ( args->unicode_array_len == 0 )
 
861
    {
 
862
        printf( "Non unicode string passed to a cairo driver, ignoring\n" );
 
863
        return;
 
864
    }
 
865
 
 
866
    // Check that unicode string isn't longer then the max we allow
 
867
    if ( args->unicode_array_len >= MAX_STRING_LEN )
 
868
    {
 
869
        printf( "Sorry, the cairo drivers only handles strings of length < %d\n", MAX_STRING_LEN );
 
870
        return;
 
871
    }
 
872
 
 
873
    // Calculate the font size (in points since DPI = 72).
 
874
    fontSize = pls->chrht * DPI / 25.4;
 
875
 
 
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 );
 
878
 
 
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 );
 
884
 
 
885
    // If asked, set the string length (in mm) and return
 
886
    if ( pls->get_string_length )
 
887
    {
 
888
        pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
 
889
        return;
 
890
    }
 
891
 
 
892
    // Set font aliasing
 
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 );
 
899
 
 
900
    // Save current transform matrix & clipping region
 
901
    cairo_save( aStream->cairoContext );
 
902
 
 
903
    // Set up the clipping region if we are doing text clipping
 
904
    if ( aStream->text_clipping )
 
905
    {
 
906
        set_clip( pls );
 
907
    }
 
908
 
 
909
    // Move to the string reference point
 
910
    cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
 
911
 
 
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 );
 
916
 
 
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 );
 
925
 
 
926
    // Apply the transform matrix
 
927
    cairo_matrix_init( cairoTransformMatrix,
 
928
        cos_rot * stride,
 
929
        -sin_rot * stride,
 
930
        cos_rot * sin_shear + sin_rot * cos_shear,
 
931
        -sin_rot * sin_shear + cos_rot * cos_shear,
 
932
        0, 0 );
 
933
    cairo_transform( aStream->cairoContext, cairoTransformMatrix );
 
934
    free( cairoTransformMatrix );
 
935
 
 
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 );
 
941
 
 
942
    // Render the text
 
943
    pango_cairo_show_layout( aStream->cairoContext, layout );
 
944
 
 
945
    // Restore the transform matrix to its state prior to the text transform.
 
946
    cairo_restore( aStream->cairoContext );
 
947
 
 
948
    // Free the layout object and the markup string.
 
949
    g_object_unref( layout );
 
950
    free( textWithPangoMarkup );
 
951
}
 
952
 
 
953
//--------------------------------------------------------------------------
 
954
// ucs4_to_pango_markup_format()
 
955
//
 
956
// Converts the plplot string (in ucs4) to a utf8 string that includes
 
957
// pango markup.
 
958
//
 
959
// http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html
 
960
//--------------------------------------------------------------------------
 
961
 
 
962
char *ucs4_to_pango_markup_format( PLUNICODE *ucs4, int ucs4Len, float fontSize )
 
963
{
 
964
    char      plplotEsc;
 
965
    int       i;
 
966
    int       upDown = 0;
 
967
    PLUNICODE fci;
 
968
    char      utf8[5];
 
969
    char      *pangoMarkupString;
 
970
    PLFLT     old_sscale, sscale, old_soffset, soffset;
 
971
    PLINT     level = 0.;
 
972
 
 
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++ )
 
976
    {
 
977
        pangoMarkupString[i] = 0;
 
978
    }
 
979
 
 
980
    // Get PLplot escape character
 
981
    plgesc( &plplotEsc );
 
982
 
 
983
    // Get the curent font and open the first span tag
 
984
    plgfci( &fci );
 
985
    open_span_tag( pangoMarkupString, fci, fontSize, 0 );
 
986
 
 
987
    // Parse the string to generate the tags
 
988
    i = 0;
 
989
    while ( i < ucs4Len )
 
990
    {
 
991
        // Try to avoid going off the end of the string
 
992
        if ( strlen( pangoMarkupString ) > ( MAX_MARKUP_LEN - 50 ) )
 
993
        {
 
994
            continue;
 
995
        }
 
996
        if ( ucs4[i] < PL_FCI_MARK )                // not a font change
 
997
        {
 
998
            if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
 
999
            {                                       // we have to handle "<", ">" and "&" separately since they throw off the XML
 
1000
                switch ( ucs4[i] )
 
1001
                {
 
1002
                case 38:
 
1003
                    strncat( pangoMarkupString, "&#38;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1004
                    break;
 
1005
                case 60:
 
1006
                    strncat( pangoMarkupString, "&#60;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1007
                    break;
 
1008
                case 62:
 
1009
                    strncat( pangoMarkupString, "&#62;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1010
                    break;
 
1011
                default:
 
1012
                    ucs4_to_utf8( ucs4[i], utf8 );
 
1013
                    strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1014
                    break;
 
1015
                }
 
1016
                i++;
 
1017
                continue;
 
1018
            }
 
1019
            i++;
 
1020
            if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
 
1021
            {
 
1022
                ucs4_to_utf8( ucs4[i], utf8 );
 
1023
                strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1024
                i++;
 
1025
                continue;
 
1026
            }
 
1027
            else
 
1028
            {
 
1029
                if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
 
1030
                {
 
1031
                    if ( upDown < 0 )
 
1032
                    {
 
1033
                        strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1034
                        level++;
 
1035
                    }
 
1036
                    else
 
1037
                    {
 
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 ) );
 
1043
                    }
 
1044
                    upDown++;
 
1045
                }
 
1046
                if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
 
1047
                {
 
1048
                    if ( upDown > 0 )
 
1049
                    {
 
1050
                        strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1051
                        level--;
 
1052
                    }
 
1053
                    else
 
1054
                    {
 
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 ) );
 
1060
                    }
 
1061
                    upDown--;
 
1062
                }
 
1063
                i++;
 
1064
            }
 
1065
        }
 
1066
        else // a font change
 
1067
        {
 
1068
            close_span_tag( pangoMarkupString, upDown );
 
1069
            open_span_tag( pangoMarkupString, ucs4[i], fontSize, upDown );
 
1070
            i++;
 
1071
        }
 
1072
    }
 
1073
 
 
1074
    // Close the last span tag.
 
1075
    close_span_tag( pangoMarkupString, upDown );
 
1076
 
 
1077
    // printf("%s\n", pangoMarkupString);
 
1078
 
 
1079
    return pangoMarkupString;
 
1080
}
 
1081
 
 
1082
//--------------------------------------------------------------------------
 
1083
// open_span_tag
 
1084
//
 
1085
// 1. Opens a span tag with the appropriate font description given the
 
1086
//   current fci.
 
1087
// 2. Add the appropriate number of <sub> or <sup> tags to bring us
 
1088
//   back to our current sub/super-script level.
 
1089
//--------------------------------------------------------------------------
 
1090
 
 
1091
void open_span_tag( char *pangoMarkupString, PLUNICODE fci, float fontSize, int upDown )
 
1092
{
 
1093
    unsigned char fontFamily, fontStyle, fontWeight;
 
1094
    char          openTag[TAG_LEN];
 
1095
    int           upDown_level;
 
1096
    PLFLT         old_sscale, sscale, old_soffset, soffset;
 
1097
    PLINT         level = 0.;
 
1098
 
 
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 );
 
1104
 
 
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 ) );
 
1109
 
 
1110
    snprintf( openTag, TAG_LEN, "style=\"%s\" ", styleLookup[fontStyle] );
 
1111
    strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1112
 
 
1113
    snprintf( openTag, TAG_LEN, "weight=\"%s\">", weightLookup[fontWeight] );
 
1114
    strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1115
 
 
1116
    // Move to the right superscript/subscript level
 
1117
    for ( upDown_level = 0; upDown_level < upDown; upDown_level++ )
 
1118
    {
 
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 ) );
 
1124
    }
 
1125
    for ( upDown_level = 0; upDown_level > upDown; upDown_level-- )
 
1126
    {
 
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 ) );
 
1132
    }
 
1133
}
 
1134
 
 
1135
//--------------------------------------------------------------------------
 
1136
// close_span_tag
 
1137
//
 
1138
// Close a span tag & brings us down to zero sub/super-script level.
 
1139
//--------------------------------------------------------------------------
 
1140
 
 
1141
void close_span_tag( char *pangoMarkupString, int upDown )
 
1142
{
 
1143
    if ( upDown > 0 )
 
1144
    {
 
1145
        while ( upDown > 0 )
 
1146
        {
 
1147
            strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1148
            upDown--;
 
1149
        }
 
1150
    }
 
1151
    if ( upDown < 0 )
 
1152
    {
 
1153
        while ( upDown < 0 )
 
1154
        {
 
1155
            strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1156
            upDown++;
 
1157
        }
 
1158
    }
 
1159
 
 
1160
    strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
 
1161
}
 
1162
 
 
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
 
1167
// are involved).
 
1168
# define RISE_FACTOR    0.8
 
1169
 
 
1170
//--------------------------------------------------------------------------
 
1171
// rise_span_tag
 
1172
//
 
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.
 
1178
 
 
1179
//--------------------------------------------------------------------------
 
1180
 
 
1181
char *rise_span_tag( int ifsuperscript, float fontSize, float multiplier, float rise )
 
1182
{
 
1183
    float       offset;
 
1184
    static char tag[100];
 
1185
 
 
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;
 
1192
 
 
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 );
 
1197
 
 
1198
    if ( ifsuperscript )
 
1199
    {
 
1200
        sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
 
1201
            (int) ( rise + offset ), (int) ( fontSize * 1024. * multiplier ) );
 
1202
    }
 
1203
    else
 
1204
    {
 
1205
        sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
 
1206
            (int) -( rise - offset ), (int) ( fontSize * 1024. * multiplier ) );
 
1207
    }
 
1208
 
 
1209
    return ( tag );
 
1210
}
 
1211
 
 
1212
//--------------------------------------------------------------------------
 
1213
// write_to_stream()
 
1214
//
 
1215
// Writes data to a open file stream. This function is passed to the
 
1216
// Cairo file IO devices.
 
1217
//--------------------------------------------------------------------------
 
1218
 
 
1219
cairo_status_t write_to_stream( void *filePointer, unsigned char *data, unsigned int length )
 
1220
{
 
1221
    int bytes_written;
 
1222
 
 
1223
    bytes_written = fwrite( data, 1, length, (FILE *) filePointer );
 
1224
    if ( bytes_written == length )
 
1225
    {
 
1226
        return CAIRO_STATUS_SUCCESS;
 
1227
    }
 
1228
    else
 
1229
    {
 
1230
        return CAIRO_STATUS_WRITE_ERROR;
 
1231
    }
 
1232
}
 
1233
 
 
1234
//--------------------------------------------------------------------------
 
1235
// stream_and_font_setup()
 
1236
//
 
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
//--------------------------------------------------------------------------
 
1242
 
 
1243
PLCairo *stream_and_font_setup( PLStream *pls, int interactive )
 
1244
{
 
1245
    int     i;
 
1246
    char    *a;
 
1247
    PLCairo *aStream;
 
1248
    PLFLT   downscale;
 
1249
    downscale = 0.0;
 
1250
 
 
1251
    // Stream setup
 
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
 
1257
    pls->dev_clear         = 0;
 
1258
    pls->alt_unicode       = 1;           // Wants to handle unicode character by character
 
1259
    pls->page              = 0;
 
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
 
1266
 
 
1267
    if ( pls->xlength <= 0 || pls->ylength <= 0 )
 
1268
    {
 
1269
        pls->xlength = PLCAIRO_DEFAULT_X;
 
1270
        pls->ylength = PLCAIRO_DEFAULT_Y;
 
1271
    }
 
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 );
 
1276
    else
 
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 );
 
1280
 
 
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++ )
 
1284
    {
 
1285
        if ( ( a = getenv( envFamilyLookup[i] ) ) != NULL )
 
1286
        {
 
1287
            strncpy( familyLookup[i], a, FAMILY_LOOKUP_LEN - 1 );
 
1288
            familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
 
1289
        }
 
1290
        else
 
1291
        {
 
1292
            strncpy( familyLookup[i], defaultFamilyLookup[i], FAMILY_LOOKUP_LEN - 1 );
 
1293
            familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
 
1294
        }
 
1295
    }
 
1296
 
 
1297
    // Allocate a cairo stream structure
 
1298
    aStream = malloc( sizeof ( PLCairo ) );
 
1299
#if defined ( PLD_xcairo )
 
1300
    aStream->XDisplay = NULL;
 
1301
    aStream->XWindow  = -1;
 
1302
#endif
 
1303
    aStream->cairoSurface = NULL;
 
1304
    aStream->cairoContext = NULL;
 
1305
    aStream->downscale    = downscale;
 
1306
 
 
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;
 
1310
    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
 
1316
 
 
1317
    // Check for cairo specific options
 
1318
    plParseDrvOpts( cairo_options );
 
1319
 
 
1320
    // Turn off text clipping if the user desires this
 
1321
    if ( !text_clipping )
 
1322
    {
 
1323
        aStream->text_clipping = 0;
 
1324
    }
 
1325
 
 
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;
 
1332
 
 
1333
    return aStream;
 
1334
}
 
1335
 
 
1336
//--------------------------------------------------------------------------
 
1337
// set_current_context()
 
1338
//
 
1339
// Updates the cairo graphics context with the current values in
 
1340
// PLStream.
 
1341
//--------------------------------------------------------------------------
 
1342
 
 
1343
void set_current_context( PLStream *pls )
 
1344
{
 
1345
    PLCairo *aStream;
 
1346
 
 
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 )
 
1355
    {
 
1356
        cairo_set_line_width( aStream->cairoContext, 1.0 );
 
1357
    }
 
1358
    else
 
1359
    {
 
1360
        cairo_set_line_width( aStream->cairoContext, (double) pls->width );
 
1361
    }
 
1362
}
 
1363
 
 
1364
//--------------------------------------------------------------------------
 
1365
// poly_line()
 
1366
//
 
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
//--------------------------------------------------------------------------
 
1371
 
 
1372
void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts )
 
1373
{
 
1374
    int     i;
 
1375
    PLCairo *aStream;
 
1376
 
 
1377
    aStream = (PLCairo *) pls->dev;
 
1378
 
 
1379
    set_current_context( pls );
 
1380
 
 
1381
    cairo_move_to( aStream->cairoContext, aStream->downscale * (double) xa[0], aStream->downscale * (double) ya[0] );
 
1382
    for ( i = 1; i < npts; i++ )
 
1383
    {
 
1384
        cairo_line_to( aStream->cairoContext, aStream->downscale * (double) xa[i], aStream->downscale * (double) ya[i] );
 
1385
    }
 
1386
}
 
1387
 
 
1388
//--------------------------------------------------------------------------
 
1389
// filled_polygon()
 
1390
//
 
1391
// Draws a filled polygon.
 
1392
//--------------------------------------------------------------------------
 
1393
 
 
1394
void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts )
 
1395
{
 
1396
    int     i;
 
1397
    PLCairo *aStream;
 
1398
 
 
1399
    aStream = (PLCairo *) pls->dev;
 
1400
 
 
1401
    cairo_save( aStream->cairoContext );
 
1402
 
 
1403
    // Draw the polygons
 
1404
    poly_line( pls, xa, ya, npts );
 
1405
 
 
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 );
 
1411
 
 
1412
    if ( cairo_get_antialias( aStream->cairoContext ) != CAIRO_ANTIALIAS_NONE )
 
1413
    {
 
1414
        cairo_fill_preserve( aStream->cairoContext );
 
1415
 
 
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 );
 
1420
    }
 
1421
    else
 
1422
    {
 
1423
        cairo_fill( aStream->cairoContext );
 
1424
    }
 
1425
 
 
1426
    cairo_restore( aStream->cairoContext );
 
1427
}
 
1428
 
 
1429
//--------------------------------------------------------------------------
 
1430
// gradient()
 
1431
//
 
1432
// Render a gradient within a polygon.
 
1433
//--------------------------------------------------------------------------
 
1434
 
 
1435
void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
 
1436
{
 
1437
    int i;
 
1438
    PLCairo         *aStream;
 
1439
    cairo_pattern_t *linear_gradient;
 
1440
 
 
1441
    aStream = (PLCairo *) pls->dev;
 
1442
 
 
1443
    // These line properties make for a nicer looking polygon mesh
 
1444
    set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
 
1445
 
 
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] );
 
1451
 
 
1452
    cairo_pattern_reference( linear_gradient );
 
1453
    for ( i = 0; i < pls->ncol1; i++ )
 
1454
    {
 
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 );
 
1461
    }
 
1462
 
 
1463
    // Draw the polygon using the gradient.
 
1464
    poly_line( pls, xa, ya, npts );
 
1465
 
 
1466
    cairo_set_source( aStream->cairoContext, linear_gradient );
 
1467
    cairo_fill( aStream->cairoContext );
 
1468
    cairo_pattern_destroy( linear_gradient );
 
1469
}
 
1470
 
 
1471
//--------------------------------------------------------------------------
 
1472
// set_clip()
 
1473
//
 
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
//--------------------------------------------------------------------------
 
1478
 
 
1479
void set_clip( PLStream *pls )
 
1480
{
 
1481
    PLINT   rcx[4], rcy[4];
 
1482
    PLCairo *aStream;
 
1483
    aStream = (PLCairo *) pls->dev;
 
1484
 
 
1485
    // Use PLplot core routine to get the corners of the clipping rectangle
 
1486
    difilt_clip( rcx, rcy );
 
1487
 
 
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] );
 
1505
 
 
1506
    // Set the clipping region
 
1507
    cairo_clip( aStream->cairoContext );
 
1508
 
 
1509
    // Apparently, in some older Cairo versions, cairo_clip does not consume
 
1510
    // the current path.
 
1511
    cairo_new_path( aStream->cairoContext );
 
1512
}
 
1513
 
 
1514
//--------------------------------------------------------------------------
 
1515
// arc()
 
1516
//
 
1517
// Draws an arc, possibly filled.
 
1518
//--------------------------------------------------------------------------
 
1519
 
 
1520
void arc( PLStream *pls, arc_struct *arc_info )
 
1521
{
 
1522
    PLCairo *aStream;
 
1523
    double  x, y, a, b;
 
1524
    double  angle1, angle2, rotate;
 
1525
 
 
1526
    set_current_context( pls );
 
1527
 
 
1528
    aStream = (PLCairo *) pls->dev;
 
1529
 
 
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;
 
1535
 
 
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;
 
1540
 
 
1541
    cairo_save( aStream->cairoContext );
 
1542
 
 
1543
    // Clip the output to the plotting window
 
1544
    set_clip( pls );
 
1545
 
 
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 );
 
1555
 
 
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 )
 
1562
    {
 
1563
        cairo_fill( aStream->cairoContext );
 
1564
    }
 
1565
    else
 
1566
    {
 
1567
        cairo_stroke( aStream->cairoContext );
 
1568
    }
 
1569
    cairo_restore( aStream->cairoContext );
 
1570
}
 
1571
 
 
1572
//--------------------------------------------------------------------------
 
1573
// rotate_cairo_surface()
 
1574
//
 
1575
// Rotates the cairo surface to the appropriate orientation.
 
1576
//--------------------------------------------------------------------------
 
1577
 
 
1578
void rotate_cairo_surface( PLStream *pls, float x11, float x12, float x21, float x22, float x0, float y0, PLBOOL is_xcairo )
 
1579
{
 
1580
    cairo_matrix_t *matrix;
 
1581
    PLCairo        *aStream;
 
1582
 
 
1583
    aStream = (PLCairo *) pls->dev;
 
1584
 
 
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 )
 
1588
    if ( is_xcairo )
 
1589
    {
 
1590
        cairo_transform( aStream->cairoContext_X, matrix );
 
1591
    }
 
1592
    else
 
1593
    {
 
1594
        cairo_transform( aStream->cairoContext, matrix );
 
1595
    }
 
1596
#else
 
1597
    cairo_transform( aStream->cairoContext, matrix );
 
1598
#endif
 
1599
    free( matrix );
 
1600
}
 
1601
 
 
1602
//--------------------------------------------------------------------------
 
1603
//--------------------------------------------------------------------------
 
1604
//
 
1605
// That which is common to all familying Cairo Drivers
 
1606
//
 
1607
//--------------------------------------------------------------------------
 
1608
//--------------------------------------------------------------------------
 
1609
#if defined ( PLD_pngcairo ) || defined ( PLD_svgcairo )
 
1610
 
 
1611
void plD_bop_famcairo( PLStream * );
 
1612
//--------------------------------------------------------------------------
 
1613
// plD_bop_famcairo()
 
1614
//
 
1615
// Familying Devices: Set up for the next page.
 
1616
//--------------------------------------------------------------------------
 
1617
 
 
1618
void plD_bop_famcairo( PLStream *pls )
 
1619
{
 
1620
    PLCairo *aStream;
 
1621
 
 
1622
    aStream = (PLCairo *) pls->dev;
 
1623
 
 
1624
    // Plot familying stuff. Not really understood, just copying gd.c
 
1625
    plGetFam( pls );
 
1626
    pls->famadv = 1;
 
1627
    pls->page++;
 
1628
 
 
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 );
 
1637
}
 
1638
 
 
1639
#endif
 
1640
//--------------------------------------------------------------------------
 
1641
//--------------------------------------------------------------------------
 
1642
//
 
1643
// That which is specific to the xcairo driver.
 
1644
//
 
1645
//--------------------------------------------------------------------------
 
1646
//--------------------------------------------------------------------------
 
1647
 
 
1648
#if defined ( PLD_xcairo )
 
1649
 
 
1650
static int    XScreen;
 
1651
static Window rootWindow;
 
1652
 
 
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 * );
 
1660
 
 
1661
//--------------------------------------------------------------------------
 
1662
// plD_dispatch_init_xcairo()
 
1663
//
 
1664
// xcairo dispatch table initialization.
 
1665
//--------------------------------------------------------------------------
 
1666
 
 
1667
void plD_dispatch_init_xcairo( PLDispatchTable *pdt )
 
1668
{
 
1669
#ifndef ENABLE_DYNDRIVERS
 
1670
    pdt->pl_MenuStr = "Cairo X Windows Driver";
 
1671
    pdt->pl_DevName = "xcairo";
 
1672
#endif
 
1673
    pdt->pl_type     = plDevType_Interactive;
 
1674
    pdt->pl_seq      = 100;
 
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;
 
1683
}
 
1684
 
 
1685
//--------------------------------------------------------------------------
 
1686
// xcairo_init_cairo()
 
1687
//
 
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.
 
1692
//
 
1693
// A return value of 0 indicates success.  Currently this function only
 
1694
// returns 0.
 
1695
//--------------------------------------------------------------------------
 
1696
 
 
1697
static signed int xcairo_init_cairo( PLStream *pls )
 
1698
{
 
1699
    PLCairo *aStream;
 
1700
    Visual  *defaultVisual;
 
1701
 
 
1702
    aStream = (PLCairo *) pls->dev;
 
1703
 
 
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 )
 
1712
    {
 
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 );
 
1715
    }
 
1716
    else
 
1717
    {
 
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 );
 
1723
    }
 
1724
 
 
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 );
 
1727
 
 
1728
    // Set graphics aliasing
 
1729
    cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
 
1730
 
 
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 );
 
1734
    else
 
1735
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
1736
 
 
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 );
 
1746
 
 
1747
    XFlush( aStream->XDisplay );
 
1748
 
 
1749
    return 0;
 
1750
}
 
1751
 
 
1752
//--------------------------------------------------------------------------
 
1753
// plD_init_xcairo()
 
1754
//
 
1755
// Initialize Cairo X Windows device.
 
1756
//--------------------------------------------------------------------------
 
1757
 
 
1758
void plD_init_xcairo( PLStream *pls )
 
1759
{
 
1760
    PLCairo *aStream;
 
1761
    Atom    wmDelete;
 
1762
 
 
1763
    // Setup the PLStream and the font lookup table.
 
1764
    aStream = stream_and_font_setup( pls, 1 );
 
1765
 
 
1766
    // Save the pointer to the structure in the PLplot stream
 
1767
    pls->dev = aStream;
 
1768
 
 
1769
    // Create a X Window if required.
 
1770
    if ( external_drawable != 0 )
 
1771
    {
 
1772
        aStream->xdrawable_mode = 1;
 
1773
    }
 
1774
    else
 
1775
    {
 
1776
        // X Windows setup
 
1777
        aStream->XDisplay = NULL;
 
1778
        aStream->XDisplay = XOpenDisplay( NULL );
 
1779
        if ( aStream->XDisplay == NULL )
 
1780
        {
 
1781
            printf( "Failed to open X Windows display\n" );
 
1782
            // some sort of error here
 
1783
        }
 
1784
        XScreen    = DefaultScreen( aStream->XDisplay );
 
1785
        rootWindow = RootWindow( aStream->XDisplay, XScreen );
 
1786
 
 
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;
 
1793
 
 
1794
        wmDelete = XInternAtom( aStream->XDisplay, "WM_DELETE_WINDOW", True );
 
1795
        XSetWMProtocols( aStream->XDisplay, aStream->XWindow, &wmDelete, 1 );
 
1796
 
 
1797
        xcairo_init_cairo( pls );
 
1798
    }
 
1799
 
 
1800
    aStream->exit_event_loop = 0;
 
1801
}
 
1802
 
 
1803
//--------------------------------------------------------------------------
 
1804
// blit_to_x()
 
1805
//
 
1806
//
 
1807
// Blit the offscreen image to the X window.
 
1808
//--------------------------------------------------------------------------
 
1809
 
 
1810
void blit_to_x( PLStream *pls, double x, double y, double w, double h )
 
1811
{
 
1812
    PLCairo *aStream;
 
1813
 
 
1814
    aStream = pls->dev;
 
1815
 
 
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 );
 
1828
 
 
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 );
 
1837
}
 
1838
 
 
1839
//--------------------------------------------------------------------------
 
1840
// plD_bop_xcairo()
 
1841
//
 
1842
// X Windows specific start of page.
 
1843
//--------------------------------------------------------------------------
 
1844
 
 
1845
void plD_bop_xcairo( PLStream *pls )
 
1846
{
 
1847
    PLCairo *aStream;
 
1848
 
 
1849
    aStream = (PLCairo *) pls->dev;
 
1850
 
 
1851
    plD_bop_cairo( pls );
 
1852
 
 
1853
    if ( aStream->xdrawable_mode )
 
1854
        return;
 
1855
 
 
1856
    XFlush( aStream->XDisplay );
 
1857
}
 
1858
 
 
1859
//--------------------------------------------------------------------------
 
1860
// plD_eop_xcairo()
 
1861
//
 
1862
// X Windows specific end of page.
 
1863
//--------------------------------------------------------------------------
 
1864
 
 
1865
void plD_eop_xcairo( PLStream *pls )
 
1866
{
 
1867
    int            number_chars;
 
1868
    long           event_mask;
 
1869
    char           event_string[10];
 
1870
    KeySym         keysym;
 
1871
    XComposeStatus cs;
 
1872
    XEvent         event;
 
1873
    XExposeEvent   *expose;
 
1874
    PLCairo        *aStream;
 
1875
    char           helpmsg[] = " - Press Enter or right-click to continue";
 
1876
    char           *plotTitle;
 
1877
 
 
1878
    aStream = (PLCairo *) pls->dev;
 
1879
 
 
1880
    // Blit the offscreen image to the X window.
 
1881
    blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
 
1882
 
 
1883
    if ( aStream->xdrawable_mode )
 
1884
        return;
 
1885
 
 
1886
    // Only pause if nopause is unset.
 
1887
    if ( pls->nopause )
 
1888
        aStream->exit_event_loop = 1;
 
1889
 
 
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 )
 
1894
    {
 
1895
        //XWindowEvent( aStream->XDisplay, aStream->XWindow, event_mask, &event );
 
1896
        XNextEvent( aStream->XDisplay, &event );
 
1897
        switch ( event.type )
 
1898
        {
 
1899
        case KeyPress:
 
1900
            number_chars = XLookupString( (XKeyEvent *) &event, event_string, 10, &keysym, &cs );
 
1901
            event_string[number_chars] = '\0';
 
1902
            if ( keysym == XK_Return )
 
1903
            {
 
1904
                aStream->exit_event_loop = 1;
 
1905
            }
 
1906
            break;
 
1907
        case ButtonPress:
 
1908
            if ( ( (XButtonEvent *) &event )->button == Button3 )
 
1909
                aStream->exit_event_loop = 1;
 
1910
            break;
 
1911
        case ClientMessage:
 
1912
            // plexit("X Window closed");
 
1913
            pls->stream_closed       = TRUE;
 
1914
            aStream->exit_event_loop = 1;
 
1915
            break;
 
1916
        case Expose:
 
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 )
 
1921
            {
 
1922
                blit_to_x( pls, expose->x, expose->y,
 
1923
                    expose->width, expose->height );
 
1924
            }
 
1925
            break;
 
1926
        }
 
1927
    }
 
1928
    aStream->exit_event_loop = 0;
 
1929
}
 
1930
 
 
1931
//--------------------------------------------------------------------------
 
1932
// plD_tidy_xcairo()
 
1933
//
 
1934
// X Windows: close graphics file or otherwise clean up.
 
1935
//--------------------------------------------------------------------------
 
1936
 
 
1937
void plD_tidy_xcairo( PLStream *pls )
 
1938
{
 
1939
    PLCairo *aStream;
 
1940
 
 
1941
    aStream = (PLCairo *) pls->dev;
 
1942
 
 
1943
    plD_tidy_cairo( pls );
 
1944
 
 
1945
    // Also free up the Cairo X surface and context
 
1946
    cairo_destroy( aStream->cairoContext_X );
 
1947
    cairo_surface_destroy( aStream->cairoSurface_X );
 
1948
 
 
1949
    if ( aStream->xdrawable_mode )
 
1950
        return;
 
1951
 
 
1952
    // Close the window and the display.
 
1953
    XFlush( aStream->XDisplay );
 
1954
 
 
1955
    XDestroyWindow( aStream->XDisplay, aStream->XWindow );
 
1956
 
 
1957
    XCloseDisplay( aStream->XDisplay );
 
1958
}
 
1959
 
 
1960
//--------------------------------------------------------------------------
 
1961
// plD_esc_xcairo()
 
1962
//
 
1963
// Escape function, specialized for the xcairo driver
 
1964
//--------------------------------------------------------------------------
 
1965
 
 
1966
void plD_esc_xcairo( PLStream *pls, PLINT op, void *ptr )
 
1967
{
 
1968
    PLCairo *aStream;
 
1969
 
 
1970
    aStream = (PLCairo *) pls->dev;
 
1971
 
 
1972
    switch ( op )
 
1973
    {
 
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 );
 
1977
        break;
 
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 );
 
1982
        break;
 
1983
    case PLESC_DEVINIT: { // Set external drawable
 
1984
        Window               rootwin;
 
1985
        PLXcairoDrawableInfo *xinfo = (PLXcairoDrawableInfo *) ptr;
 
1986
        signed int           x, y;
 
1987
        unsigned int         w, h, b, d;
 
1988
        if ( xinfo == NULL )
 
1989
        {
 
1990
            printf( "xcairo: PLESC_DEVINIT ignored, no drawable info provided\n" );
 
1991
            return;
 
1992
        }
 
1993
        if ( aStream->xdrawable_mode == 0 )
 
1994
        {
 
1995
            printf( "xcairo: PLESC_DEVINIT called with drawable but stream not in xdrawable mode\n" );
 
1996
            return;
 
1997
        }
 
1998
        aStream->XDisplay = xinfo->display;
 
1999
        aStream->XWindow  = xinfo->drawable;
 
2000
 
 
2001
        // Ensure plplot knows the real dimensions of the drawable
 
2002
        XGetGeometry( aStream->XDisplay, aStream->XWindow, &rootwin,
 
2003
            &x, &y, &w, &h, &b, &d );
 
2004
        pls->xlength = w;
 
2005
        pls->ylength = h;
 
2006
        plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / aStream->downscale ), (PLINT) 0,
 
2007
            (PLINT) ( pls->ylength / aStream->downscale ) );
 
2008
 
 
2009
        // Associate cairo with the supplied drawable
 
2010
        xcairo_init_cairo( pls );
 
2011
 
 
2012
        // Recalculate dimensions and the like now that the drawable is known
 
2013
        plbop();
 
2014
 
 
2015
        break;
 
2016
    }
 
2017
    default:
 
2018
        plD_esc_cairo( pls, op, ptr );
 
2019
        break;
 
2020
    }
 
2021
}
 
2022
 
 
2023
//--------------------------------------------------------------------------
 
2024
// xcairo_get_cursor()
 
2025
//
 
2026
// X Windows: returns the location of the next mouse click or key press.
 
2027
//--------------------------------------------------------------------------
 
2028
 
 
2029
void xcairo_get_cursor( PLStream *pls, PLGraphicsIn *gin )
 
2030
{
 
2031
    int            number_chars;
 
2032
    char           *ksname;
 
2033
    char           str[257];
 
2034
    KeySym         keysym;
 
2035
    XComposeStatus cs;
 
2036
    XEvent         event;
 
2037
    XButtonEvent   *xButtonEvent;
 
2038
    Cursor         xHairCursor;
 
2039
    PLCairo        *aStream;
 
2040
 
 
2041
    aStream = (PLCairo *) pls->dev;
 
2042
 
 
2043
    // Initialize PLplot mouse event structure
 
2044
    plGinInit( gin );
 
2045
 
 
2046
    // Create cross hair cursor & switch to using it
 
2047
    xHairCursor = XCreateFontCursor( aStream->XDisplay, XC_crosshair );
 
2048
    XDefineCursor( aStream->XDisplay, aStream->XWindow, xHairCursor );
 
2049
 
 
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 );
 
2054
 
 
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 ) );
 
2063
 
 
2064
    // Get key pressed (if any)
 
2065
    if ( event.type == KeyPress || event.type == KeyRelease )
 
2066
    {
 
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';
 
2074
        switch ( keysym )
 
2075
        {
 
2076
        case XK_BackSpace:
 
2077
        case XK_Tab:
 
2078
        case XK_Linefeed:
 
2079
        case XK_Return:
 
2080
        case XK_Escape:
 
2081
        case XK_Delete:
 
2082
            gin->keysym = 0xFF & keysym;
 
2083
            break;
 
2084
        default:
 
2085
            gin->keysym = keysym;
 
2086
        }
 
2087
    }
 
2088
    else // button press
 
2089
    {
 
2090
        sprintf( gin->string, "button %u", gin->button );
 
2091
        gin->keysym = 0x20;
 
2092
    }
 
2093
 
 
2094
    // Switch back to normal cursor
 
2095
    XUndefineCursor( aStream->XDisplay, aStream->XWindow );
 
2096
    XFlush( aStream->XDisplay );
 
2097
}
 
2098
 
 
2099
#endif
 
2100
 
 
2101
 
 
2102
//--------------------------------------------------------------------------
 
2103
//--------------------------------------------------------------------------
 
2104
//
 
2105
// That which is specific to the cairo PDF driver.
 
2106
//
 
2107
//--------------------------------------------------------------------------
 
2108
//--------------------------------------------------------------------------
 
2109
 
 
2110
#if defined ( PLD_pdfcairo )
 
2111
 
 
2112
void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt );
 
2113
void plD_init_pdfcairo( PLStream * );
 
2114
 
 
2115
//--------------------------------------------------------------------------
 
2116
// dispatch_init_init()
 
2117
//
 
2118
// Initialize device dispatch table
 
2119
//--------------------------------------------------------------------------
 
2120
 
 
2121
// pdfcairo
 
2122
void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt )
 
2123
{
 
2124
#ifndef ENABLE_DYNDRIVERS
 
2125
    pdt->pl_MenuStr = "Cairo PDF Driver";
 
2126
    pdt->pl_DevName = "pdfcairo";
 
2127
#endif
 
2128
    pdt->pl_type     = plDevType_FileOriented;
 
2129
    pdt->pl_seq      = 101;
 
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;
 
2138
}
 
2139
 
 
2140
//--------------------------------------------------------------------------
 
2141
// plD_init_pdfcairo()
 
2142
//
 
2143
// Initialize Cairo PDF device
 
2144
//--------------------------------------------------------------------------
 
2145
 
 
2146
void plD_init_pdfcairo( PLStream *pls )
 
2147
{
 
2148
    PLCairo *aStream;
 
2149
 
 
2150
    // Setup the PLStream and the font lookup table
 
2151
    aStream = stream_and_font_setup( pls, 0 );
 
2152
 
 
2153
    // Prompt for a file name if not already set.
 
2154
    plOpenFile( pls );
 
2155
 
 
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 );
 
2160
 
 
2161
    // Save the pointer to the structure in the PLplot stream
 
2162
    pls->dev = aStream;
 
2163
 
 
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 );
 
2166
 
 
2167
    // Set graphics aliasing
 
2168
    cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
 
2169
 
 
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 );
 
2173
    else
 
2174
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
2175
}
 
2176
 
 
2177
#endif
 
2178
 
 
2179
 
 
2180
//--------------------------------------------------------------------------
 
2181
//--------------------------------------------------------------------------
 
2182
//
 
2183
// That which is specific to the cairo PS driver.
 
2184
//
 
2185
//--------------------------------------------------------------------------
 
2186
//--------------------------------------------------------------------------
 
2187
 
 
2188
#if defined ( PLD_pscairo )
 
2189
 
 
2190
void plD_dispatch_init_pscairo( PLDispatchTable *pdt );
 
2191
void plD_init_pscairo( PLStream * );
 
2192
 
 
2193
//--------------------------------------------------------------------------
 
2194
// dispatch_init_init()
 
2195
//
 
2196
// Initialize device dispatch table
 
2197
//--------------------------------------------------------------------------
 
2198
 
 
2199
// pscairo
 
2200
void plD_dispatch_init_pscairo( PLDispatchTable *pdt )
 
2201
{
 
2202
#ifndef ENABLE_DYNDRIVERS
 
2203
    pdt->pl_MenuStr = "Cairo PS Driver";
 
2204
    pdt->pl_DevName = "pscairo";
 
2205
#endif
 
2206
    pdt->pl_type     = plDevType_FileOriented;
 
2207
    pdt->pl_seq      = 102;
 
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;
 
2216
}
 
2217
 
 
2218
//--------------------------------------------------------------------------
 
2219
// plD_init_pscairo()
 
2220
//
 
2221
// Initialize Cairo PS device
 
2222
//--------------------------------------------------------------------------
 
2223
 
 
2224
void plD_init_pscairo( PLStream *pls )
 
2225
{
 
2226
    PLCairo *aStream;
 
2227
 
 
2228
    // Setup the PLStream and the font lookup table
 
2229
    aStream = stream_and_font_setup( pls, 0 );
 
2230
 
 
2231
    // Prompt for a file name if not already set.
 
2232
    plOpenFile( pls );
 
2233
 
 
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 );
 
2238
 
 
2239
    // Save the pointer to the structure in the PLplot stream
 
2240
    pls->dev = aStream;
 
2241
 
 
2242
    // Handle portrait or landscape
 
2243
    if ( pls->portrait )
 
2244
    {
 
2245
        plsdiori( 1 );
 
2246
        pls->freeaspect = 1;
 
2247
    }
 
2248
    rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, pls->ylength, pls->xlength, FALSE );
 
2249
 
 
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 );
 
2253
    else
 
2254
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
2255
}
 
2256
 
 
2257
#endif
 
2258
 
 
2259
 
 
2260
//--------------------------------------------------------------------------
 
2261
//--------------------------------------------------------------------------
 
2262
//
 
2263
// That which is specific to the cairo SVG driver.
 
2264
//
 
2265
//--------------------------------------------------------------------------
 
2266
//--------------------------------------------------------------------------
 
2267
 
 
2268
#if defined ( PLD_svgcairo )
 
2269
 
 
2270
void plD_dispatch_init_svgcairo( PLDispatchTable *pdt );
 
2271
void plD_init_svgcairo( PLStream * );
 
2272
 
 
2273
//--------------------------------------------------------------------------
 
2274
// dispatch_init_init()
 
2275
//
 
2276
// Initialize device dispatch table
 
2277
//--------------------------------------------------------------------------
 
2278
 
 
2279
// svgcairo
 
2280
void plD_dispatch_init_svgcairo( PLDispatchTable *pdt )
 
2281
{
 
2282
#ifndef ENABLE_DYNDRIVERS
 
2283
    pdt->pl_MenuStr = "Cairo SVG Driver";
 
2284
    pdt->pl_DevName = "svgcairo";
 
2285
#endif
 
2286
    pdt->pl_type     = plDevType_FileOriented;
 
2287
    pdt->pl_seq      = 103;
 
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;
 
2296
}
 
2297
 
 
2298
//--------------------------------------------------------------------------
 
2299
// plD_init_svgcairo()
 
2300
//
 
2301
// Initialize Cairo SVG device
 
2302
//--------------------------------------------------------------------------
 
2303
 
 
2304
void plD_init_svgcairo( PLStream *pls )
 
2305
{
 
2306
    PLCairo *aStream;
 
2307
 
 
2308
    // Setup the PLStream and the font lookup table and allocate a cairo
 
2309
    // stream structure.
 
2310
    //
 
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.
 
2318
    //
 
2319
    if ( pls->dev == NULL )
 
2320
    {
 
2321
        aStream = stream_and_font_setup( pls, 0 );
 
2322
    }
 
2323
    else
 
2324
    {
 
2325
        stream_and_font_setup( pls, 0 );
 
2326
        aStream = pls->dev;
 
2327
    }
 
2328
 
 
2329
    // Initialize family file info
 
2330
    plFamInit( pls );
 
2331
 
 
2332
    // Prompt for a file name if not already set.
 
2333
    plOpenFile( pls );
 
2334
 
 
2335
    // Save the pointer to the structure in the PLplot stream
 
2336
    pls->dev = aStream;
 
2337
 
 
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 );
 
2342
 
 
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 );
 
2345
 
 
2346
    // Set graphics aliasing
 
2347
    cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
 
2348
 
 
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 );
 
2352
    else
 
2353
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
2354
}
 
2355
 
 
2356
#endif
 
2357
 
 
2358
 
 
2359
//--------------------------------------------------------------------------
 
2360
//--------------------------------------------------------------------------
 
2361
//
 
2362
// That which is specific to the cairo PNG driver.
 
2363
//
 
2364
//--------------------------------------------------------------------------
 
2365
//--------------------------------------------------------------------------
 
2366
 
 
2367
#if defined ( PLD_pngcairo )
 
2368
 
 
2369
void plD_dispatch_init_pngcairo( PLDispatchTable *pdt );
 
2370
void plD_init_pngcairo( PLStream * );
 
2371
void plD_eop_pngcairo( PLStream * );
 
2372
 
 
2373
//--------------------------------------------------------------------------
 
2374
// dispatch_init_init()
 
2375
//
 
2376
// Initialize device dispatch table
 
2377
//--------------------------------------------------------------------------
 
2378
 
 
2379
// pngcairo
 
2380
void plD_dispatch_init_pngcairo( PLDispatchTable *pdt )
 
2381
{
 
2382
#ifndef ENABLE_DYNDRIVERS
 
2383
    pdt->pl_MenuStr = "Cairo PNG Driver";
 
2384
    pdt->pl_DevName = "pngcairo";
 
2385
#endif
 
2386
    pdt->pl_type     = plDevType_FileOriented;
 
2387
    pdt->pl_seq      = 104;
 
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;
 
2396
}
 
2397
 
 
2398
//--------------------------------------------------------------------------
 
2399
// plD_init_pngcairo()
 
2400
//
 
2401
// Initialize Cairo PNG device
 
2402
//--------------------------------------------------------------------------
 
2403
 
 
2404
void plD_init_pngcairo( PLStream *pls )
 
2405
{
 
2406
    PLCairo *aStream;
 
2407
 
 
2408
    // Setup the PLStream and the font lookup table and allocate a cairo
 
2409
    // stream structure.
 
2410
    //
 
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.
 
2418
    //
 
2419
    if ( pls->dev == NULL )
 
2420
    {
 
2421
        aStream = stream_and_font_setup( pls, 0 );
 
2422
    }
 
2423
    else
 
2424
    {
 
2425
        stream_and_font_setup( pls, 0 );
 
2426
        aStream = pls->dev;
 
2427
    }
 
2428
 
 
2429
    // Initialize family file info
 
2430
    plFamInit( pls );
 
2431
 
 
2432
    // Prompt for a file name if not already set.
 
2433
    plOpenFile( pls );
 
2434
 
 
2435
    // Save the pointer to the structure in the PLplot stream
 
2436
    pls->dev = aStream;
 
2437
 
 
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 );
 
2442
 
 
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 );
 
2445
 
 
2446
    // Set graphics aliasing
 
2447
    cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
 
2448
 
 
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 );
 
2452
    else
 
2453
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
2454
}
 
2455
 
 
2456
//--------------------------------------------------------------------------
 
2457
// plD_eop_pngcairo()
 
2458
//
 
2459
// PNG: End of page.
 
2460
//--------------------------------------------------------------------------
 
2461
 
 
2462
void plD_eop_pngcairo( PLStream *pls )
 
2463
{
 
2464
    PLCairo *aStream;
 
2465
 
 
2466
    aStream = (PLCairo *) pls->dev;
 
2467
    cairo_surface_write_to_png_stream( aStream->cairoSurface, (cairo_write_func_t) write_to_stream, pls->OutFile );
 
2468
}
 
2469
 
 
2470
#endif
 
2471
 
 
2472
 
 
2473
//--------------------------------------------------------------------------
 
2474
//--------------------------------------------------------------------------
 
2475
//
 
2476
// That which is specific to the cairo memory driver.
 
2477
//
 
2478
//--------------------------------------------------------------------------
 
2479
//--------------------------------------------------------------------------
 
2480
 
 
2481
#if defined ( PLD_memcairo )
 
2482
 
 
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 * );
 
2487
 
 
2488
//--------------------------------------------------------------------------
 
2489
// dispatch_init_init()
 
2490
//
 
2491
// Initialize device dispatch table
 
2492
//--------------------------------------------------------------------------
 
2493
 
 
2494
// memcairo
 
2495
void plD_dispatch_init_memcairo( PLDispatchTable *pdt )
 
2496
{
 
2497
#ifndef ENABLE_DYNDRIVERS
 
2498
    pdt->pl_MenuStr = "Cairo memory driver";
 
2499
    pdt->pl_DevName = "memcairo";
 
2500
#endif
 
2501
    pdt->pl_type     = plDevType_FileOriented;
 
2502
    pdt->pl_seq      = 105;
 
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;
 
2511
}
 
2512
 
 
2513
//--------------------------------------------------------------------------
 
2514
// plD_bop_memcairo()
 
2515
//
 
2516
// Set up for the next page.
 
2517
//--------------------------------------------------------------------------
 
2518
 
 
2519
void plD_bop_memcairo( PLStream *pls )
 
2520
{
 
2521
    // nothing to do here (we want to preserve the memory as it is)
 
2522
}
 
2523
 
 
2524
//--------------------------------------------------------------------------
 
2525
// plD_init_memcairo()
 
2526
//
 
2527
// Initialize Cairo memory device
 
2528
//--------------------------------------------------------------------------
 
2529
 
 
2530
void plD_init_memcairo( PLStream *pls )
 
2531
{
 
2532
    PLCairo       *aStream;
 
2533
    int           stride, i;
 
2534
    unsigned char *cairo_mem;
 
2535
    unsigned char *input_mem;
 
2536
 
 
2537
    // used for checking byte order
 
2538
    union
 
2539
    {
 
2540
        int  testWord;
 
2541
        char testByte[sizeof ( int )];
 
2542
    } endianTest;
 
2543
    endianTest.testWord = 1;
 
2544
 
 
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;
 
2549
 
 
2550
 
 
2551
    // Setup the PLStream and the font lookup table
 
2552
    aStream = stream_and_font_setup( pls, 0 );
 
2553
 
 
2554
    // Test byte order
 
2555
    if ( endianTest.testByte[0] == 1 )
 
2556
        aStream->bigendian = 0;
 
2557
    else
 
2558
        aStream->bigendian = 1;
 
2559
 
 
2560
    // Check that user supplied us with some memory to draw in
 
2561
    if ( pls->dev == NULL )
 
2562
    {
 
2563
        plexit( "Must call plsmem first to set user plotting area!" );
 
2564
    }
 
2565
 
 
2566
    // Save a pointer to the memory.
 
2567
    aStream->memory = pls->dev;
 
2568
 
 
2569
    // Create a cairo surface & context.  Copy data in from the input memory area
 
2570
 
 
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 );
 
2578
 
 
2579
    // Copy the input data into the Cairo data format
 
2580
    cairo_mem = aStream->cairo_format_memory;
 
2581
    input_mem = aStream->memory;
 
2582
 
 
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
 
2586
 
 
2587
    if ( aStream->bigendian )
 
2588
    {
 
2589
        for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
 
2590
        {
 
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 )
 
2595
            {
 
2596
                cairo_mem[0] = input_mem[3];
 
2597
                input_mem   += 4;
 
2598
            }
 
2599
            else
 
2600
            {
 
2601
                input_mem += 3;
 
2602
            }
 
2603
            cairo_mem += 4;
 
2604
        }
 
2605
    }
 
2606
    else
 
2607
    {
 
2608
        for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
 
2609
        {
 
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 )
 
2614
            {
 
2615
                cairo_mem[3] = input_mem[3];
 
2616
                input_mem   += 4;
 
2617
            }
 
2618
            else
 
2619
            {
 
2620
                input_mem += 3;
 
2621
            }
 
2622
            cairo_mem += 4;
 
2623
        }
 
2624
    }
 
2625
 
 
2626
    // Create a Cairo drawing surface from the input data
 
2627
    aStream->cairoSurface =
 
2628
        // Dimension units are width, height of buffer image from cairo
 
2629
        // documentation.
 
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 );
 
2632
 
 
2633
    // Save the pointer to the structure in the PLplot stream.
 
2634
    // Note that this wipes out the direct pointer to the memory buffer.
 
2635
    pls->dev = aStream;
 
2636
 
 
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 );
 
2639
 
 
2640
    // Set graphics aliasing
 
2641
    cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
 
2642
 
 
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 );
 
2646
    else
 
2647
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
2648
}
 
2649
 
 
2650
//--------------------------------------------------------------------------
 
2651
// plD_eop_memcairo()
 
2652
//
 
2653
// Memory device specific end of page. This copies the contents
 
2654
// of the cairo surface into the user supplied memory buffer.
 
2655
//--------------------------------------------------------------------------
 
2656
 
 
2657
void plD_eop_memcairo( PLStream *pls )
 
2658
{
 
2659
    int           i;
 
2660
    unsigned char *memory;
 
2661
    unsigned char *cairo_surface_data;
 
2662
    PLCairo       *aStream;
 
2663
 
 
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 )
 
2671
    {
 
2672
        for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
 
2673
        {
 
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 )
 
2678
            {
 
2679
                memory[3] = cairo_surface_data[0];
 
2680
                memory   += 4;
 
2681
            }
 
2682
            else
 
2683
            {
 
2684
                memory += 3;
 
2685
            }
 
2686
            cairo_surface_data += 4;
 
2687
        }
 
2688
    }
 
2689
    else
 
2690
    {
 
2691
        for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
 
2692
        {
 
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 )
 
2697
            {
 
2698
                memory[3] = cairo_surface_data[3];
 
2699
                memory   += 4;
 
2700
            }
 
2701
            else
 
2702
            {
 
2703
                memory += 3;
 
2704
            }
 
2705
            cairo_surface_data += 4;
 
2706
        }
 
2707
    }
 
2708
 
 
2709
    // Free up the temporary memory malloc'ed in plD_init_memcairo
 
2710
    free( aStream->cairo_format_memory );
 
2711
}
 
2712
 
 
2713
#endif
 
2714
 
 
2715
//--------------------------------------------------------------------------
 
2716
//--------------------------------------------------------------------------
 
2717
//
 
2718
// That which is specific to the cairo external context driver.
 
2719
//
 
2720
//--------------------------------------------------------------------------
 
2721
//--------------------------------------------------------------------------
 
2722
 
 
2723
#if defined ( PLD_extcairo )
 
2724
 
 
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 * );
 
2732
 
 
2733
//--------------------------------------------------------------------------
 
2734
// extcairo_setbackground()
 
2735
//
 
2736
// Set the background color for the extcairo device
 
2737
//--------------------------------------------------------------------------
 
2738
 
 
2739
void extcairo_setbackground( PLStream *pls )
 
2740
{
 
2741
    PLCairo *aStream;
 
2742
 
 
2743
    aStream = (PLCairo *) pls->dev;
 
2744
 
 
2745
    // Fill the context with the background color if the user so desires.
 
2746
    if ( aStream->cairoContext != NULL )
 
2747
    {
 
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 );
 
2755
    }
 
2756
}
 
2757
 
 
2758
//--------------------------------------------------------------------------
 
2759
// dispatch_init_init()
 
2760
//
 
2761
// Initialize device dispatch table
 
2762
//--------------------------------------------------------------------------
 
2763
 
 
2764
// extcairo
 
2765
void plD_dispatch_init_extcairo( PLDispatchTable *pdt )
 
2766
{
 
2767
#ifndef ENABLE_DYNDRIVERS
 
2768
    pdt->pl_MenuStr = "Cairo external context driver";
 
2769
    pdt->pl_DevName = "extcairo";
 
2770
#endif
 
2771
    pdt->pl_type     = plDevType_Interactive;
 
2772
    pdt->pl_seq      = 106;
 
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;
 
2781
}
 
2782
 
 
2783
//--------------------------------------------------------------------------
 
2784
// plD_init_extcairo()
 
2785
//
 
2786
// Initialize Cairo external context driver.
 
2787
//--------------------------------------------------------------------------
 
2788
 
 
2789
void plD_init_extcairo( PLStream *pls )
 
2790
{
 
2791
    PLCairo *aStream;
 
2792
 
 
2793
    // Setup the PLStream and the font lookup table
 
2794
    aStream = stream_and_font_setup( pls, 0 );
 
2795
 
 
2796
    // Save the pointer to the structure in the PLplot stream
 
2797
    pls->dev = aStream;
 
2798
}
 
2799
 
 
2800
//--------------------------------------------------------------------------
 
2801
// plD_bop_extcairo()
 
2802
//
 
2803
// Set up for the next page.
 
2804
//--------------------------------------------------------------------------
 
2805
 
 
2806
void plD_bop_extcairo( PLStream *pls )
 
2807
{
 
2808
    PLCairo *aStream;
 
2809
 
 
2810
    aStream = (PLCairo *) pls->dev;
 
2811
 
 
2812
    // Set background if desired
 
2813
    if ( aStream->set_background )
 
2814
    {
 
2815
        extcairo_setbackground( pls );
 
2816
    }
 
2817
}
 
2818
 
 
2819
//--------------------------------------------------------------------------
 
2820
// plD_eop_extcairo()
 
2821
//
 
2822
// End of page.
 
2823
//--------------------------------------------------------------------------
 
2824
 
 
2825
void plD_eop_extcairo( PLStream *pls )
 
2826
{
 
2827
    // nothing to do here, we leave it to the calling program to display
 
2828
    // (or not) the update cairo context.
 
2829
}
 
2830
 
 
2831
//--------------------------------------------------------------------------
 
2832
// plD_esc_extcairo()
 
2833
//
 
2834
// The generic escape function, extended so that user can pass in
 
2835
// an external Cairo context to use for rendering.
 
2836
//--------------------------------------------------------------------------
 
2837
 
 
2838
void plD_esc_extcairo( PLStream *pls, PLINT op, void *ptr )
 
2839
{
 
2840
    PLCairo *aStream;
 
2841
 
 
2842
    aStream = (PLCairo *) pls->dev;
 
2843
 
 
2844
    switch ( op )
 
2845
    {
 
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 );
 
2850
 
 
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 );
 
2853
 
 
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?
 
2856
 
 
2857
        // Set background if desired
 
2858
        if ( aStream->set_background )
 
2859
        {
 
2860
            extcairo_setbackground( pls );
 
2861
        }
 
2862
 
 
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 );
 
2866
        else
 
2867
            cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
2868
        break;
 
2869
    default: // Fall back on default Cairo actions
 
2870
        plD_esc_cairo( pls, op, ptr );
 
2871
        break;
 
2872
    }
 
2873
}
 
2874
 
 
2875
//--------------------------------------------------------------------------
 
2876
// plD_tidy_extcairo()
 
2877
//
 
2878
// This is nop, it is up to the calling program to clean up the Cairo
 
2879
// context, etc...
 
2880
//--------------------------------------------------------------------------
 
2881
 
 
2882
void plD_tidy_extcairo( PLStream *pls )
 
2883
{
 
2884
}
 
2885
 
 
2886
#endif
 
2887
 
 
2888
 
 
2889
//--------------------------------------------------------------------------
 
2890
//--------------------------------------------------------------------------
 
2891
//
 
2892
// That which is specific to the cairo microsoft windows driver.
 
2893
//
 
2894
// Much of the Windows specific code here was lifted from the wingcc
 
2895
// driver.
 
2896
//
 
2897
//--------------------------------------------------------------------------
 
2898
//--------------------------------------------------------------------------
 
2899
 
 
2900
#if defined ( PLD_wincairo )
 
2901
 
 
2902
static char* szWndClass = "PLplot WinCairo";
 
2903
 
 
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 * );
 
2910
 
 
2911
//--------------------------------------------------------------------------
 
2912
// blit_to_win()
 
2913
//
 
2914
// Blit the offscreen image to the Windows window.
 
2915
//--------------------------------------------------------------------------
 
2916
 
 
2917
void blit_to_win( PLCairo *aStream )
 
2918
{
 
2919
    cairo_set_source_surface( aStream->cairoContext_win, aStream->cairoSurface, 0.0, 0.0 );
 
2920
    cairo_paint( aStream->cairoContext_win );
 
2921
}
 
2922
 
 
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
//--------------------------------------------------------------------------
 
2928
 
 
2929
LRESULT CALLBACK PlplotCairoWndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
 
2930
{
 
2931
    PLStream *pls = NULL;
 
2932
    PLCairo  *dev = NULL;
 
2933
 
 
2934
//
 
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.
 
2942
//
 
2943
 
 
2944
    if ( nMsg == WM_CREATE )
 
2945
    {
 
2946
        return ( 0 );
 
2947
    }
 
2948
    else
 
2949
    {
 
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
 
2952
        {
 
2953
            dev = (PLCairo *) pls->dev;
 
2954
        }
 
2955
    }
 
2956
 
 
2957
//
 
2958
// Process the windows messages
 
2959
//
 
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
 
2965
//
 
2966
 
 
2967
    switch ( nMsg )
 
2968
    {
 
2969
    case WM_DESTROY:
 
2970
        //        if ( dev )
 
2971
        //            Debug( "WM_DESTROY\t" );
 
2972
        PostQuitMessage( 0 );
 
2973
        return ( 0 );
 
2974
        break;
 
2975
 
 
2976
    case WM_PAINT:
 
2977
        blit_to_win( dev );
 
2978
        return ( 1 );
 
2979
        break;
 
2980
 
 
2981
    case WM_SIZE:
 
2982
        GetClientRect( dev->hwnd, &dev->rect );
 
2983
        return ( 0 );
 
2984
        break;
 
2985
 
 
2986
    case WM_ENTERSIZEMOVE:
 
2987
        return ( 0 );
 
2988
        break;
 
2989
 
 
2990
    case WM_EXITSIZEMOVE:
 
2991
        return ( 0 );
 
2992
        break;
 
2993
 
 
2994
    case WM_ERASEBKGND:
 
2995
        if ( dev )
 
2996
        {
 
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 );
 
3000
        }
 
3001
        return ( 1 );
 
3002
        break;
 
3003
 
 
3004
    case WM_COMMAND:
 
3005
        return ( 0 );
 
3006
        break;
 
3007
    }
 
3008
 
 
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 );
 
3012
}
 
3013
 
 
3014
//--------------------------------------------------------------------------
 
3015
// handle_locate()
 
3016
//
 
3017
// Handle getting the cursor location.
 
3018
//--------------------------------------------------------------------------
 
3019
 
 
3020
void
 
3021
handle_locate( PLStream *pls, PLGraphicsIn *gin )
 
3022
{
 
3023
    int     located  = 0;
 
3024
    PLCairo *aStream = (PLCairo *) pls->dev;
 
3025
 
 
3026
    // Initialize PLplot mouse event structure
 
3027
    plGinInit( gin );
 
3028
 
 
3029
    while ( GetMessage( &aStream->msg, NULL, 0, 0 ) && !located )
 
3030
    {
 
3031
        TranslateMessage( &aStream->msg );
 
3032
 
 
3033
        switch ( (int) aStream->msg.message )
 
3034
        {
 
3035
        case WM_MOUSEMOVE:
 
3036
        case WM_LBUTTONDOWN:
 
3037
            gin->state  = 1;
 
3038
            gin->button = 1;
 
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 );
 
3043
            break;
 
3044
        case WM_CHAR:
 
3045
            gin->keysym = aStream->msg.wParam;
 
3046
            located     = 1;
 
3047
            break;
 
3048
 
 
3049
        default:
 
3050
            DispatchMessage( &aStream->msg );
 
3051
            break;
 
3052
        }
 
3053
    }
 
3054
}
 
3055
 
 
3056
//--------------------------------------------------------------------------
 
3057
// dispatch_init_init()
 
3058
//
 
3059
// Initialize device dispatch table
 
3060
//--------------------------------------------------------------------------
 
3061
 
 
3062
// extcairo
 
3063
void plD_dispatch_init_wincairo( PLDispatchTable *pdt )
 
3064
{
 
3065
#ifndef ENABLE_DYNDRIVERS
 
3066
    pdt->pl_MenuStr = "Cairo Microsoft Windows driver";
 
3067
    pdt->pl_DevName = "wincairo";
 
3068
#endif
 
3069
    pdt->pl_type     = plDevType_Interactive;
 
3070
    pdt->pl_seq      = 107;
 
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;
 
3079
}
 
3080
 
 
3081
//--------------------------------------------------------------------------
 
3082
// plD_init_wincairo()
 
3083
//
 
3084
// Initialize Cairo Microsoft Windows driver.
 
3085
//--------------------------------------------------------------------------
 
3086
 
 
3087
void plD_init_wincairo( PLStream *pls )
 
3088
{
 
3089
    PLCairo *aStream;
 
3090
 
 
3091
    // Setup the PLStream and the font lookup table
 
3092
    aStream = stream_and_font_setup( pls, 1 );
 
3093
 
 
3094
    // Save the pointer to the structure in the PLplot stream
 
3095
    pls->dev = aStream;
 
3096
 
 
3097
    // Create window
 
3098
    memset( &aStream->wndclass, 0, sizeof ( WNDCLASSEX ) );
 
3099
 
 
3100
    // This class is called WinTestWin
 
3101
    aStream->wndclass.lpszClassName = szWndClass;
 
3102
 
 
3103
    // cbSize gives the size of the structure for extensibility.
 
3104
    aStream->wndclass.cbSize = sizeof ( WNDCLASSEX );
 
3105
 
 
3106
    // All windows of this class redraw when resized.
 
3107
    aStream->wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC | CS_PARENTDC;
 
3108
 
 
3109
    // All windows of this class use the PlplotCairoWndProc window function.
 
3110
    aStream->wndclass.lpfnWndProc = PlplotCairoWndProc;
 
3111
 
 
3112
    // This class is used with the current program instance.
 
3113
 
 
3114
    aStream->wndclass.hInstance = GetModuleHandle( NULL );
 
3115
 
 
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;
 
3122
 
 
3123
    aStream->wndclass.cbWndExtra = sizeof ( pls );
 
3124
 
 
3125
 
 
3126
    //
 
3127
    // Now register the window class for use.
 
3128
    //
 
3129
 
 
3130
    RegisterClassEx( &aStream->wndclass );
 
3131
 
 
3132
    //
 
3133
    // Create our main window using that window class.
 
3134
    //
 
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
 
3145
        NULL,                                               // No menu
 
3146
        aStream->wndclass.hInstance,                        // This program instance
 
3147
        NULL                                                // Creation parameters
 
3148
        );
 
3149
 
 
3150
 
 
3151
//
 
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
 
3155
//
 
3156
 
 
3157
    SetWindowLong( aStream->hwnd, GWL_USERDATA, (long) pls );
 
3158
    aStream->SCRN_hdc = aStream->hdc = GetDC( aStream->hwnd );
 
3159
 
 
3160
//
 
3161
//  Setup the popup menu
 
3162
//
 
3163
 
 
3164
//
 
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" );
 
3169
//
 
3170
 
 
3171
    //    plD_state_wingcc( pls, PLSTATE_COLOR0 );
 
3172
    //
 
3173
    // Display the window which we just created (using the nShow
 
3174
    // passed by the OS, which allows for start minimized and that
 
3175
    // sort of thing).
 
3176
    //
 
3177
    ShowWindow( aStream->hwnd, SW_SHOWDEFAULT );
 
3178
    SetForegroundWindow( aStream->hwnd );
 
3179
 
 
3180
//
 
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
 
3185
//
 
3186
 
 
3187
//
 
3188
//  GetClientRect( dev->hwnd, &dev->rect );
 
3189
//  dev->width  = dev->rect.right;
 
3190
//  dev->height = dev->rect.bottom;
 
3191
//
 
3192
 
 
3193
//
 
3194
// Initialize Cairo Surface using the windows hdc.
 
3195
//
 
3196
 
 
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 );
 
3200
 
 
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 );
 
3204
 
 
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 );
 
3207
 
 
3208
    // Set graphics aliasing
 
3209
    cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
 
3210
 
 
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 );
 
3214
    else
 
3215
        cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
 
3216
}
 
3217
 
 
3218
//--------------------------------------------------------------------------
 
3219
// plD_eop_wincairo()
 
3220
//
 
3221
// Clean up Cairo Microsoft Windows driver.
 
3222
//--------------------------------------------------------------------------
 
3223
 
 
3224
void
 
3225
plD_eop_wincairo( PLStream *pls )
 
3226
{
 
3227
    PLCairo *aStream = (PLCairo *) pls->dev;
 
3228
 
 
3229
    if ( !pls->nopause )
 
3230
    {
 
3231
        while ( GetMessage( &aStream->msg, NULL, 0, 0 ) )
 
3232
        {
 
3233
            TranslateMessage( &aStream->msg );
 
3234
            switch ( (int) aStream->msg.message )
 
3235
            {
 
3236
            case WM_CHAR:
 
3237
                if ( ( (TCHAR) ( aStream->msg.wParam ) == 13 ) ||
 
3238
                     ( (TCHAR) ( aStream->msg.wParam ) == 'q' ) ||
 
3239
                     ( (TCHAR) ( aStream->msg.wParam ) == 'Q' ) )
 
3240
                {
 
3241
                    PostQuitMessage( 0 );
 
3242
                }
 
3243
                break;
 
3244
 
 
3245
            default:
 
3246
                DispatchMessage( &aStream->msg );
 
3247
                break;
 
3248
            }
 
3249
        }
 
3250
    }
 
3251
}
 
3252
 
 
3253
//--------------------------------------------------------------------------
 
3254
// plD_tidy_wincairo()
 
3255
//
 
3256
// Clean up Cairo Microsoft Windows driver.
 
3257
//--------------------------------------------------------------------------
 
3258
 
 
3259
void plD_tidy_wincairo( PLStream *pls )
 
3260
{
 
3261
    PLCairo *aStream = (PLCairo *) pls->dev;
 
3262
 
 
3263
    plD_tidy_cairo( pls );
 
3264
 
 
3265
    // Also free up the Cairo win32 surface and context
 
3266
    cairo_destroy( aStream->cairoContext_win );
 
3267
    cairo_surface_destroy( aStream->cairoSurface_win );
 
3268
 
 
3269
    if ( aStream != NULL )
 
3270
    {
 
3271
        if ( aStream->hdc != NULL )
 
3272
            ReleaseDC( aStream->hwnd, aStream->hdc );
 
3273
        free_mem( pls->dev );
 
3274
    }
 
3275
}
 
3276
 
 
3277
//--------------------------------------------------------------------------
 
3278
// plD_esc_wincairo()
 
3279
//
 
3280
// Escape function, specialized for the wincairo driver
 
3281
//--------------------------------------------------------------------------
 
3282
 
 
3283
void plD_esc_wincairo( PLStream *pls, PLINT op, void *ptr )
 
3284
{
 
3285
    PLCairo *aStream;
 
3286
 
 
3287
    aStream = (PLCairo *) pls->dev;
 
3288
 
 
3289
    switch ( op )
 
3290
    {
 
3291
    case PLESC_FLUSH:
 
3292
        InvalidateRect( aStream->hwnd, NULL, TRUE );
 
3293
        break;
 
3294
    case PLESC_GETC:
 
3295
        handle_locate( pls, (PLGraphicsIn *) ptr );
 
3296
        break;
 
3297
    default:
 
3298
        plD_esc_cairo( pls, op, ptr );
 
3299
        break;
 
3300
    }
 
3301
}
 
3302
 
 
3303
#endif