PLplot  5.10.0
cairo.c
Go to the documentation of this file.
00001 // June 2, 2007
00002 //
00003 // Graphics drivers that are based on the Cairo / Pango Libraries.
00004 //
00005 // Copyright (C) 2008 Hazen Babcock
00006 // Copyright (C) 2009, 2010 Hezekiah M. Carty
00007 //
00008 // This file is part of PLplot.
00009 //
00010 // PLplot is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Library General Public License as published
00012 // by the Free Software Foundation; either version 2 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // PLplot is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Library General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Library General Public License
00021 // along with PLplot; if not, write to the Free Software
00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023 //
00024 //
00025 
00026 //--------------------------------------------------------------------------
00027 // Header files
00028 //--------------------------------------------------------------------------
00029 
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <math.h>
00033 
00034 #include <cairo.h>
00035 #include <pango/pangocairo.h>
00036 
00037 // PLplot header files (must occur before driver-dependent includes)
00038 
00039 #include "plDevs.h"
00040 #include "plplotP.h"
00041 #include "drivers.h"
00042 
00043 // Driver-dependent includes
00044 #if defined ( PLD_wincairo )
00045 #include <windows.h>
00046 #endif
00047 #if defined ( PLD_xcairo )
00048 #include <cairo-xlib.h>
00049 #include <X11/X.h>
00050 #include <X11/Xlib.h>
00051 #include <X11/Xutil.h>
00052 #include <X11/cursorfont.h>
00053 #include <X11/keysym.h>
00054 #endif
00055 #if defined ( PLD_pdfcairo )
00056 #include <cairo-pdf.h>
00057 #endif
00058 #if defined ( PLD_pscairo )
00059 #include <cairo-ps.h>
00060 #endif
00061 #if defined ( PLD_svgcairo )
00062 #include <cairo-svg.h>
00063 #endif
00064 
00065 
00066 //--------------------------------------------------------------------------
00067 // Constants & global (to this file) variables
00068 //--------------------------------------------------------------------------
00069 
00070 #define DPI                  72
00071 #define PLCAIRO_DEFAULT_X    720
00072 #define PLCAIRO_DEFAULT_Y    540
00073 
00074 #define MAX_STRING_LEN       500
00075 #define MAX_MARKUP_LEN       MAX_STRING_LEN * 10
00076 
00077 static int    text_clipping;
00078 static int    text_anti_aliasing;
00079 static int    graphics_anti_aliasing;
00080 static int    external_drawable;
00081 static int    rasterize_image;
00082 static int    set_background;
00083 static int    image_buffering;
00084 static int    already_warned = 0;
00085 
00086 static DrvOpt cairo_options[] = { { "text_clipping",          DRV_INT, &text_clipping,          "Use text clipping (text_clipping=0|1)"                                                                                                                                                                                          },
00087                                   { "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)"        },
00088                                   { "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" },
00089                                   { "external_drawable",      DRV_INT, &external_drawable,      "Plot to external X drawable"                                                                                                                                                                                                    },
00090                                   { "rasterize_image",        DRV_INT, &rasterize_image,        "Raster or vector image rendering (rasterize_image=0|1)"                                                                                                                                                                         },
00091                                   { "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"                                                                                                              },
00092                                   { "image_buffering",        DRV_INT, &image_buffering,        "Buffered offscreen rendering for the xcairo device (image_buffering=0|1)."                                                                                                                                                      },
00093                                   { NULL,                     DRV_INT, NULL,                    NULL                                                                                                                                                                                                                             } };
00094 
00095 typedef struct
00096 {
00097     cairo_surface_t *cairoSurface;
00098     cairo_t         *cairoContext;
00099     cairo_surface_t *cairoSurface_raster;
00100     cairo_t         *cairoContext_raster;
00101     short           text_clipping;
00102     short           text_anti_aliasing;
00103     short           graphics_anti_aliasing;
00104     short           rasterize_image;
00105     short           set_background;
00106     short           image_buffering;
00107     double          downscale;
00108     char            *pangoMarkupString;
00109     short           upDown;
00110     float           fontSize;
00111     short           uline;
00112 
00113     // These are arguments for plP_script_scale which must be retained
00114     // in aStream for the alt_unicode approach.  level has an
00115     // identical meaning to upDown above, but it is incremented and
00116     // decremented in plP_script_scale as well as other places in the
00117     // code so the only safe thing to do is to treat level separately
00118     // from upDown.
00119     PLFLT           old_sscale, sscale, old_soffset, soffset;
00120     PLINT           level;
00121 
00122 #if defined ( PLD_xcairo )
00123     cairo_surface_t *cairoSurface_X;
00124     cairo_t         *cairoContext_X;
00125     short           exit_event_loop;
00126     Display         *XDisplay;
00127     Window          XWindow;
00128     unsigned int    xdrawable_mode;
00129 #endif
00130 #if defined ( PLD_memcairo )
00131     unsigned char   *memory;
00132     unsigned char   *cairo_format_memory;
00133     char            bigendian;
00134 #endif
00135 #if defined ( PLD_wincairo )
00136     cairo_surface_t *cairoSurface_win;
00137     cairo_t         *cairoContext_win;
00138     WNDCLASSEX      wndclass;
00139     HWND            hwnd;
00140     MSG             msg;
00141     HDC             hdc;
00142     HDC             SCRN_hdc;
00143     COLORREF        oldcolour;
00144     RECT            rect;
00145 #endif
00146 } PLCairo;
00147 
00148 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_cairo =
00149 #if defined ( PLD_xcairo )
00150     "xcairo:Cairo X Windows Driver:1:cairo:100:xcairo\n"
00151 #endif
00152 #if defined ( PLD_pdfcairo )
00153     "pdfcairo:Cairo PDF Driver:0:cairo:101:pdfcairo\n"
00154 #endif
00155 #if defined ( PLD_pscairo )
00156     "pscairo:Cairo PS Driver:0:cairo:102:pscairo\n"
00157 #endif
00158 #if defined ( PLD_epscairo )
00159     "epscairo:Cairo EPS Driver:0:cairo:103:epscairo\n"
00160 #endif
00161 #if defined ( PLD_svgcairo )
00162     "svgcairo:Cairo SVG Driver:0:cairo:104:svgcairo\n"
00163 #endif
00164 #if defined ( PLD_pngcairo )
00165     "pngcairo:Cairo PNG Driver:0:cairo:105:pngcairo\n"
00166 #endif
00167 #if defined ( PLD_memcairo )
00168     "memcairo:Cairo Memory Driver:0:cairo:106:memcairo\n"
00169 #endif
00170 #if defined ( PLD_extcairo )
00171     "extcairo:Cairo External Context Driver:0:cairo:107:extcairo\n"
00172 #endif
00173 #if defined ( PLD_wincairo )
00174     "wincairo:Cairo Microscoft Windows Driver:0:cairo:108:wincairo\n"
00175 #endif
00176 ;
00177 
00178 //
00179 // Structure for passing external drawables to xcairo devices via
00180 // the PLESC_DEVINIT escape function.
00181 //
00182 #if defined ( PLD_xcairo )
00183 typedef struct
00184 {
00185     Display  *display;
00186     Drawable drawable;
00187 } PLXcairoDrawableInfo;
00188 #endif
00189 
00190 //--------------------------------------------------------------------------
00191 // Font style and weight lookup tables (copied
00192 // from the psttf driver).
00193 //--------------------------------------------------------------------------
00194 
00195 #define NPANGOLOOKUP    5
00196 
00197 const char *defaultFamilyLookup[NPANGOLOOKUP] = {
00198     "sans",
00199     "serif",
00200     "monospace",
00201     "sans,serif",
00202     "sans,serif"
00203 };
00204 
00205 const char *envFamilyLookup[NPANGOLOOKUP] = {
00206     "PLPLOT_FREETYPE_SANS_FAMILY",
00207     "PLPLOT_FREETYPE_SERIF_FAMILY",
00208     "PLPLOT_FREETYPE_MONO_FAMILY",
00209     "PLPLOT_FREETYPE_SCRIPT_FAMILY",
00210     "PLPLOT_FREETYPE_SYMBOL_FAMILY"
00211 };
00212 
00213 #define FAMILY_LOOKUP_LEN    1024
00214 char familyLookup[NPANGOLOOKUP][FAMILY_LOOKUP_LEN];
00215 
00216 #define TAG_LEN              200
00217 
00218 const char *weightLookup[2] = {
00219     "normal",
00220     "bold"
00221 };
00222 
00223 const char *styleLookup[3] = {
00224     "normal",
00225     "italic",
00226     "oblique"
00227 };
00228 
00229 //--------------------------------------------------------------------------
00230 //--------------------------------------------------------------------------
00231 //
00232 // That which is common to all the Cairo Drivers
00233 //
00234 //--------------------------------------------------------------------------
00235 //--------------------------------------------------------------------------
00236 
00237 //--------------------------------------------------------------------------
00238 // function declarations
00239 //--------------------------------------------------------------------------
00240 
00241 // General
00242 
00243 PLCairo *stream_and_font_setup( PLStream *, int );
00244 cairo_status_t write_to_stream( void *, unsigned char *, unsigned int );
00245 void set_clip( PLStream *pls );
00246 int cairo_family_check( PLStream *pls );
00247 
00248 // String processing
00249 
00250 static void proc_str( PLStream *, EscText * );
00251 static void text_begin_cairo( PLStream *pls, EscText *args );
00252 static void text_char_cairo( PLStream *pls, EscText *args );
00253 static void text_esc_cairo( PLStream *pls, EscText *args );
00254 static void text_end_cairo( PLStream *pls, EscText *args );
00255 static char *ucs4_to_pango_markup_format( PLUNICODE *, int, float );
00256 static void open_span_tag( char *, PLUNICODE, float, int );
00257 static void close_span_tag( char *, int );
00258 static char *rise_span_tag( int, float, float, float );
00259 
00260 // Graphics
00261 
00262 static void set_current_context( PLStream * );
00263 static void poly_line( PLStream *, short *, short *, PLINT );
00264 static void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts );
00265 static void gradient( PLStream *pls, short *xa, short *ya, PLINT npts );
00266 static void arc( PLStream *, arc_struct * );
00267 static void rotate_cairo_surface( PLStream *, float, float, float, float, float, float, PLBOOL );
00268 static void blit_to_x( PLStream *pls, double x, double y, double w, double h );
00269 // Rasterization of plotted material
00270 static void start_raster( PLStream* );
00271 static void end_raster( PLStream* );
00272 // Get/set drawing mode
00273 static void set_mode( PLStream*, PLINT* );
00274 static void get_mode( PLStream*, PLINT* );
00275 // Get / set line properties
00276 void get_line_properties( PLCairo *aStream, cairo_line_join_t *join, cairo_line_cap_t *cap );
00277 void set_line_properties( PLCairo *aStream, cairo_line_join_t join, cairo_line_cap_t cap );
00278 
00279 
00280 // PLplot interface functions
00281 
00282 // general
00283 void plD_bop_cairo( PLStream * );
00284 void plD_eop_cairo( PLStream * );
00285 void plD_state_cairo( PLStream *, PLINT );
00286 void plD_esc_cairo( PLStream *, PLINT, void * );
00287 void plD_tidy_cairo( PLStream * );
00288 void plD_line_cairo( PLStream *, short, short, short, short );
00289 void plD_polyline_cairo( PLStream *, short *, short *, PLINT );
00290 
00291 //--------------------------------------------------------------------------
00292 // start_raster()
00293 //
00294 // Set up off-screen rasterized rendering
00295 //--------------------------------------------------------------------------
00296 
00297 void start_raster( PLStream *pls )
00298 {
00299     PLCairo         *aStream;
00300     cairo_surface_t *tmp_sfc;
00301     cairo_t         *tmp_context;
00302 
00303     aStream = (PLCairo *) pls->dev;
00304 
00305     // Do not use the external surface if the user says not to
00306     if ( !aStream->rasterize_image )
00307         return;
00308 
00309     // Create an image surface and context for the offscreen rendering
00310     aStream->cairoSurface_raster =
00311         //
00312         //  cairo_surface_create_similar( aStream->cairoSurface,
00313         //                                CAIRO_CONTENT_COLOR,
00314         //                                pls->xlength, pls->ylength );
00315         //
00316         cairo_image_surface_create( CAIRO_FORMAT_ARGB32,
00317             pls->xlength, pls->ylength );
00318     aStream->cairoContext_raster = cairo_create( aStream->cairoSurface_raster );
00319 
00320     // Disable antialiasing for the raster surface.  The output seems to look
00321     // better that way.
00322     cairo_set_antialias( aStream->cairoContext_raster, CAIRO_ANTIALIAS_NONE );
00323 
00324     // Swap the raster and main plot surfaces and contexts
00325     tmp_sfc               = aStream->cairoSurface;
00326     tmp_context           = aStream->cairoContext;
00327     aStream->cairoSurface = aStream->cairoSurface_raster;
00328     aStream->cairoContext = aStream->cairoContext_raster;
00329     // Save the main plot surface and context for when we are finished
00330     aStream->cairoSurface_raster = tmp_sfc;
00331     aStream->cairoContext_raster = tmp_context;
00332 }
00333 
00334 //--------------------------------------------------------------------------
00335 // end_raster()
00336 //
00337 // Finish off-screen rasterized rendering and copy the result on to the
00338 // main plot surface.
00339 //--------------------------------------------------------------------------
00340 
00341 void end_raster( PLStream *pls )
00342 {
00343     PLCairo         *aStream;
00344     cairo_surface_t *tmp_sfc;
00345     cairo_t         *tmp_context;
00346 
00347     aStream = (PLCairo *) pls->dev;
00348 
00349     // TODO FIXME: This should really only copy the used portion of the
00350     // offscreen pixmap.
00351 
00352     // Do not use the external surface if the user says not to
00353     if ( !aStream->rasterize_image )
00354         return;
00355 
00356     // Some Cairo devices support delayed device setup (eg: xcairo with
00357     // external drawable and extcairo with an external context).
00358     if ( aStream->cairoContext == NULL )
00359         plexit( "Can not plot to a Cairo device with no context" );
00360 
00361     // Restore the main plot surface and context for future plotting
00362     tmp_sfc                      = aStream->cairoSurface;
00363     tmp_context                  = aStream->cairoContext;
00364     aStream->cairoSurface        = aStream->cairoSurface_raster;
00365     aStream->cairoContext        = aStream->cairoContext_raster;
00366     aStream->cairoSurface_raster = tmp_sfc;
00367     aStream->cairoContext_raster = tmp_context;
00368 
00369     // Blit the raster surface on to the main plot
00370     cairo_set_source_surface( aStream->cairoContext, aStream->cairoSurface_raster, 0.0, 0.0 );
00371     cairo_paint( aStream->cairoContext );
00372 
00373     // Free the now extraneous surface and context
00374     cairo_destroy( aStream->cairoContext_raster );
00375     cairo_surface_destroy( aStream->cairoSurface_raster );
00376 }
00377 
00378 //--------------------------------------------------------------------------
00379 // plD_bop_cairo()
00380 //
00381 // Set up for the next page.
00382 //--------------------------------------------------------------------------
00383 
00384 void plD_bop_cairo( PLStream *pls )
00385 {
00386     PLCairo *aStream;
00387 
00388     aStream = (PLCairo *) pls->dev;
00389 
00390     // Some Cairo devices support delayed device setup (eg: xcairo with
00391     // external drawable and extcairo with an external context).
00392     if ( aStream->cairoContext == NULL )
00393         return;
00394 
00395     // Fill in the window with the background color.
00396     cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
00397     if ( (double) pls->cmap0[0].a < 1.0 )
00398     {
00399         cairo_set_source_rgba( aStream->cairoContext, 1.0, 1.0, 1.0, 1.0 );
00400         cairo_fill_preserve( aStream->cairoContext );
00401     }
00402     cairo_set_source_rgba( aStream->cairoContext,
00403         (double) pls->cmap0[0].r / 255.0,
00404         (double) pls->cmap0[0].g / 255.0,
00405         (double) pls->cmap0[0].b / 255.0,
00406         (double) pls->cmap0[0].a );
00407     cairo_fill( aStream->cairoContext );
00408 }
00409 
00410 //--------------------------------------------------------------------------
00411 // plD_line_cairo()
00412 //
00413 // Draw a line in the current color from (x1,y1) to (x2,y2).
00414 //--------------------------------------------------------------------------
00415 
00416 //--------------------------------------------------------------------------
00417 // (get|set)_line_properties
00418 //
00419 // (Get|Set) the current Cairo line drawing properties.
00420 //--------------------------------------------------------------------------
00421 void get_line_properties( PLCairo *aStream, cairo_line_join_t *join, cairo_line_cap_t *cap )
00422 {
00423     *join = cairo_get_line_join( aStream->cairoContext );
00424     *cap  = cairo_get_line_cap( aStream->cairoContext );
00425 }
00426 
00427 void set_line_properties( PLCairo *aStream, cairo_line_join_t join, cairo_line_cap_t cap )
00428 {
00429     cairo_set_line_join( aStream->cairoContext, join );
00430     cairo_set_line_cap( aStream->cairoContext, cap );
00431 }
00432 
00433 void plD_line_cairo( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
00434 {
00435     PLCairo *aStream;
00436 
00437     aStream = (PLCairo *) pls->dev;
00438 
00439     set_current_context( pls );
00440 
00441     cairo_save( aStream->cairoContext );
00442 
00443     set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_ROUND );
00444 
00445     cairo_move_to( aStream->cairoContext, aStream->downscale * (double) x1a, aStream->downscale * (double) y1a );
00446     cairo_line_to( aStream->cairoContext, aStream->downscale * (double) x2a, aStream->downscale * (double) y2a );
00447 
00448     cairo_stroke( aStream->cairoContext );
00449 
00450     cairo_restore( aStream->cairoContext );
00451 }
00452 
00453 //--------------------------------------------------------------------------
00454 // plD_polyline_cairo()
00455 //
00456 // Draw a polyline in the current color.
00457 //--------------------------------------------------------------------------
00458 
00459 void plD_polyline_cairo( PLStream *pls, short *xa, short *ya, PLINT npts )
00460 {
00461     PLCairo *aStream;
00462 
00463     aStream = (PLCairo *) pls->dev;
00464 
00465     cairo_save( aStream->cairoContext );
00466 
00467     set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
00468 
00469     poly_line( pls, xa, ya, npts );
00470 
00471     cairo_stroke( aStream->cairoContext );
00472 
00473     cairo_restore( aStream->cairoContext );
00474 }
00475 
00476 //--------------------------------------------------------------------------
00477 // plD_eop_cairo()
00478 //
00479 // Generic end of page.
00480 //--------------------------------------------------------------------------
00481 
00482 void plD_eop_cairo( PLStream *pls )
00483 {
00484     PLCairo *aStream;
00485 
00486     aStream = (PLCairo *) pls->dev;
00487 
00488     cairo_show_page( aStream->cairoContext );
00489 }
00490 
00491 //--------------------------------------------------------------------------
00492 // plD_tidy_cairo()
00493 //
00494 // General: Close graphics file or otherwise clean up.
00495 //--------------------------------------------------------------------------
00496 
00497 void plD_tidy_cairo( PLStream *pls )
00498 {
00499     PLCairo *aStream;
00500 
00501     aStream = (PLCairo *) pls->dev;
00502 
00503     // Free the cairo context and surface.
00504     cairo_destroy( aStream->cairoContext );
00505     cairo_surface_destroy( aStream->cairoSurface );
00506 
00507     plCloseFile( pls );
00508 }
00509 
00510 //--------------------------------------------------------------------------
00511 // plD_state_cairo()
00512 //
00513 // Handle change in PLStream state (color, pen width, fill attribute, etc).
00514 //
00515 // Nothing is done here because these attributes are acquired from
00516 // PLStream for each element that is drawn.
00517 //--------------------------------------------------------------------------
00518 
00519 void plD_state_cairo( PLStream * PL_UNUSED( pls ), PLINT PL_UNUSED( op ) )
00520 {
00521 }
00522 
00523 //--------------------------------------------------------------------------
00524 // plD_esc_cairo()
00525 //
00526 // Generic escape function.
00527 //--------------------------------------------------------------------------
00528 
00529 void plD_esc_cairo( PLStream *pls, PLINT op, void *ptr )
00530 {
00531     //PLCairo *aStream;
00532 
00533     //aStream = (PLCairo *) pls->dev;
00534 
00535     switch ( op )
00536     {
00537     case PLESC_FILL:     // filled polygon
00538         filled_polygon( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
00539         break;
00540     case PLESC_GRADIENT:     // render a gradient within a polygon.
00541         gradient( pls, pls->dev_x, pls->dev_y, pls->dev_npts );
00542         break;
00543     case PLESC_HAS_TEXT:
00544         if ( !pls->alt_unicode )
00545         {
00546             proc_str( pls, (EscText *) ptr );
00547         }
00548         break;
00549     case PLESC_BEGIN_TEXT: // get ready to get a handle a string of text
00550         text_begin_cairo( pls, (EscText *) ptr );
00551         break;
00552     case PLESC_TEXT_CHAR: // handle a character of text to display
00553         text_char_cairo( pls, (EscText *) ptr );
00554         break;
00555     case PLESC_CONTROL_CHAR: // handle a control character (super/subscript of fontchange)
00556         text_esc_cairo( pls, (EscText *) ptr );
00557         break;
00558     case PLESC_END_TEXT: // finish a string of text
00559         text_end_cairo( pls, (EscText *) ptr );
00560         break;
00561     case PLESC_START_RASTERIZE: // Start offscreen/rasterized rendering
00562         start_raster( pls );
00563         break;
00564     case PLESC_END_RASTERIZE: // End offscreen/rasterized rendering
00565         end_raster( pls );
00566         break;
00567     case PLESC_ARC: // Draw an arc, either filled or outline
00568         arc( pls, (arc_struct *) ptr );
00569         break;
00570     case PLESC_MODESET: // Set drawing mode
00571         set_mode( pls, (int *) ptr );
00572         break;
00573     case PLESC_MODEGET: // Get drawing mode
00574         get_mode( pls, (int *) ptr );
00575         break;
00576     }
00577 }
00578 
00579 
00580 //--------------------------------------------------------------------------
00581 // set_mode
00582 //
00583 // Set drawing mode.
00584 //--------------------------------------------------------------------------
00585 void set_mode( PLStream *pls, PLINT *mode )
00586 {
00587     PLCairo *aStream;
00588 
00589     aStream = (PLCairo *) pls->dev;
00590 
00591     switch ( *mode )
00592     {
00593     case PL_DRAWMODE_UNKNOWN: // Invalid - do nothing
00594         break;
00595     case PL_DRAWMODE_DEFAULT:
00596         cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_OVER );
00597         break;
00598     case PL_DRAWMODE_REPLACE:
00599         cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_SOURCE );
00600         break;
00601     case PL_DRAWMODE_XOR:
00602         cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_XOR );
00603         break;
00604     }
00605     return;
00606 }
00607 
00608 //--------------------------------------------------------------------------
00609 // get_mode
00610 //
00611 // Get drawing mode.
00612 //--------------------------------------------------------------------------
00613 void get_mode( PLStream *pls, PLINT *mode )
00614 {
00615     PLCairo          *aStream;
00616     cairo_operator_t op;
00617 
00618     aStream = (PLCairo *) pls->dev;
00619 
00620     op = cairo_get_operator( aStream->cairoContext );
00621 
00622     switch ( op )
00623     {
00624     case CAIRO_OPERATOR_OVER:
00625         *mode = PL_DRAWMODE_DEFAULT;
00626         break;
00627     case CAIRO_OPERATOR_SOURCE:
00628         *mode = PL_DRAWMODE_REPLACE;
00629         break;
00630     case CAIRO_OPERATOR_XOR:
00631         *mode = PL_DRAWMODE_XOR;
00632         break;
00633     default:
00634         *mode = PL_DRAWMODE_UNKNOWN;
00635     }
00636     return;
00637 }
00638 
00639 //--------------------------------------------------------------------------
00640 // text_begin_cairo()
00641 //
00642 // Begin text.
00643 //--------------------------------------------------------------------------
00644 
00645 void text_begin_cairo( PLStream *pls, EscText *args )
00646 {
00647     int     i;
00648     PLCairo *aStream;
00649 
00650     aStream                    = (PLCairo *) pls->dev;
00651     aStream->upDown            = 0;
00652     aStream->uline             = 0;
00653     aStream->level             = 0;
00654     aStream->pangoMarkupString = (char *) malloc( sizeof ( char ) * MAX_MARKUP_LEN );
00655     // Calculate the font size (in points since DPI = 72).
00656     aStream->fontSize = (float) ( pls->chrht * DPI / 25.4 );
00657     for ( i = 0; i < MAX_MARKUP_LEN; i++ )
00658     {
00659         aStream->pangoMarkupString[i] = 0;
00660     }
00661     open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, 0 );
00662 }
00663 
00664 //--------------------------------------------------------------------------
00665 // text_char_cairo()
00666 //
00667 // Add text.
00668 //--------------------------------------------------------------------------
00669 
00670 void text_char_cairo( PLStream *pls, EscText *args )
00671 {
00672     char    utf8[5];
00673     PLCairo *aStream;
00674 
00675     aStream = (PLCairo *) pls->dev;
00676     // make sure we are not too close to the end of the string
00677     if ( strlen( aStream->pangoMarkupString ) < ( MAX_MARKUP_LEN - 50 ) )
00678     {
00679         switch ( args->n_char )
00680         {
00681         case 38:
00682             strncat( aStream->pangoMarkupString, "&#38;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00683             break;
00684         case 60:
00685             strncat( aStream->pangoMarkupString, "&#60;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00686             break;
00687         case 62:
00688             strncat( aStream->pangoMarkupString, "&#62;", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00689             break;
00690         default:
00691             ucs4_to_utf8( args->n_char, utf8 );
00692             strncat( aStream->pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00693             break;
00694         }
00695     }
00696 }
00697 
00698 //--------------------------------------------------------------------------
00699 // text_esc_cairo()
00700 //
00701 // A font change, superscript, subscript, etc...
00702 //--------------------------------------------------------------------------
00703 
00704 void text_esc_cairo( PLStream *pls, EscText *args )
00705 {
00706     PLCairo *aStream;
00707 
00708     aStream = (PLCairo *) pls->dev;
00709     switch ( args->n_ctrl_char )
00710     {
00711     case PLTEXT_FONTCHANGE:
00712         close_span_tag( aStream->pangoMarkupString, aStream->upDown );
00713         open_span_tag( aStream->pangoMarkupString, args->n_fci, aStream->fontSize, aStream->upDown );
00714         break;
00715     case PLTEXT_SUPERSCRIPT:
00716         if ( aStream->upDown < 0 )
00717         {
00718             strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00719             aStream->level++;
00720         }
00721         else
00722         {
00723             plP_script_scale( TRUE, &aStream->level,
00724                 &aStream->old_sscale, &aStream->sscale, &aStream->old_soffset, &aStream->soffset );
00725             strncat( aStream->pangoMarkupString,
00726                 rise_span_tag( TRUE, aStream->fontSize, (float) aStream->sscale, (float) aStream->soffset ),
00727                 MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00728         }
00729         aStream->upDown++;
00730         break;
00731     case PLTEXT_SUBSCRIPT:
00732         if ( aStream->upDown > 0 )
00733         {
00734             strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00735             aStream->level--;
00736         }
00737         else
00738         {
00739             plP_script_scale( FALSE, &aStream->level,
00740                 &aStream->old_sscale, &aStream->sscale, &aStream->old_soffset, &aStream->soffset );
00741             strncat( aStream->pangoMarkupString,
00742                 rise_span_tag( FALSE, aStream->fontSize, (float) aStream->sscale, (float) aStream->soffset ),
00743                 MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00744         }
00745         aStream->upDown--;
00746         break;
00747     case PLTEXT_UNDERLINE:
00748         if ( aStream->uline == 1 )
00749         {
00750             strncat( aStream->pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00751             aStream->level++;
00752         }
00753         else
00754         {
00755             strncat( aStream->pangoMarkupString, "<span underline=\"single\">", MAX_MARKUP_LEN - 1 - strlen( aStream->pangoMarkupString ) );
00756             aStream->level++;
00757         }
00758         aStream->uline = !aStream->uline;
00759         break;
00760     case PLTEXT_BACKCHAR:
00761     case PLTEXT_OVERLINE:
00762         plwarn( "'-', and 'b/B' text escape sequences not processed." );
00763         break;
00764     }
00765 }
00766 
00767 //--------------------------------------------------------------------------
00768 // text_end_cairo()
00769 //
00770 // Draw the text and clean up.
00771 //--------------------------------------------------------------------------
00772 
00773 void text_end_cairo( PLStream *pls, EscText *args )
00774 {
00775     int   textXExtent, textYExtent, baseline;
00776     PLFLT rotation, shear, stride, cos_rot, sin_rot, cos_shear, sin_shear;
00777     cairo_matrix_t       *cairoTransformMatrix;
00778     cairo_font_options_t *cairoFontOptions;
00779     PangoContext         *context;
00780     PangoLayout          *layout;
00781     PLCairo              *aStream;
00782 
00783     aStream = (PLCairo *) pls->dev;
00784 
00785     set_current_context( pls );
00786 
00787     // Close the last span tag.
00788     close_span_tag( aStream->pangoMarkupString, aStream->upDown );
00789 
00790     // printf("%s\n", aStream->pangoMarkupString);
00791 
00792     // Create the Pango text layout so we can figure out how big it is
00793     layout = pango_cairo_create_layout( aStream->cairoContext );
00794     pango_layout_set_markup( layout, aStream->pangoMarkupString, -1 );
00795     pango_layout_get_pixel_size( layout, &textXExtent, &textYExtent );
00796     baseline = pango_layout_get_baseline( layout );
00797 
00798     // If asked, set the string length (in mm) and return
00799     if ( pls->get_string_length )
00800     {
00801         pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
00802     }
00803     else
00804     {
00805         // Set font aliasing
00806         context          = pango_layout_get_context( layout );
00807         cairoFontOptions = cairo_font_options_create();
00808         cairo_font_options_set_antialias( cairoFontOptions, aStream->text_anti_aliasing );
00809         pango_cairo_context_set_font_options( context, cairoFontOptions );
00810         pango_layout_context_changed( layout );
00811         cairo_font_options_destroy( cairoFontOptions );
00812 
00813         // Save current transform matrix & clipping region
00814         cairo_save( aStream->cairoContext );
00815 
00816         // Set up the clipping region if we are doing text clipping
00817         if ( aStream->text_clipping )
00818         {
00819             set_clip( pls );
00820         }
00821 
00822         // Move to the string reference point
00823         cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
00824 
00825         // Invert the coordinate system so that the text is drawn right side up
00826         cairoTransformMatrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
00827         cairo_matrix_init( cairoTransformMatrix, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
00828         cairo_transform( aStream->cairoContext, cairoTransformMatrix );
00829 
00830         // Extract rotation angle and shear from the PLplot tranformation matrix.
00831         // Compute sines and cosines of the angles as an optimization.
00832         plRotationShear( args->xform, &rotation, &shear, &stride );
00833         rotation -= pls->diorot * PI / 2.0;
00834         cos_rot   = cos( rotation );
00835         sin_rot   = sin( rotation );
00836         cos_shear = cos( shear );
00837         sin_shear = sin( shear );
00838 
00839         // Apply the transform matrix
00840         cairo_matrix_init( cairoTransformMatrix,
00841             cos_rot * stride,
00842             -sin_rot * stride,
00843             cos_rot * sin_shear + sin_rot * cos_shear,
00844             -sin_rot * sin_shear + cos_rot * cos_shear,
00845             0, 0 );
00846         cairo_transform( aStream->cairoContext, cairoTransformMatrix );
00847         free( cairoTransformMatrix );
00848 
00849         // Move to the text starting point
00850         // printf("baseline %d %d\n", baseline, textYExtent);
00851         cairo_rel_move_to( aStream->cairoContext,
00852             (double) ( -1.0 * args->just * (double) textXExtent ),
00853             (double) 0.5 * aStream->fontSize - baseline / 1024.0 );
00854 
00855         // Render the text
00856         pango_cairo_show_layout( aStream->cairoContext, layout );
00857 
00858         // Restore the transform matrix to its state prior to the text transform.
00859         cairo_restore( aStream->cairoContext );
00860     }
00861 
00862     // Free the layout object and the markup string
00863     g_object_unref( layout );
00864     free( aStream->pangoMarkupString );
00865 }
00866 
00867 //--------------------------------------------------------------------------
00868 // proc_str()
00869 //
00870 // Processes strings for display.
00871 //--------------------------------------------------------------------------
00872 
00873 void proc_str( PLStream *pls, EscText *args )
00874 {
00875     float fontSize;
00876     int   textXExtent, textYExtent, baseline;
00877     char                 *textWithPangoMarkup;
00878     PLFLT rotation, shear, stride, cos_rot, sin_rot, cos_shear, sin_shear;
00879     cairo_matrix_t       *cairoTransformMatrix;
00880     cairo_font_options_t *cairoFontOptions;
00881     PangoContext         *context;
00882     PangoLayout          *layout;
00883     PLCairo              *aStream;
00884 
00885     aStream = (PLCairo *) pls->dev;
00886 
00887     set_current_context( pls );
00888 
00889     // Check that we got unicode, warning message and return if not
00890     if ( args->unicode_array_len == 0 )
00891     {
00892         printf( "Non unicode string passed to a cairo driver, ignoring\n" );
00893         return;
00894     }
00895 
00896     // Check that unicode string isn't longer then the max we allow
00897     if ( args->unicode_array_len >= MAX_STRING_LEN )
00898     {
00899         printf( "Sorry, the cairo drivers only handles strings of length < %d\n", MAX_STRING_LEN );
00900         return;
00901     }
00902 
00903     // Calculate the font size (in points since DPI = 72).
00904     fontSize = (float) ( pls->chrht * DPI / 25.4 );
00905 
00906     // Convert the escape characters into the appropriate Pango markup
00907     textWithPangoMarkup = ucs4_to_pango_markup_format( args->unicode_array, args->unicode_array_len, fontSize );
00908 
00909     // Create the Pango text layout so we can figure out how big it is
00910     layout = pango_cairo_create_layout( aStream->cairoContext );
00911     pango_layout_set_markup( layout, textWithPangoMarkup, -1 );
00912     pango_layout_get_pixel_size( layout, &textXExtent, &textYExtent );
00913     baseline = pango_layout_get_baseline( layout );
00914 
00915     // If asked, set the string length (in mm) and return
00916     if ( pls->get_string_length )
00917     {
00918         pls->string_length = (PLFLT) textXExtent * 25.4 / DPI;
00919         return;
00920     }
00921 
00922     // Set font aliasing
00923     context          = pango_layout_get_context( layout );
00924     cairoFontOptions = cairo_font_options_create();
00925     cairo_font_options_set_antialias( cairoFontOptions, aStream->text_anti_aliasing );
00926     pango_cairo_context_set_font_options( context, cairoFontOptions );
00927     pango_layout_context_changed( layout );
00928     cairo_font_options_destroy( cairoFontOptions );
00929 
00930     // Save current transform matrix & clipping region
00931     cairo_save( aStream->cairoContext );
00932 
00933     // Set up the clipping region if we are doing text clipping
00934     if ( aStream->text_clipping )
00935     {
00936         set_clip( pls );
00937     }
00938 
00939     // Move to the string reference point
00940     cairo_move_to( aStream->cairoContext, aStream->downscale * (double) args->x, aStream->downscale * (double) args->y );
00941 
00942     // Invert the coordinate system so that the text is drawn right side up
00943     cairoTransformMatrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
00944     cairo_matrix_init( cairoTransformMatrix, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 );
00945     cairo_transform( aStream->cairoContext, cairoTransformMatrix );
00946 
00947     // Extract rotation angle and shear from the PLplot tranformation matrix.
00948     // Compute sines and cosines of the angles as an optimization.
00949     plRotationShear( args->xform, &rotation, &shear, &stride );
00950     rotation -= pls->diorot * PI / 2.0;
00951     cos_rot   = cos( rotation );
00952     sin_rot   = sin( rotation );
00953     cos_shear = cos( shear );
00954     sin_shear = sin( shear );
00955 
00956     // Apply the transform matrix
00957     cairo_matrix_init( cairoTransformMatrix,
00958         cos_rot * stride,
00959         -sin_rot * stride,
00960         cos_rot * sin_shear + sin_rot * cos_shear,
00961         -sin_rot * sin_shear + cos_rot * cos_shear,
00962         0, 0 );
00963     cairo_transform( aStream->cairoContext, cairoTransformMatrix );
00964     free( cairoTransformMatrix );
00965 
00966     // printf("baseline (ps) %d %d %f\n", baseline, textYExtent, aStream->fontSize);
00967     // Move to the text starting point
00968     cairo_rel_move_to( aStream->cairoContext,
00969         (double) ( -1.0 * args->just * (double) textXExtent ),
00970         (double) 0.5 * fontSize - baseline / 1024.0 );
00971 
00972     // Render the text
00973     pango_cairo_show_layout( aStream->cairoContext, layout );
00974 
00975     // Restore the transform matrix to its state prior to the text transform.
00976     cairo_restore( aStream->cairoContext );
00977 
00978     // Free the layout object and the markup string.
00979     g_object_unref( layout );
00980     free( textWithPangoMarkup );
00981 }
00982 
00983 //--------------------------------------------------------------------------
00984 // ucs4_to_pango_markup_format()
00985 //
00986 // Converts the plplot string (in ucs4) to a utf8 string that includes
00987 // pango markup.
00988 //
00989 // http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.html
00990 //--------------------------------------------------------------------------
00991 
00992 char *ucs4_to_pango_markup_format( PLUNICODE *ucs4, int ucs4Len, float fontSize )
00993 {
00994     char      plplotEsc;
00995     int       i;
00996     int       upDown = 0;
00997     PLUNICODE fci;
00998     char      utf8[5];
00999     char      *pangoMarkupString;
01000     PLFLT     old_sscale, sscale, old_soffset, soffset;
01001     PLINT     level = 0;
01002     short     uline = 0;
01003 
01004     // Will this be big enough? We might have lots of markup.
01005     pangoMarkupString = (char *) malloc( sizeof ( char ) * MAX_MARKUP_LEN );
01006     for ( i = 0; i < MAX_MARKUP_LEN; i++ )
01007     {
01008         pangoMarkupString[i] = 0;
01009     }
01010 
01011     // Get PLplot escape character
01012     plgesc( &plplotEsc );
01013 
01014     // Get the curent font and open the first span tag
01015     plgfci( &fci );
01016     open_span_tag( pangoMarkupString, fci, fontSize, 0 );
01017 
01018     // Parse the string to generate the tags
01019     i = 0;
01020     while ( i < ucs4Len )
01021     {
01022         // Try to avoid going off the end of the string
01023         if ( strlen( pangoMarkupString ) > ( MAX_MARKUP_LEN - 50 ) )
01024         {
01025             continue;
01026         }
01027         if ( ucs4[i] < PL_FCI_MARK )                // not a font change
01028         {
01029             if ( ucs4[i] != (PLUNICODE) plplotEsc ) // a character to display
01030             {                                       // we have to handle "<", ">" and "&" separately since they throw off the XML
01031                 switch ( ucs4[i] )
01032                 {
01033                 case 38:
01034                     strncat( pangoMarkupString, "&#38;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01035                     break;
01036                 case 60:
01037                     strncat( pangoMarkupString, "&#60;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01038                     break;
01039                 case 62:
01040                     strncat( pangoMarkupString, "&#62;", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01041                     break;
01042                 default:
01043                     ucs4_to_utf8( ucs4[i], utf8 );
01044                     strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01045                     break;
01046                 }
01047                 i++;
01048                 continue;
01049             }
01050             i++;
01051             if ( ucs4[i] == (PLUNICODE) plplotEsc ) // a escape character to display
01052             {
01053                 ucs4_to_utf8( ucs4[i], utf8 );
01054                 strncat( pangoMarkupString, utf8, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01055                 i++;
01056                 continue;
01057             }
01058             else
01059             {
01060                 if ( ucs4[i] == (PLUNICODE) 'u' ) // Superscript
01061                 {
01062                     if ( upDown < 0 )
01063                     {
01064                         strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01065                         level++;
01066                     }
01067                     else
01068                     {
01069                         plP_script_scale( TRUE, &level,
01070                             &old_sscale, &sscale, &old_soffset, &soffset );
01071                         strncat( pangoMarkupString,
01072                             rise_span_tag( TRUE, fontSize, (float) sscale, (float) soffset ),
01073                             MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01074                     }
01075                     upDown++;
01076                 }
01077                 if ( ucs4[i] == (PLUNICODE) 'd' ) // Subscript
01078                 {
01079                     if ( upDown > 0 )
01080                     {
01081                         strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01082                         level--;
01083                     }
01084                     else
01085                     {
01086                         plP_script_scale( FALSE, &level,
01087                             &old_sscale, &sscale, &old_soffset, &soffset );
01088                         strncat( pangoMarkupString,
01089                             rise_span_tag( FALSE, fontSize, (float) sscale, (float) soffset ),
01090                             MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01091                     }
01092                     upDown--;
01093                 }
01094                 if ( ucs4[i] == (PLUNICODE) '-' ) // Superscript
01095                 {
01096                     if ( uline == 1 )
01097                     {
01098                         strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01099                         level++;
01100                     }
01101                     else
01102                     {
01103                         strncat( pangoMarkupString,
01104                             "<span underline=\"single\">",
01105                             MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01106                     }
01107                     uline = uline;
01108                 }
01109                 i++;
01110             }
01111         }
01112         else // a font change
01113         {
01114             close_span_tag( pangoMarkupString, upDown );
01115             open_span_tag( pangoMarkupString, ucs4[i], fontSize, upDown );
01116             i++;
01117         }
01118     }
01119 
01120     // Close the last span tag.
01121     close_span_tag( pangoMarkupString, upDown );
01122 
01123     // printf("%s\n", pangoMarkupString);
01124 
01125     return pangoMarkupString;
01126 }
01127 
01128 //--------------------------------------------------------------------------
01129 // open_span_tag
01130 //
01131 // 1. Opens a span tag with the appropriate font description given the
01132 //   current fci.
01133 // 2. Add the appropriate number of <sub> or <sup> tags to bring us
01134 //   back to our current sub/super-script level.
01135 //--------------------------------------------------------------------------
01136 
01137 void open_span_tag( char *pangoMarkupString, PLUNICODE fci, float fontSize, int upDown )
01138 {
01139     unsigned char fontFamily, fontStyle, fontWeight;
01140     char          openTag[TAG_LEN];
01141     int           upDown_level;
01142     PLFLT         old_sscale, sscale, old_soffset, soffset;
01143     PLINT         level = 0.;
01144 
01145     // Generate the font info for the open tag & concatenate this
01146     // onto the markup string.
01147     plP_fci2hex( fci, &fontFamily, PL_FCI_FAMILY );
01148     plP_fci2hex( fci, &fontStyle, PL_FCI_STYLE );
01149     plP_fci2hex( fci, &fontWeight, PL_FCI_WEIGHT );
01150 
01151     // From http://library.gnome.org/devel/pango/unstable/PangoMarkupFormat.html
01152     // size = font size in 1024ths of a point.
01153     snprintf( openTag, TAG_LEN, "<span font_desc=\"%s\" size=\"%d\" ", familyLookup[fontFamily], (int) ( fontSize * 1024. ) );
01154     strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01155 
01156     snprintf( openTag, TAG_LEN, "style=\"%s\" ", styleLookup[fontStyle] );
01157     strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01158 
01159     snprintf( openTag, TAG_LEN, "weight=\"%s\">", weightLookup[fontWeight] );
01160     strncat( pangoMarkupString, openTag, MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01161 
01162     // Move to the right superscript/subscript level
01163     for ( upDown_level = 0; upDown_level < upDown; upDown_level++ )
01164     {
01165         plP_script_scale( TRUE, &level,
01166             &old_sscale, &sscale, &old_soffset, &soffset );
01167         strncat( pangoMarkupString,
01168             rise_span_tag( TRUE, fontSize, (float) sscale, (float) soffset ),
01169             MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01170     }
01171     for ( upDown_level = 0; upDown_level > upDown; upDown_level-- )
01172     {
01173         plP_script_scale( FALSE, &level,
01174             &old_sscale, &sscale, &old_soffset, &soffset );
01175         strncat( pangoMarkupString,
01176             rise_span_tag( FALSE, fontSize, (float) sscale, (float) soffset ),
01177             MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01178     }
01179 }
01180 
01181 //--------------------------------------------------------------------------
01182 // close_span_tag
01183 //
01184 // Close a span tag & brings us down to zero sub/super-script level.
01185 //--------------------------------------------------------------------------
01186 
01187 void close_span_tag( char *pangoMarkupString, int upDown )
01188 {
01189     if ( upDown > 0 )
01190     {
01191         while ( upDown > 0 )
01192         {
01193             strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01194             upDown--;
01195         }
01196     }
01197     if ( upDown < 0 )
01198     {
01199         while ( upDown < 0 )
01200         {
01201             strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01202             upDown++;
01203         }
01204     }
01205 
01206     strncat( pangoMarkupString, "</span>", MAX_MARKUP_LEN - 1 - strlen( pangoMarkupString ) );
01207 }
01208 
01209 // 0.8 mimics the offset of first superscript/subscript level implemented
01210 // in plstr (plsym.c) for Hershey fonts.  Indeed when comparing with
01211 // -dev xwin results this factor appears to offset the centers of the
01212 // letters appropriately (but not their edges since different font sizes
01213 // are involved).
01214 # define RISE_FACTOR    0.8
01215 
01216 //--------------------------------------------------------------------------
01217 // rise_span_tag
01218 //
01219 // Create a rise span tag w/ appropriate font size & baseline offset
01220 // fontSize is the baseline font size in points (1/72 of an inch),
01221 // multiplier is a scaling factor for that font size for superscript
01222 // or subscript, and rise is the vertical offset (in units of font
01223 // size) for that superscript or subscript.
01224 
01225 //--------------------------------------------------------------------------
01226 
01227 char *rise_span_tag( int ifsuperscript, float fontSize, float multiplier, float rise )
01228 {
01229     float       offset;
01230     static char tag[100];
01231 
01232     // http://developer.gnome.org/pango/unstable/PangoMarkupFormat.html says
01233     // rise should be in units of 10000 em's, but empirical evidence shows
01234     // it is in units of 1024th of a point.  Therefore, since FontSize
01235     // is in points, a rise of 1024. * fontSize corresponds a rise of
01236     // a full character height.
01237     rise = 1024.f * fontSize * (float) RISE_FACTOR * rise;
01238 
01239     // This is the correction for the difference between baseline and
01240     // middle coordinate systems.  This offset should be
01241     // 0.5*(fontSize - superscript/subscript fontSize).
01242     offset = 1024.f * 0.5f * fontSize * ( 1.0f - multiplier );
01243 
01244     if ( ifsuperscript )
01245     {
01246         sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
01247             (int) ( rise + offset ), (int) ( fontSize * 1024. * multiplier ) );
01248     }
01249     else
01250     {
01251         sprintf( tag, "<span rise=\"%d\" size=\"%d\">",
01252             (int) -( rise - offset ), (int) ( fontSize * 1024. * multiplier ) );
01253     }
01254 
01255     return ( tag );
01256 }
01257 
01258 //--------------------------------------------------------------------------
01259 // write_to_stream()
01260 //
01261 // Writes data to a open file stream. This function is passed to the
01262 // Cairo file IO devices.
01263 //--------------------------------------------------------------------------
01264 
01265 cairo_status_t write_to_stream( void *filePointer, unsigned char *data, unsigned int length )
01266 {
01267     unsigned int bytes_written;
01268 
01269     bytes_written = (unsigned int) fwrite( data, 1, (size_t) length, (FILE *) filePointer );
01270     if ( bytes_written == length )
01271     {
01272         return CAIRO_STATUS_SUCCESS;
01273     }
01274     else
01275     {
01276         return CAIRO_STATUS_WRITE_ERROR;
01277     }
01278 }
01279 
01280 //--------------------------------------------------------------------------
01281 // stream_and_font_setup()
01282 //
01283 // Initializes the PLStream structure for the cairo devices.
01284 // Initializes the font lookup table.
01285 // Checks for cairo specific user options.
01286 // Returns a new PLCairo structure.
01287 //--------------------------------------------------------------------------
01288 
01289 PLCairo *stream_and_font_setup( PLStream *pls, int interactive )
01290 {
01291     int     i;
01292     char    *a;
01293     PLCairo *aStream;
01294     PLFLT   downscale;
01295     downscale = 0.0;
01296 
01297     // Stream setup
01298     pls->termin            = interactive; // Interactive device
01299     pls->dev_flush         = 1;           // Handles flushes
01300     pls->color             = 1;           // Supports color
01301     pls->dev_text          = 1;           // Handles text
01302     pls->dev_unicode       = 1;           // Wants unicode text
01303     pls->dev_clear         = 0;
01304     pls->alt_unicode       = 1;           // Wants to handle unicode character by character
01305     pls->page              = 0;
01306     pls->dev_fill0         = 1;           // Supports hardware solid fills
01307     pls->dev_gradient      = 1;           // driver renders gradient
01308     pls->dev_arc           = 1;           // Supports driver-level arcs
01309     pls->plbuf_write       = interactive; // Activate plot buffer
01310     pls->has_string_length = 1;           // Driver supports string length calculations
01311     pls->dev_modeset       = 1;           // Driver supports drawing mode setting
01312 
01313     if ( pls->xlength <= 0 || pls->ylength <= 0 )
01314     {
01315         pls->xlength = PLCAIRO_DEFAULT_X;
01316         pls->ylength = PLCAIRO_DEFAULT_Y;
01317     }
01318     // Calculate ratio of (smaller) external coordinates used for cairo
01319     // devices to (larger) internal PLplot coordinates.
01320     if ( pls->xlength > pls->ylength )
01321         downscale = (double) pls->xlength / (double) ( PIXELS_X - 1 );
01322     else
01323         downscale = (double) pls->ylength / (double) PIXELS_Y;
01324     plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / downscale ), (PLINT) 0, (PLINT) ( pls->ylength / downscale ) );
01325     plP_setpxl( DPI / 25.4 / downscale, DPI / 25.4 / downscale );
01326 
01327     // Initialize font table with either enviroment variables or defaults.
01328     // This was copied from the psttf driver.
01329     for ( i = 0; i < NPANGOLOOKUP; i++ )
01330     {
01331         if ( ( a = getenv( envFamilyLookup[i] ) ) != NULL )
01332         {
01333             strncpy( familyLookup[i], a, FAMILY_LOOKUP_LEN - 1 );
01334             familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
01335         }
01336         else
01337         {
01338             strncpy( familyLookup[i], defaultFamilyLookup[i], FAMILY_LOOKUP_LEN - 1 );
01339             familyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
01340         }
01341     }
01342 
01343     // Allocate a cairo stream structure
01344     aStream = malloc( sizeof ( PLCairo ) );
01345 #if defined ( PLD_xcairo )
01346     aStream->XDisplay = NULL;
01347     aStream->XWindow  = 0;
01348 #endif
01349     aStream->cairoSurface = NULL;
01350     aStream->cairoContext = NULL;
01351     aStream->downscale    = downscale;
01352 
01353     // Set text clipping on by default since it makes little difference in
01354     // speed for a modern cairo stack.
01355     aStream->text_clipping = 1;
01356     text_clipping          = 1;
01357     text_anti_aliasing     = 0; // use 'default' text aliasing by default
01358     graphics_anti_aliasing = 0; // use 'default' graphics aliasing by default
01359     rasterize_image        = 1; // Enable rasterization by default
01360     set_background         = 0; // Default for extcairo is that PLplot not change the background
01361     image_buffering        = 1; // Default to image-based buffered rendering
01362 
01363     // Check for cairo specific options
01364     plParseDrvOpts( cairo_options );
01365 
01366     // Turn off text clipping if the user desires this
01367     if ( !text_clipping )
01368     {
01369         aStream->text_clipping = 0;
01370     }
01371 
01372     // Record users desired text and graphics aliasing and rasterization
01373     aStream->text_anti_aliasing     = (short) text_anti_aliasing;
01374     aStream->graphics_anti_aliasing = (short) graphics_anti_aliasing;
01375     aStream->rasterize_image        = (short) rasterize_image;
01376     aStream->set_background         = (short) set_background;
01377     aStream->image_buffering        = (short) image_buffering;
01378 
01379     return aStream;
01380 }
01381 
01382 //--------------------------------------------------------------------------
01383 // set_current_context()
01384 //
01385 // Updates the cairo graphics context with the current values in
01386 // PLStream.
01387 //--------------------------------------------------------------------------
01388 
01389 void set_current_context( PLStream *pls )
01390 {
01391     PLCairo *aStream;
01392 
01393     aStream = (PLCairo *) pls->dev;
01394     cairo_set_source_rgba( aStream->cairoContext,
01395         (double) pls->curcolor.r / 255.0,
01396         (double) pls->curcolor.g / 255.0,
01397         (double) pls->curcolor.b / 255.0,
01398         (double) pls->curcolor.a );
01399     // In Cairo, zero width lines are not hairlines, they are completely invisible.
01400     if ( pls->width <= 0. )
01401     {
01402         cairo_set_line_width( aStream->cairoContext, 1.0 );
01403     }
01404     else
01405     {
01406         cairo_set_line_width( aStream->cairoContext, (double) pls->width );
01407     }
01408 }
01409 
01410 //--------------------------------------------------------------------------
01411 // poly_line()
01412 //
01413 // Draws a multi-segmented line. It is then up to the calling function
01414 // to decide whether to just draw the line, or fill in the area
01415 // enclosed by the line.
01416 //--------------------------------------------------------------------------
01417 
01418 void poly_line( PLStream *pls, short *xa, short *ya, PLINT npts )
01419 {
01420     int     i;
01421     PLCairo *aStream;
01422 
01423     aStream = (PLCairo *) pls->dev;
01424 
01425     set_current_context( pls );
01426 
01427     cairo_move_to( aStream->cairoContext, aStream->downscale * (double) xa[0], aStream->downscale * (double) ya[0] );
01428     for ( i = 1; i < npts; i++ )
01429     {
01430         cairo_line_to( aStream->cairoContext, aStream->downscale * (double) xa[i], aStream->downscale * (double) ya[i] );
01431     }
01432 }
01433 
01434 //--------------------------------------------------------------------------
01435 // filled_polygon()
01436 //
01437 // Draws a filled polygon.
01438 //--------------------------------------------------------------------------
01439 
01440 void filled_polygon( PLStream *pls, short *xa, short *ya, PLINT npts )
01441 {
01442     PLCairo *aStream;
01443 
01444     aStream = (PLCairo *) pls->dev;
01445 
01446     cairo_save( aStream->cairoContext );
01447 
01448     // Draw the polygons
01449     poly_line( pls, xa, ya, npts );
01450 
01451     cairo_set_source_rgba( aStream->cairoContext,
01452         (double) pls->curcolor.r / 255.0,
01453         (double) pls->curcolor.g / 255.0,
01454         (double) pls->curcolor.b / 255.0,
01455         (double) pls->curcolor.a );
01456 
01457     if ( cairo_get_antialias( aStream->cairoContext ) != CAIRO_ANTIALIAS_NONE )
01458     {
01459         cairo_fill_preserve( aStream->cairoContext );
01460 
01461         // These line properties make for a nicer looking polygon mesh
01462         set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
01463         // Comment out the following call to cairo_set_line width
01464         // since the hard-coded width value of 1.0 is not appropriate
01465         // for fills of small areas.  Instead, use the line width that
01466         // has already been set by the user via the above call of
01467         // poly_line which in turn calls set_current_context which in
01468         // turn calls cairo_set_line_width for the user-specified
01469         // width.
01470         // cairo_set_line_width( aStream->cairoContext, 1.0 );
01471         cairo_stroke( aStream->cairoContext );
01472     }
01473     else
01474     {
01475         cairo_fill( aStream->cairoContext );
01476     }
01477 
01478     cairo_restore( aStream->cairoContext );
01479 }
01480 
01481 //--------------------------------------------------------------------------
01482 // gradient()
01483 //
01484 // Render a gradient within a polygon.
01485 //--------------------------------------------------------------------------
01486 
01487 void gradient( PLStream *pls, short *xa, short *ya, PLINT npts )
01488 {
01489     int i;
01490     PLCairo         *aStream;
01491     cairo_pattern_t *linear_gradient;
01492 
01493     aStream = (PLCairo *) pls->dev;
01494 
01495     // These line properties make for a nicer looking polygon mesh
01496     set_line_properties( aStream, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_CAP_BUTT );
01497 
01498     linear_gradient = cairo_pattern_create_linear(
01499         aStream->downscale * pls->xgradient[0],
01500         aStream->downscale * pls->ygradient[0],
01501         aStream->downscale * pls->xgradient[1],
01502         aStream->downscale * pls->ygradient[1] );
01503 
01504     cairo_pattern_reference( linear_gradient );
01505     for ( i = 0; i < pls->ncol1; i++ )
01506     {
01507         cairo_pattern_add_color_stop_rgba( linear_gradient,
01508             (double) i / (double) ( pls->ncol1 - 1 ),
01509             (double) pls->cmap1[i].r / 255.,
01510             (double) pls->cmap1[i].g / 255.,
01511             (double) pls->cmap1[i].b / 255.,
01512             (double) pls->cmap1[i].a );
01513     }
01514 
01515     // Draw the polygon using the gradient.
01516     poly_line( pls, xa, ya, npts );
01517 
01518     cairo_set_source( aStream->cairoContext, linear_gradient );
01519     cairo_fill( aStream->cairoContext );
01520     cairo_pattern_destroy( linear_gradient );
01521 }
01522 
01523 //--------------------------------------------------------------------------
01524 // set_clip()
01525 //
01526 // Set the clipping region to the plot window.
01527 // NOTE: cairo_save() and cairo_restore() should probably be called before
01528 // and after this, respectively.
01529 //--------------------------------------------------------------------------
01530 
01531 void set_clip( PLStream *pls )
01532 {
01533     PLINT   rcx[4], rcy[4];
01534     PLCairo *aStream;
01535     aStream = (PLCairo *) pls->dev;
01536 
01537     // Use PLplot core routine to get the corners of the clipping rectangle
01538     difilt_clip( rcx, rcy );
01539 
01540     // Layout the bounds of the clipping region
01541     // Should we convert PLINT to short and use the polyline routine?
01542     cairo_move_to( aStream->cairoContext,
01543         aStream->downscale * (double) rcx[0],
01544         aStream->downscale * (double) rcy[0] );
01545     cairo_line_to( aStream->cairoContext,
01546         aStream->downscale * (double) rcx[1],
01547         aStream->downscale * (double) rcy[1] );
01548     cairo_line_to( aStream->cairoContext,
01549         aStream->downscale * (double) rcx[2],
01550         aStream->downscale * (double) rcy[2] );
01551     cairo_line_to( aStream->cairoContext,
01552         aStream->downscale * (double) rcx[3],
01553         aStream->downscale * (double) rcy[3] );
01554     cairo_line_to( aStream->cairoContext,
01555         aStream->downscale * (double) rcx[0],
01556         aStream->downscale * (double) rcy[0] );
01557 
01558     // Set the clipping region
01559     cairo_clip( aStream->cairoContext );
01560 
01561     // Apparently, in some older Cairo versions, cairo_clip does not consume
01562     // the current path.
01563     cairo_new_path( aStream->cairoContext );
01564 }
01565 
01566 //--------------------------------------------------------------------------
01567 // cairo_family_check ()
01568 //
01569 // support function to help supress more than one page if family file
01570 // output not specified by the user  (e.g., with the -fam command-line option).
01571 //--------------------------------------------------------------------------
01572 
01573 int cairo_family_check( PLStream *pls )
01574 {
01575     if ( pls->family || pls->page == 1 )
01576     {
01577         return 0;
01578     }
01579     else
01580     {
01581         if ( !already_warned )
01582         {
01583             already_warned = 1;
01584             plwarn( "All pages after the first skipped because family file output not specified.\n" );
01585         }
01586         return 1;
01587     }
01588 }
01589 
01590 //--------------------------------------------------------------------------
01591 // arc()
01592 //
01593 // Draws an arc, possibly filled.
01594 //--------------------------------------------------------------------------
01595 
01596 void arc( PLStream *pls, arc_struct *arc_info )
01597 {
01598     PLCairo *aStream;
01599     double  x, y, a, b;
01600     double  angle1, angle2, rotate;
01601 
01602     set_current_context( pls );
01603 
01604     aStream = (PLCairo *) pls->dev;
01605 
01606     // Scale to the proper Cairo coordinates
01607     x = aStream->downscale * arc_info->x;
01608     y = aStream->downscale * arc_info->y;
01609     a = aStream->downscale * arc_info->a;
01610     b = aStream->downscale * arc_info->b;
01611 
01612     // Degrees to radians
01613     angle1 = arc_info->angle1 * M_PI / 180.0;
01614     angle2 = arc_info->angle2 * M_PI / 180.0;
01615     rotate = arc_info->rotate * M_PI / 180.0;
01616 
01617     cairo_save( aStream->cairoContext );
01618 
01619     // Clip the output to the plotting window
01620     set_clip( pls );
01621 
01622     // Make sure the arc is properly shaped and oriented
01623     cairo_save( aStream->cairoContext );
01624     cairo_translate( aStream->cairoContext, x, y );
01625     cairo_rotate( aStream->cairoContext, rotate );
01626     cairo_scale( aStream->cairoContext, a, b );
01627     cairo_arc( aStream->cairoContext, 0.0, 0.0, 1.0, angle1, angle2 );
01628     if ( arc_info->fill )
01629         cairo_line_to( aStream->cairoContext, 0.0, 0.0 );
01630     cairo_restore( aStream->cairoContext );
01631 
01632     cairo_set_source_rgba( aStream->cairoContext,
01633         (double) pls->curcolor.r / 255.0,
01634         (double) pls->curcolor.g / 255.0,
01635         (double) pls->curcolor.b / 255.0,
01636         (double) pls->curcolor.a );
01637     if ( arc_info->fill )
01638     {
01639         cairo_fill( aStream->cairoContext );
01640     }
01641     else
01642     {
01643         cairo_stroke( aStream->cairoContext );
01644     }
01645     cairo_restore( aStream->cairoContext );
01646 }
01647 
01648 //--------------------------------------------------------------------------
01649 // rotate_cairo_surface()
01650 //
01651 // Rotates the cairo surface to the appropriate orientation.
01652 //--------------------------------------------------------------------------
01653 
01654 void rotate_cairo_surface( PLStream *pls, float x11, float x12, float x21, float x22, float x0, float y0, PLBOOL is_xcairo )
01655 {
01656     cairo_matrix_t *matrix;
01657     PLCairo        *aStream;
01658 
01659     aStream = (PLCairo *) pls->dev;
01660 
01661     matrix = (cairo_matrix_t *) malloc( sizeof ( cairo_matrix_t ) );
01662     cairo_matrix_init( matrix, x11, x12, x21, x22, x0, y0 );
01663 #if defined ( PLD_xcairo )
01664     if ( is_xcairo )
01665     {
01666         cairo_transform( aStream->cairoContext_X, matrix );
01667     }
01668     else
01669     {
01670         cairo_transform( aStream->cairoContext, matrix );
01671     }
01672 #else
01673     cairo_transform( aStream->cairoContext, matrix );
01674 #endif
01675     free( matrix );
01676 }
01677 
01678 //--------------------------------------------------------------------------
01679 //--------------------------------------------------------------------------
01680 //
01681 // That which is common to all familying Cairo Drivers
01682 //
01683 //--------------------------------------------------------------------------
01684 //--------------------------------------------------------------------------
01685 #if defined ( PLD_pngcairo ) || defined ( PLD_svgcairo ) || defined ( PLD_epscairo )
01686 
01687 void plD_bop_cairo_fam( PLStream * );
01688 void plD_eop_cairo_fam( PLStream * );
01689 void plD_state_cairo_fam( PLStream *, PLINT );
01690 void plD_esc_cairo_fam( PLStream *, PLINT, void * );
01691 void plD_tidy_cairo_fam( PLStream * );
01692 void plD_line_cairo_fam( PLStream *, short, short, short, short );
01693 void plD_polyline_cairo_fam( PLStream *, short *, short *, PLINT );
01694 
01695 //--------------------------------------------------------------------------
01696 // plD_bop_cairo_fam()
01697 //
01698 // Familying Devices: Set up for the next page.
01699 //--------------------------------------------------------------------------
01700 
01701 void plD_bop_cairo_fam( PLStream *pls )
01702 {
01703     PLCairo *aStream;
01704 
01705     // Plot familying stuff. Not really understood, just copying gd.c
01706     plGetFam( pls );
01707 
01708     aStream = (PLCairo *) pls->dev;
01709 
01710     pls->famadv = 1;
01711     pls->page++;
01712 
01713     // Suppress multi-page output if family file output is not
01714     // specified by the user.
01715     if ( cairo_family_check( pls ) )
01716     {
01717         return;
01718     }
01719 
01720     // Fill in the window with the background color.
01721     cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
01722     cairo_set_source_rgba( aStream->cairoContext,
01723         (double) pls->cmap0[0].r / 255.0,
01724         (double) pls->cmap0[0].g / 255.0,
01725         (double) pls->cmap0[0].b / 255.0,
01726         (double) pls->cmap0[0].a );
01727     cairo_fill( aStream->cairoContext );
01728 }
01729 
01730 //--------------------------------------------------------------------------
01731 // plD_eop_cairo()
01732 //
01733 // End of page.
01734 //--------------------------------------------------------------------------
01735 
01736 void plD_eop_cairo_fam( PLStream *pls )
01737 {
01738     if ( cairo_family_check( pls ) )
01739     {
01740         return;
01741     }
01742 
01743     plD_eop_cairo( pls );
01744 }
01745 
01746 //--------------------------------------------------------------------------
01747 // plD_state_cairo_fam()
01748 //
01749 // Handle change in PLStream state (color, pen width, fill attribute, etc).
01750 //--------------------------------------------------------------------------
01751 
01752 void plD_state_cairo_fam( PLStream *pls, PLINT op )
01753 {
01754     if ( cairo_family_check( pls ) )
01755     {
01756         return;
01757     }
01758 
01759     plD_state_cairo( pls, op );
01760 }
01761 
01762 //--------------------------------------------------------------------------
01763 // plD_esc_cairo_fam()
01764 //
01765 // Generic escape function.
01766 //--------------------------------------------------------------------------
01767 
01768 void plD_esc_cairo_fam( PLStream *pls, PLINT op, void *ptr )
01769 {
01770     if ( cairo_family_check( pls ) )
01771     {
01772         return;
01773     }
01774 
01775     plD_esc_cairo( pls, op, ptr );
01776 }
01777 
01778 //--------------------------------------------------------------------------
01779 // plD_tidy_cairo_fam()
01780 //
01781 // Close graphics file or otherwise clean up.
01782 //--------------------------------------------------------------------------
01783 
01784 void plD_tidy_cairo_fam( PLStream *pls )
01785 {
01786     plD_tidy_cairo( pls );
01787 }
01788 
01789 //--------------------------------------------------------------------------
01790 // plD_line_cairo_fam()
01791 //
01792 // Draw a line.
01793 //--------------------------------------------------------------------------
01794 
01795 void plD_line_cairo_fam( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
01796 {
01797     if ( cairo_family_check( pls ) )
01798     {
01799         return;
01800     }
01801 
01802     plD_line_cairo( pls, x1a, y1a, x2a, y2a );
01803 }
01804 
01805 //--------------------------------------------------------------------------
01806 // plD_polyline_cairo_fam()
01807 //
01808 // Draw a polyline in the current color.
01809 //--------------------------------------------------------------------------
01810 
01811 void plD_polyline_cairo_fam( PLStream *pls, short *xa, short *ya, PLINT npts )
01812 {
01813     if ( cairo_family_check( pls ) )
01814     {
01815         return;
01816     }
01817 
01818     plD_polyline_cairo( pls, xa, ya, npts );
01819 }
01820 
01821 #endif
01822 //--------------------------------------------------------------------------
01823 //--------------------------------------------------------------------------
01824 //
01825 // That which is specific to the xcairo driver.
01826 //
01827 //--------------------------------------------------------------------------
01828 //--------------------------------------------------------------------------
01829 
01830 #if defined ( PLD_xcairo )
01831 
01832 static int    XScreen;
01833 static Window rootWindow;
01834 
01835 void plD_dispatch_init_xcairo( PLDispatchTable *pdt );
01836 void plD_init_xcairo( PLStream * );
01837 void plD_bop_xcairo( PLStream * );
01838 void plD_eop_xcairo( PLStream * );
01839 void plD_tidy_xcairo( PLStream * );
01840 void plD_esc_xcairo( PLStream *, PLINT, void * );
01841 static void xcairo_get_cursor( PLStream *, PLGraphicsIn * );
01842 
01843 //--------------------------------------------------------------------------
01844 // plD_dispatch_init_xcairo()
01845 //
01846 // xcairo dispatch table initialization.
01847 //--------------------------------------------------------------------------
01848 
01849 void plD_dispatch_init_xcairo( PLDispatchTable *pdt )
01850 {
01851 #ifndef ENABLE_DYNDRIVERS
01852     pdt->pl_MenuStr = "Cairo X Windows Driver";
01853     pdt->pl_DevName = "xcairo";
01854 #endif
01855     pdt->pl_type     = plDevType_Interactive;
01856     pdt->pl_seq      = 100;
01857     pdt->pl_init     = (plD_init_fp) plD_init_xcairo;
01858     pdt->pl_line     = (plD_line_fp) plD_line_cairo;
01859     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
01860     pdt->pl_eop      = (plD_eop_fp) plD_eop_xcairo;
01861     pdt->pl_bop      = (plD_bop_fp) plD_bop_xcairo;
01862     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_xcairo;
01863     pdt->pl_state    = (plD_state_fp) plD_state_cairo;
01864     pdt->pl_esc      = (plD_esc_fp) plD_esc_xcairo;
01865 }
01866 
01867 //--------------------------------------------------------------------------
01868 // xcairo_init_cairo()
01869 //
01870 // Configures Cairo to use whichever X Drawable is set up in the given
01871 // stream.  This is called by plD_init_xcairo() in the event we are
01872 // drawing into a plplot-managed window, and plD_esc_xcairo() if
01873 // we are using an external X Drawable.
01874 //
01875 // A return value of 0 indicates success.  Currently this function only
01876 // returns 0.
01877 //--------------------------------------------------------------------------
01878 
01879 static signed int xcairo_init_cairo( PLStream *pls )
01880 {
01881     PLCairo *aStream;
01882     Visual  *defaultVisual;
01883 
01884     aStream = (PLCairo *) pls->dev;
01885 
01886     // Create an cairo surface & context that are associated with the X window.
01887     defaultVisual = DefaultVisual( aStream->XDisplay, 0 );
01888     // Dimension units are pixels from cairo documentation.
01889     // This is the X window Cairo surface.
01890     aStream->cairoSurface_X = cairo_xlib_surface_create( aStream->XDisplay, aStream->XWindow, defaultVisual, pls->xlength, pls->ylength );
01891     aStream->cairoContext_X = cairo_create( aStream->cairoSurface_X );
01892     // This is the Cairo surface PLplot will actually plot to.
01893     if ( aStream->image_buffering == 0 )
01894     {
01895         aStream->cairoSurface = cairo_surface_create_similar( aStream->cairoSurface_X, CAIRO_CONTENT_COLOR_ALPHA, pls->xlength, pls->ylength );
01896         aStream->cairoContext = cairo_create( aStream->cairoSurface );
01897     }
01898     else
01899     {
01900         // Plot to an off-screen image
01901         aStream->cairoSurface =
01902             cairo_image_surface_create( CAIRO_FORMAT_ARGB32,
01903                 pls->xlength, pls->ylength );
01904         aStream->cairoContext = cairo_create( aStream->cairoSurface );
01905     }
01906 
01907     // Invert the surface so that the graphs are drawn right side up.
01908     rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, TRUE );
01909 
01910     // Set graphics aliasing
01911     cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
01912 
01913     // Set fill rule for the case of self-intersecting boundaries.
01914     if ( pls->dev_eofill )
01915         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
01916     else
01917         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
01918 
01919     // Fill in the X window with the background color to avoid starting out
01920     // with a blank window of an unexpected color.
01921     cairo_rectangle( aStream->cairoContext_X, 0.0, 0.0, pls->xlength, pls->ylength );
01922     cairo_set_source_rgba( aStream->cairoContext_X,
01923         (double) pls->cmap0[0].r / 255.0,
01924         (double) pls->cmap0[0].g / 255.0,
01925         (double) pls->cmap0[0].b / 255.0,
01926         (double) pls->cmap0[0].a );
01927     cairo_fill( aStream->cairoContext_X );
01928 
01929     XFlush( aStream->XDisplay );
01930 
01931     return 0;
01932 }
01933 
01934 //--------------------------------------------------------------------------
01935 // plD_init_xcairo()
01936 //
01937 // Initialize Cairo X Windows device.
01938 //--------------------------------------------------------------------------
01939 
01940 void plD_init_xcairo( PLStream *pls )
01941 {
01942     PLCairo *aStream;
01943     Atom    wmDelete;
01944 
01945     // Setup the PLStream and the font lookup table.
01946     aStream = stream_and_font_setup( pls, 1 );
01947 
01948     // Save the pointer to the structure in the PLplot stream
01949     pls->dev = aStream;
01950 
01951     // Create a X Window if required.
01952     if ( external_drawable != 0 )
01953     {
01954         aStream->xdrawable_mode = 1;
01955     }
01956     else
01957     {
01958         // X Windows setup
01959         aStream->XDisplay = NULL;
01960         if ( pls->FileName != NULL )
01961             aStream->XDisplay = XOpenDisplay( pls->FileName );
01962         else
01963             aStream->XDisplay = XOpenDisplay( NULL );
01964         if ( aStream->XDisplay == NULL )
01965         {
01966             plexit( "Failed to open X Windows display\n" );
01967             // some sort of error here
01968         }
01969         XScreen    = DefaultScreen( aStream->XDisplay );
01970         rootWindow = RootWindow( aStream->XDisplay, XScreen );
01971 
01972         aStream->XWindow = XCreateSimpleWindow( aStream->XDisplay, rootWindow, 0, 0, (unsigned int) pls->xlength, (unsigned int) pls->ylength,
01973             1, BlackPixel( aStream->XDisplay, XScreen ), BlackPixel( aStream->XDisplay, XScreen ) );
01974         XStoreName( aStream->XDisplay, aStream->XWindow, pls->plwindow );
01975         XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
01976         XMapWindow( aStream->XDisplay, aStream->XWindow );
01977         aStream->xdrawable_mode = 0;
01978 
01979         wmDelete = XInternAtom( aStream->XDisplay, "WM_DELETE_WINDOW", True );
01980         XSetWMProtocols( aStream->XDisplay, aStream->XWindow, &wmDelete, 1 );
01981 
01982         xcairo_init_cairo( pls );
01983     }
01984 
01985     aStream->exit_event_loop = 0;
01986 }
01987 
01988 //--------------------------------------------------------------------------
01989 // blit_to_x()
01990 //
01991 //
01992 // Blit the offscreen image to the X window.
01993 //--------------------------------------------------------------------------
01994 
01995 void blit_to_x( PLStream *pls, double x, double y, double w, double h )
01996 {
01997     PLCairo *aStream;
01998 
01999     aStream = pls->dev;
02000 
02001     cairo_save( aStream->cairoContext );
02002     // "Flatten" any transparent regions to look like they were drawn over the
02003     // correct background color
02004     cairo_rectangle( aStream->cairoContext, x, y, w, h );
02005     cairo_set_operator( aStream->cairoContext, CAIRO_OPERATOR_DEST_OVER );
02006     cairo_set_source_rgba( aStream->cairoContext,
02007         (double) pls->cmap0[0].r / 255.0,
02008         (double) pls->cmap0[0].g / 255.0,
02009         (double) pls->cmap0[0].b / 255.0,
02010         (double) pls->cmap0[0].a );
02011     cairo_fill( aStream->cairoContext );
02012     cairo_restore( aStream->cairoContext );
02013 
02014     cairo_save( aStream->cairoContext_X );
02015     // Copy a portion of the surface
02016     cairo_rectangle( aStream->cairoContext_X, x, y, w, h );
02017     cairo_set_operator( aStream->cairoContext_X, CAIRO_OPERATOR_SOURCE );
02018     cairo_set_source_surface( aStream->cairoContext_X,
02019         aStream->cairoSurface, 0.0, 0.0 );
02020     cairo_fill( aStream->cairoContext_X );
02021     cairo_restore( aStream->cairoContext_X );
02022 }
02023 
02024 //--------------------------------------------------------------------------
02025 // plD_bop_xcairo()
02026 //
02027 // X Windows specific start of page.
02028 //--------------------------------------------------------------------------
02029 
02030 void plD_bop_xcairo( PLStream *pls )
02031 {
02032     PLCairo *aStream;
02033 
02034     aStream = (PLCairo *) pls->dev;
02035 
02036     plD_bop_cairo( pls );
02037 
02038     if ( aStream->xdrawable_mode )
02039         return;
02040 
02041     XFlush( aStream->XDisplay );
02042 }
02043 
02044 //--------------------------------------------------------------------------
02045 // plD_eop_xcairo()
02046 //
02047 // X Windows specific end of page.
02048 //--------------------------------------------------------------------------
02049 
02050 void plD_eop_xcairo( PLStream *pls )
02051 {
02052     int            number_chars;
02053     long           event_mask;
02054     char           event_string[10];
02055     KeySym         keysym;
02056     XComposeStatus cs;
02057     XEvent         event;
02058     XExposeEvent   *expose;
02059     PLCairo        *aStream;
02060 
02061     aStream = (PLCairo *) pls->dev;
02062 
02063     // Blit the offscreen image to the X window.
02064     blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
02065 
02066     if ( aStream->xdrawable_mode )
02067         return;
02068 
02069     // Only pause if nopause is unset.
02070     if ( pls->nopause )
02071         aStream->exit_event_loop = 1;
02072 
02073     // Loop, handling selected events, till the user elects to close the plot.
02074     event_mask = ButtonPressMask | KeyPressMask | ExposureMask;
02075     XSelectInput( aStream->XDisplay, aStream->XWindow, event_mask );
02076     while ( !aStream->exit_event_loop )
02077     {
02078         //XWindowEvent( aStream->XDisplay, aStream->XWindow, event_mask, &event );
02079         XNextEvent( aStream->XDisplay, &event );
02080         switch ( event.type )
02081         {
02082         case KeyPress:
02083             number_chars = XLookupString( (XKeyEvent *) &event, event_string, 10, &keysym, &cs );
02084             event_string[number_chars] = '\0';
02085             if ( keysym == XK_Return )
02086             {
02087                 aStream->exit_event_loop = 1;
02088             }
02089             break;
02090         case ButtonPress:
02091             if ( ( (XButtonEvent *) &event )->button == Button3 )
02092                 aStream->exit_event_loop = 1;
02093             break;
02094         case ClientMessage:
02095             // plexit("X Window closed");
02096             pls->stream_closed       = TRUE;
02097             aStream->exit_event_loop = 1;
02098             break;
02099         case Expose:
02100             // Blit the image again after an expose event, but only for the last
02101             // available event.  Otherwise multiple redraws occur needlessly.
02102             expose = (XExposeEvent *) &event;
02103             if ( expose->count == 0 )
02104             {
02105                 blit_to_x( pls, expose->x, expose->y,
02106                     expose->width, expose->height );
02107             }
02108             break;
02109         }
02110     }
02111     aStream->exit_event_loop = 0;
02112 }
02113 
02114 //--------------------------------------------------------------------------
02115 // plD_tidy_xcairo()
02116 //
02117 // X Windows: close graphics file or otherwise clean up.
02118 //--------------------------------------------------------------------------
02119 
02120 void plD_tidy_xcairo( PLStream *pls )
02121 {
02122     PLCairo *aStream;
02123 
02124     aStream = (PLCairo *) pls->dev;
02125 
02126     plD_tidy_cairo( pls );
02127 
02128     // Also free up the Cairo X surface and context
02129     cairo_destroy( aStream->cairoContext_X );
02130     cairo_surface_destroy( aStream->cairoSurface_X );
02131 
02132     if ( aStream->xdrawable_mode )
02133         return;
02134 
02135     // Close the window and the display.
02136     XFlush( aStream->XDisplay );
02137 
02138     XDestroyWindow( aStream->XDisplay, aStream->XWindow );
02139 
02140     XCloseDisplay( aStream->XDisplay );
02141 }
02142 
02143 //--------------------------------------------------------------------------
02144 // plD_esc_xcairo()
02145 //
02146 // Escape function, specialized for the xcairo driver
02147 //--------------------------------------------------------------------------
02148 
02149 void plD_esc_xcairo( PLStream *pls, PLINT op, void *ptr )
02150 {
02151     PLCairo *aStream;
02152 
02153     aStream = (PLCairo *) pls->dev;
02154 
02155     switch ( op )
02156     {
02157     case PLESC_FLUSH:    // forced update of the window
02158         blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
02159         XFlush( aStream->XDisplay );
02160         break;
02161     case PLESC_GETC:     // get cursor position
02162         blit_to_x( pls, 0.0, 0.0, pls->xlength, pls->ylength );
02163         XFlush( aStream->XDisplay );
02164         xcairo_get_cursor( pls, (PLGraphicsIn *) ptr );
02165         break;
02166     case PLESC_DEVINIT: { // Set external drawable
02167         Window               rootwin;
02168         PLXcairoDrawableInfo *xinfo = (PLXcairoDrawableInfo *) ptr;
02169         signed int           x, y;
02170         unsigned int         w, h, b, d;
02171         if ( xinfo == NULL )
02172         {
02173             printf( "xcairo: PLESC_DEVINIT ignored, no drawable info provided\n" );
02174             return;
02175         }
02176         if ( aStream->xdrawable_mode == 0 )
02177         {
02178             printf( "xcairo: PLESC_DEVINIT called with drawable but stream not in xdrawable mode\n" );
02179             return;
02180         }
02181         aStream->XDisplay = xinfo->display;
02182         aStream->XWindow  = xinfo->drawable;
02183 
02184         // Ensure plplot knows the real dimensions of the drawable
02185         XGetGeometry( aStream->XDisplay, aStream->XWindow, &rootwin,
02186             &x, &y, &w, &h, &b, &d );
02187         pls->xlength = (PLINT) w;
02188         pls->ylength = (PLINT) h;
02189         // Calculate ratio of (smaller) external coordinates used for cairo
02190         // devices to (larger) internal PLplot coordinates.
02191         if ( pls->xlength > pls->ylength )
02192             aStream->downscale = (double) pls->xlength / (double) ( PIXELS_X - 1 );
02193         else
02194             aStream->downscale = (double) pls->ylength / (double) PIXELS_Y;
02195         plP_setphy( (PLINT) 0, (PLINT) ( pls->xlength / aStream->downscale ), (PLINT) 0,
02196             (PLINT) ( pls->ylength / aStream->downscale ) );
02197 
02198         // Associate cairo with the supplied drawable
02199         xcairo_init_cairo( pls );
02200 
02201         // Recalculate dimensions and the like now that the drawable is known
02202         plbop();
02203 
02204         break;
02205     }
02206     default:
02207         plD_esc_cairo( pls, op, ptr );
02208         break;
02209     }
02210 }
02211 
02212 //--------------------------------------------------------------------------
02213 // xcairo_get_cursor()
02214 //
02215 // X Windows: returns the location of the next mouse click or key press.
02216 //--------------------------------------------------------------------------
02217 
02218 void xcairo_get_cursor( PLStream *pls, PLGraphicsIn *gin )
02219 {
02220     const char   *ksname;
02221     char         str[257];
02222     KeySym       keysym;
02223     XEvent       event;
02224     XButtonEvent *xButtonEvent;
02225     Cursor       xHairCursor;
02226     PLCairo      *aStream;
02227 
02228     aStream = (PLCairo *) pls->dev;
02229 
02230     // Initialize PLplot mouse event structure
02231     plGinInit( gin );
02232 
02233     // Create cross hair cursor & switch to using it
02234     xHairCursor = XCreateFontCursor( aStream->XDisplay, XC_crosshair );
02235     XDefineCursor( aStream->XDisplay, aStream->XWindow, xHairCursor );
02236 
02237     // Get the next mouse button release or key press event
02238     XSelectInput( aStream->XDisplay, aStream->XWindow, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask );
02239     XMaskEvent( aStream->XDisplay, ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask, &event );
02240     XSelectInput( aStream->XDisplay, aStream->XWindow, NoEventMask );
02241 
02242     // Update PLplot's mouse event structure
02243     xButtonEvent = (XButtonEvent *) &event;
02244     gin->state   = xButtonEvent->state;
02245     gin->button  = xButtonEvent->button;
02246     gin->pX      = event.xbutton.x;
02247     gin->pY      = pls->ylength - event.xbutton.y;
02248     gin->dX      = (PLFLT) event.xbutton.x / ( (PLFLT) ( pls->xlength ) );
02249     gin->dY      = (PLFLT) ( pls->ylength - event.xbutton.y ) / ( (PLFLT) ( pls->ylength ) );
02250 
02251     // Get key pressed (if any)
02252     if ( event.type == KeyPress || event.type == KeyRelease )
02253     {
02254         XLookupString( (XKeyEvent *) &event, str, 100, &keysym, NULL );
02255         if ( keysym == NoSymbol )
02256             ksname = "NoSymbol";
02257         else if ( !( ksname = XKeysymToString( keysym ) ) )
02258             ksname = "(no name)";
02259         strcpy( gin->string, ksname );
02260         //        gin->string[number_chars] = '\0';
02261         switch ( keysym )
02262         {
02263         case XK_BackSpace:
02264         case XK_Tab:
02265         case XK_Linefeed:
02266         case XK_Return:
02267         case XK_Escape:
02268         case XK_Delete:
02269             gin->keysym = 0xFF & keysym;
02270             break;
02271         default:
02272             gin->keysym = (unsigned int) keysym;
02273         }
02274     }
02275     else // button press
02276     {
02277         sprintf( gin->string, "button %u", gin->button );
02278         gin->keysym = 0x20;
02279     }
02280 
02281     // Switch back to normal cursor
02282     XUndefineCursor( aStream->XDisplay, aStream->XWindow );
02283     XFlush( aStream->XDisplay );
02284 }
02285 
02286 #endif
02287 
02288 
02289 //--------------------------------------------------------------------------
02290 //--------------------------------------------------------------------------
02291 //
02292 // That which is specific to the cairo PDF driver.
02293 //
02294 //--------------------------------------------------------------------------
02295 //--------------------------------------------------------------------------
02296 
02297 #if defined ( PLD_pdfcairo )
02298 
02299 void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt );
02300 void plD_init_pdfcairo( PLStream * );
02301 
02302 //--------------------------------------------------------------------------
02303 // dispatch_init_init()
02304 //
02305 // Initialize device dispatch table
02306 //--------------------------------------------------------------------------
02307 
02308 // pdfcairo
02309 void plD_dispatch_init_pdfcairo( PLDispatchTable *pdt )
02310 {
02311 #ifndef ENABLE_DYNDRIVERS
02312     pdt->pl_MenuStr = "Cairo PDF Driver";
02313     pdt->pl_DevName = "pdfcairo";
02314 #endif
02315     pdt->pl_type     = plDevType_FileOriented;
02316     pdt->pl_seq      = 101;
02317     pdt->pl_init     = (plD_init_fp) plD_init_pdfcairo;
02318     pdt->pl_line     = (plD_line_fp) plD_line_cairo;
02319     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
02320     pdt->pl_eop      = (plD_eop_fp) plD_eop_cairo;
02321     pdt->pl_bop      = (plD_bop_fp) plD_bop_cairo;
02322     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_cairo;
02323     pdt->pl_state    = (plD_state_fp) plD_state_cairo;
02324     pdt->pl_esc      = (plD_esc_fp) plD_esc_cairo;
02325 }
02326 
02327 //--------------------------------------------------------------------------
02328 // plD_init_pdfcairo()
02329 //
02330 // Initialize Cairo PDF device
02331 //--------------------------------------------------------------------------
02332 
02333 void plD_init_pdfcairo( PLStream *pls )
02334 {
02335     PLCairo *aStream;
02336 
02337     // Setup the PLStream and the font lookup table
02338     aStream = stream_and_font_setup( pls, 0 );
02339 
02340     // Prompt for a file name if not already set.
02341     plOpenFile( pls );
02342 
02343     // Create an cairo surface & context for PDF file.
02344     // Dimension units are pts = 1/72 inches from cairo documentation.
02345     aStream->cairoSurface = cairo_pdf_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
02346     aStream->cairoContext = cairo_create( aStream->cairoSurface );
02347 
02348     // Save the pointer to the structure in the PLplot stream
02349     pls->dev = aStream;
02350 
02351     // Invert the surface so that the graphs are drawn right side up.
02352     rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
02353 
02354     // Set graphics aliasing
02355     cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
02356 
02357     // Set fill rule for the case of self-intersecting boundaries.
02358     if ( pls->dev_eofill )
02359         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
02360     else
02361         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
02362 }
02363 
02364 #endif
02365 
02366 
02367 //--------------------------------------------------------------------------
02368 //--------------------------------------------------------------------------
02369 //
02370 // That which is specific to the cairo PS driver.
02371 //
02372 //--------------------------------------------------------------------------
02373 //--------------------------------------------------------------------------
02374 
02375 #if defined ( PLD_pscairo )
02376 
02377 void plD_dispatch_init_pscairo( PLDispatchTable *pdt );
02378 void plD_init_pscairo( PLStream * );
02379 
02380 //--------------------------------------------------------------------------
02381 // dispatch_init_init()
02382 //
02383 // Initialize device dispatch table
02384 //--------------------------------------------------------------------------
02385 
02386 // pscairo
02387 void plD_dispatch_init_pscairo( PLDispatchTable *pdt )
02388 {
02389 #ifndef ENABLE_DYNDRIVERS
02390     pdt->pl_MenuStr = "Cairo PS Driver";
02391     pdt->pl_DevName = "pscairo";
02392 #endif
02393     pdt->pl_type     = plDevType_FileOriented;
02394     pdt->pl_seq      = 102;
02395     pdt->pl_init     = (plD_init_fp) plD_init_pscairo;
02396     pdt->pl_line     = (plD_line_fp) plD_line_cairo;
02397     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
02398     pdt->pl_eop      = (plD_eop_fp) plD_eop_cairo;
02399     pdt->pl_bop      = (plD_bop_fp) plD_bop_cairo;
02400     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_cairo;
02401     pdt->pl_state    = (plD_state_fp) plD_state_cairo;
02402     pdt->pl_esc      = (plD_esc_fp) plD_esc_cairo;
02403 }
02404 
02405 //--------------------------------------------------------------------------
02406 // plD_init_pscairo()
02407 //
02408 // Initialize Cairo PS device
02409 //--------------------------------------------------------------------------
02410 
02411 void plD_init_pscairo( PLStream *pls )
02412 {
02413     PLCairo *aStream;
02414 
02415     // Setup the PLStream and the font lookup table
02416     aStream = stream_and_font_setup( pls, 0 );
02417 
02418     // Prompt for a file name if not already set.
02419     plOpenFile( pls );
02420 
02421     // Create an cairo surface & context for PS file.
02422     // Dimension units are pts = 1/72 inches from cairo documentation.
02423     aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
02424     aStream->cairoContext = cairo_create( aStream->cairoSurface );
02425 
02426     // Save the pointer to the structure in the PLplot stream
02427     pls->dev = aStream;
02428 
02429     // Handle portrait or landscape
02430     if ( pls->portrait )
02431     {
02432         plsdiori( 1 );
02433         pls->freeaspect = 1;
02434     }
02435     rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, (float) pls->ylength, (float) pls->xlength, FALSE );
02436 
02437     // Set fill rule for the case of self-intersecting boundaries.
02438     if ( pls->dev_eofill )
02439         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
02440     else
02441         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
02442 }
02443 
02444 #endif
02445 
02446 
02447 //--------------------------------------------------------------------------
02448 //--------------------------------------------------------------------------
02449 //
02450 // That which is specific to the cairo EPS driver.
02451 //
02452 //--------------------------------------------------------------------------
02453 //--------------------------------------------------------------------------
02454 
02455 #if defined ( PLD_epscairo )
02456 
02457 void plD_dispatch_init_epscairo( PLDispatchTable *pdt );
02458 void plD_init_epscairo( PLStream * );
02459 
02460 //--------------------------------------------------------------------------
02461 // dispatch_init_init()
02462 //
02463 // Initialize device dispatch table
02464 //--------------------------------------------------------------------------
02465 
02466 // epscairo
02467 void plD_dispatch_init_epscairo( PLDispatchTable *pdt )
02468 {
02469 #ifndef ENABLE_DYNDRIVERS
02470     pdt->pl_MenuStr = "Cairo EPS Driver";
02471     pdt->pl_DevName = "epscairo";
02472 #endif
02473     pdt->pl_type     = plDevType_FileOriented;
02474     pdt->pl_seq      = 102;
02475     pdt->pl_init     = (plD_init_fp) plD_init_epscairo;
02476     pdt->pl_line     = (plD_line_fp) plD_line_cairo_fam;
02477     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
02478     pdt->pl_eop      = (plD_eop_fp) plD_eop_cairo_fam;
02479     pdt->pl_bop      = (plD_bop_fp) plD_bop_cairo_fam;
02480     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_cairo_fam;
02481     pdt->pl_state    = (plD_state_fp) plD_state_cairo_fam;
02482     pdt->pl_esc      = (plD_esc_fp) plD_esc_cairo_fam;
02483 }
02484 
02485 //--------------------------------------------------------------------------
02486 // plD_init_epscairo()
02487 //
02488 // Initialize Cairo EPS device
02489 //--------------------------------------------------------------------------
02490 
02491 void plD_init_epscairo( PLStream *pls )
02492 {
02493     PLCairo *aStream;
02494 
02495     // Setup the PLStream and the font lookup table and allocate a cairo
02496     // stream structure.
02497     //
02498     // NOTE: The check below is necessary since, in family mode, this function
02499     //  will be called multiple times. While you might think that it is
02500     //  sufficient to update what *should* be the only pointer to the contents
02501     //  of pls->dev, i.e. the pointer pls->dev itself, it appears that
02502     //  something else somewhere else is also pointing to pls->dev. If you
02503     //  change what pls->dev points to then you will get a "bus error", from
02504     //  which I infer the existence of said bad stale pointer.
02505     //
02506     if ( pls->dev == NULL )
02507     {
02508         aStream = stream_and_font_setup( pls, 0 );
02509     }
02510     else
02511     {
02512         stream_and_font_setup( pls, 0 );
02513         aStream = pls->dev;
02514     }
02515 
02516     // Initialize family file info
02517     plFamInit( pls );
02518 
02519     // Prompt for a file name if not already set.
02520     plOpenFile( pls );
02521 
02522     // Create an cairo surface & context for EPS file.
02523     // Dimension units are pts = 1/72 inches from cairo documentation.
02524     aStream->cairoSurface = cairo_ps_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->ylength, (double) pls->xlength );
02525     aStream->cairoContext = cairo_create( aStream->cairoSurface );
02526 
02527     // Set the PS surface to be EPS.
02528     cairo_ps_surface_set_eps( aStream->cairoSurface, 1 );
02529 
02530     // Save the pointer to the structure in the PLplot stream
02531     pls->dev = aStream;
02532 
02533     // Handle portrait or landscape
02534     if ( pls->portrait )
02535     {
02536         plsdiori( 1 );
02537         pls->freeaspect = 1;
02538     }
02539     rotate_cairo_surface( pls, 0.0, -1.0, -1.0, 0.0, (float) pls->ylength, (float) pls->xlength, FALSE );
02540 
02541     // Set fill rule for the case of self-intersecting boundaries.
02542     if ( pls->dev_eofill )
02543         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
02544     else
02545         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
02546 }
02547 
02548 #endif
02549 
02550 
02551 //--------------------------------------------------------------------------
02552 //--------------------------------------------------------------------------
02553 //
02554 // That which is specific to the cairo SVG driver.
02555 //
02556 //--------------------------------------------------------------------------
02557 //--------------------------------------------------------------------------
02558 
02559 #if defined ( PLD_svgcairo )
02560 
02561 void plD_dispatch_init_svgcairo( PLDispatchTable *pdt );
02562 void plD_init_svgcairo( PLStream * );
02563 
02564 //--------------------------------------------------------------------------
02565 // dispatch_init_init()
02566 //
02567 // Initialize device dispatch table
02568 //--------------------------------------------------------------------------
02569 
02570 // svgcairo
02571 void plD_dispatch_init_svgcairo( PLDispatchTable *pdt )
02572 {
02573 #ifndef ENABLE_DYNDRIVERS
02574     pdt->pl_MenuStr = "Cairo SVG Driver";
02575     pdt->pl_DevName = "svgcairo";
02576 #endif
02577     pdt->pl_type     = plDevType_FileOriented;
02578     pdt->pl_seq      = 103;
02579     pdt->pl_init     = (plD_init_fp) plD_init_svgcairo;
02580     pdt->pl_line     = (plD_line_fp) plD_line_cairo_fam;
02581     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
02582     pdt->pl_eop      = (plD_eop_fp) plD_eop_cairo_fam;
02583     pdt->pl_bop      = (plD_bop_fp) plD_bop_cairo_fam;
02584     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_cairo_fam;
02585     pdt->pl_state    = (plD_state_fp) plD_state_cairo_fam;
02586     pdt->pl_esc      = (plD_esc_fp) plD_esc_cairo_fam;
02587 }
02588 
02589 //--------------------------------------------------------------------------
02590 // plD_init_svgcairo()
02591 //
02592 // Initialize Cairo SVG device
02593 //--------------------------------------------------------------------------
02594 
02595 void plD_init_svgcairo( PLStream *pls )
02596 {
02597     PLCairo *aStream;
02598 
02599     // Setup the PLStream and the font lookup table and allocate a cairo
02600     // stream structure.
02601     //
02602     // NOTE: The check below is necessary since, in family mode, this function
02603     //  will be called multiple times. While you might think that it is
02604     //  sufficient to update what *should* be the only pointer to the contents
02605     //  of pls->dev, i.e. the pointer pls->dev itself, it appears that
02606     //  something else somewhere else is also pointing to pls->dev. If you
02607     //  change what pls->dev points to then you will get a "bus error", from
02608     //  which I infer the existence of said bad stale pointer.
02609     //
02610     if ( pls->dev == NULL )
02611     {
02612         aStream = stream_and_font_setup( pls, 0 );
02613     }
02614     else
02615     {
02616         stream_and_font_setup( pls, 0 );
02617         aStream = pls->dev;
02618     }
02619 
02620     // Initialize family file info
02621     plFamInit( pls );
02622 
02623     // Prompt for a file name if not already set.
02624     plOpenFile( pls );
02625 
02626     // Save the pointer to the structure in the PLplot stream
02627     pls->dev = aStream;
02628 
02629     // Create an cairo surface & context for SVG file.
02630     // Dimension units are pts = 1/72 inches from cairo documentation.
02631     aStream->cairoSurface = cairo_svg_surface_create_for_stream( (cairo_write_func_t) write_to_stream, pls->OutFile, (double) pls->xlength, (double) pls->ylength );
02632     aStream->cairoContext = cairo_create( aStream->cairoSurface );
02633 
02634     // Invert the surface so that the graphs are drawn right side up.
02635     rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
02636 
02637     // Set graphics aliasing
02638     cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
02639 
02640     // Set fill rule for the case of self-intersecting boundaries.
02641     if ( pls->dev_eofill )
02642         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
02643     else
02644         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
02645 }
02646 
02647 #endif
02648 
02649 
02650 //--------------------------------------------------------------------------
02651 //--------------------------------------------------------------------------
02652 //
02653 // That which is specific to the cairo PNG driver.
02654 //
02655 //--------------------------------------------------------------------------
02656 //--------------------------------------------------------------------------
02657 
02658 #if defined ( PLD_pngcairo )
02659 
02660 void plD_dispatch_init_pngcairo( PLDispatchTable *pdt );
02661 void plD_init_pngcairo( PLStream * );
02662 void plD_eop_pngcairo( PLStream * );
02663 
02664 //--------------------------------------------------------------------------
02665 // dispatch_init_init()
02666 //
02667 // Initialize device dispatch table
02668 //--------------------------------------------------------------------------
02669 
02670 // pngcairo
02671 void plD_dispatch_init_pngcairo( PLDispatchTable *pdt )
02672 {
02673 #ifndef ENABLE_DYNDRIVERS
02674     pdt->pl_MenuStr = "Cairo PNG Driver";
02675     pdt->pl_DevName = "pngcairo";
02676 #endif
02677     pdt->pl_type     = plDevType_FileOriented;
02678     pdt->pl_seq      = 104;
02679     pdt->pl_init     = (plD_init_fp) plD_init_pngcairo;
02680     pdt->pl_line     = (plD_line_fp) plD_line_cairo_fam;
02681     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo_fam;
02682     pdt->pl_eop      = (plD_eop_fp) plD_eop_pngcairo;
02683     pdt->pl_bop      = (plD_bop_fp) plD_bop_cairo_fam;
02684     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_cairo_fam;
02685     pdt->pl_state    = (plD_state_fp) plD_state_cairo_fam;
02686     pdt->pl_esc      = (plD_esc_fp) plD_esc_cairo_fam;
02687 }
02688 
02689 //--------------------------------------------------------------------------
02690 // plD_init_pngcairo()
02691 //
02692 // Initialize Cairo PNG device
02693 //--------------------------------------------------------------------------
02694 
02695 void plD_init_pngcairo( PLStream *pls )
02696 {
02697     PLCairo *aStream;
02698 
02699     // Setup the PLStream and the font lookup table and allocate a cairo
02700     // stream structure.
02701     //
02702     // NOTE: The check below is necessary since, in family mode, this function
02703     //  will be called multiple times. While you might think that it is
02704     //  sufficient to update what *should* be the only pointer to the contents
02705     //  of pls->dev, i.e. the pointer pls->dev itself, it appears that
02706     //  something else somewhere else is also pointing to pls->dev. If you
02707     //  change what pls->dev points to then you will get a "bus error", from
02708     //  which I infer the existence of said bad stale pointer.
02709     //
02710     if ( pls->dev == NULL )
02711     {
02712         aStream = stream_and_font_setup( pls, 0 );
02713     }
02714     else
02715     {
02716         stream_and_font_setup( pls, 0 );
02717         aStream = pls->dev;
02718     }
02719 
02720     // Initialize family file info
02721     plFamInit( pls );
02722 
02723     // Prompt for a file name if not already set.
02724     plOpenFile( pls );
02725 
02726     // Save the pointer to the structure in the PLplot stream
02727     pls->dev = aStream;
02728 
02729     // Create a new cairo surface & context for PNG file.
02730     // Dimension units are pixels from cairo documentation.
02731     aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (int) pls->xlength, (int) pls->ylength );
02732     aStream->cairoContext = cairo_create( aStream->cairoSurface );
02733 
02734     // Invert the surface so that the graphs are drawn right side up.
02735     rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
02736 
02737     // Set graphics aliasing
02738     cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
02739 
02740     // Set fill rule for the case of self-intersecting boundaries.
02741     if ( pls->dev_eofill )
02742         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
02743     else
02744         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
02745 }
02746 
02747 //--------------------------------------------------------------------------
02748 // plD_eop_pngcairo()
02749 //
02750 // PNG: End of page.
02751 //--------------------------------------------------------------------------
02752 
02753 void plD_eop_pngcairo( PLStream *pls )
02754 {
02755     PLCairo *aStream;
02756 
02757     if ( cairo_family_check( pls ) )
02758     {
02759         return;
02760     }
02761 
02762     aStream = (PLCairo *) pls->dev;
02763     cairo_surface_write_to_png_stream( aStream->cairoSurface, (cairo_write_func_t) write_to_stream, pls->OutFile );
02764 }
02765 
02766 #endif
02767 
02768 
02769 //--------------------------------------------------------------------------
02770 //--------------------------------------------------------------------------
02771 //
02772 // That which is specific to the cairo memory driver.
02773 //
02774 //--------------------------------------------------------------------------
02775 //--------------------------------------------------------------------------
02776 
02777 #if defined ( PLD_memcairo )
02778 
02779 void plD_dispatch_init_memcairo( PLDispatchTable *pdt );
02780 void plD_init_memcairo( PLStream * );
02781 void plD_eop_memcairo( PLStream * );
02782 void plD_bop_memcairo( PLStream * );
02783 
02784 //--------------------------------------------------------------------------
02785 // dispatch_init_init()
02786 //
02787 // Initialize device dispatch table
02788 //--------------------------------------------------------------------------
02789 
02790 // memcairo
02791 void plD_dispatch_init_memcairo( PLDispatchTable *pdt )
02792 {
02793 #ifndef ENABLE_DYNDRIVERS
02794     pdt->pl_MenuStr = "Cairo memory driver";
02795     pdt->pl_DevName = "memcairo";
02796 #endif
02797     pdt->pl_type     = plDevType_FileOriented;
02798     pdt->pl_seq      = 105;
02799     pdt->pl_init     = (plD_init_fp) plD_init_memcairo;
02800     pdt->pl_line     = (plD_line_fp) plD_line_cairo;
02801     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
02802     pdt->pl_eop      = (plD_eop_fp) plD_eop_memcairo;
02803     pdt->pl_bop      = (plD_bop_fp) plD_bop_memcairo;
02804     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_cairo;
02805     pdt->pl_state    = (plD_state_fp) plD_state_cairo;
02806     pdt->pl_esc      = (plD_esc_fp) plD_esc_cairo;
02807 }
02808 
02809 //--------------------------------------------------------------------------
02810 // plD_bop_memcairo()
02811 //
02812 // Set up for the next page.
02813 //--------------------------------------------------------------------------
02814 
02815 void plD_bop_memcairo( PLStream * PL_UNUSED( pls ) )
02816 {
02817     // nothing to do here (we want to preserve the memory as it is)
02818 }
02819 
02820 //--------------------------------------------------------------------------
02821 // plD_init_memcairo()
02822 //
02823 // Initialize Cairo memory device
02824 //--------------------------------------------------------------------------
02825 
02826 void plD_init_memcairo( PLStream *pls )
02827 {
02828     PLCairo       *aStream;
02829     int           stride, i;
02830     unsigned char *cairo_mem;
02831     unsigned char *input_mem;
02832 
02833     // used for checking byte order
02834     union
02835     {
02836         int  testWord;
02837         char testByte[sizeof ( int )];
02838     } endianTest;
02839     endianTest.testWord = 1;
02840 
02841     // Set the plot size to the memory buffer size, on the off chance
02842     // that they are different.
02843     pls->xlength = pls->phyxma;
02844     pls->ylength = pls->phyyma;
02845 
02846 
02847     // Setup the PLStream and the font lookup table
02848     aStream = stream_and_font_setup( pls, 0 );
02849 
02850     // Test byte order
02851     if ( endianTest.testByte[0] == 1 )
02852         aStream->bigendian = 0;
02853     else
02854         aStream->bigendian = 1;
02855 
02856     // Check that user supplied us with some memory to draw in
02857     if ( pls->dev == NULL )
02858     {
02859         plexit( "Must call plsmem first to set user plotting area!" );
02860     }
02861 
02862     // Save a pointer to the memory.
02863     aStream->memory = pls->dev;
02864 
02865     // Create a cairo surface & context.  Copy data in from the input memory area
02866 
02867     // Malloc memory the way cairo likes it.  Aligned on the stride computed by cairo_format_stride_for_width
02868     // and in the RGB24 format (from http://cairographics.org/manual/cairo-Image-Surfaces.html):
02869     // Each pixel is a 32-bit quantity, with the upper 8 bits unused.
02870     // Red, Green, and Blue are stored in the remaining 24 bits in that order
02871     stride = pls->xlength * 4;
02872     // stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, pls->xlength);  This function missing from version 1.4 :-(
02873     aStream->cairo_format_memory = (unsigned char *) calloc( (size_t) ( stride * pls->ylength ), 1 );
02874 
02875     // Copy the input data into the Cairo data format
02876     cairo_mem = aStream->cairo_format_memory;
02877     input_mem = aStream->memory;
02878 
02879     // 32 bit word order
02880     // cairo mem:  Big endian:  0=A, 1=R, 2=G, 3=B
02881     //             Little endian:  3=A, 2=R, 1=G, 0=B
02882 
02883     if ( aStream->bigendian )
02884     {
02885         for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
02886         {
02887             cairo_mem[1] = input_mem[0]; // R
02888             cairo_mem[2] = input_mem[1]; // G
02889             cairo_mem[3] = input_mem[2]; // B
02890             if ( pls->dev_mem_alpha == 1 )
02891             {
02892                 cairo_mem[0] = input_mem[3];
02893                 input_mem   += 4;
02894             }
02895             else
02896             {
02897                 input_mem += 3;
02898             }
02899             cairo_mem += 4;
02900         }
02901     }
02902     else
02903     {
02904         for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
02905         {
02906             cairo_mem[2] = input_mem[0]; // R
02907             cairo_mem[1] = input_mem[1]; // G
02908             cairo_mem[0] = input_mem[2]; // B
02909             if ( pls->dev_mem_alpha == 1 )
02910             {
02911                 cairo_mem[3] = input_mem[3];
02912                 input_mem   += 4;
02913             }
02914             else
02915             {
02916                 input_mem += 3;
02917             }
02918             cairo_mem += 4;
02919         }
02920     }
02921 
02922     // Create a Cairo drawing surface from the input data
02923     aStream->cairoSurface =
02924         // Dimension units are width, height of buffer image from cairo
02925         // documentation.
02926         cairo_image_surface_create_for_data( aStream->cairo_format_memory, CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength, stride );
02927     aStream->cairoContext = cairo_create( aStream->cairoSurface );
02928 
02929     // Save the pointer to the structure in the PLplot stream.
02930     // Note that this wipes out the direct pointer to the memory buffer.
02931     pls->dev = aStream;
02932 
02933     // Invert the surface so that the graphs are drawn right side up.
02934     rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
02935 
02936     // Set graphics aliasing
02937     cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
02938 
02939     // Set fill rule for the case of self-intersecting boundaries.
02940     if ( pls->dev_eofill )
02941         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
02942     else
02943         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
02944 }
02945 
02946 //--------------------------------------------------------------------------
02947 // plD_eop_memcairo()
02948 //
02949 // Memory device specific end of page. This copies the contents
02950 // of the cairo surface into the user supplied memory buffer.
02951 //--------------------------------------------------------------------------
02952 
02953 void plD_eop_memcairo( PLStream *pls )
02954 {
02955     int           i;
02956     unsigned char *memory;
02957     unsigned char *cairo_surface_data;
02958     PLCairo       *aStream;
02959 
02960     aStream            = (PLCairo *) pls->dev;
02961     memory             = aStream->memory;
02962     cairo_surface_data = cairo_image_surface_get_data( aStream->cairoSurface );
02963     // 32 bit word order
02964     // cairo mem:  Big endian:  0=A, 1=R, 2=G, 3=B
02965     //             Little endian:  3=A, 2=R, 1=G, 0=B
02966     if ( aStream->bigendian )
02967     {
02968         for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
02969         {
02970             memory[0] = cairo_surface_data[1];           // R
02971             memory[1] = cairo_surface_data[2];           // G
02972             memory[2] = cairo_surface_data[3];           // B
02973             if ( pls->dev_mem_alpha == 1 )
02974             {
02975                 memory[3] = cairo_surface_data[0];
02976                 memory   += 4;
02977             }
02978             else
02979             {
02980                 memory += 3;
02981             }
02982             cairo_surface_data += 4;
02983         }
02984     }
02985     else
02986     {
02987         for ( i = 0; i < ( pls->xlength * pls->ylength ); i++ )
02988         {
02989             memory[0] = cairo_surface_data[2];           // R
02990             memory[1] = cairo_surface_data[1];           // G
02991             memory[2] = cairo_surface_data[0];           // B
02992             if ( pls->dev_mem_alpha == 1 )
02993             {
02994                 memory[3] = cairo_surface_data[3];
02995                 memory   += 4;
02996             }
02997             else
02998             {
02999                 memory += 3;
03000             }
03001             cairo_surface_data += 4;
03002         }
03003     }
03004 
03005     // Free up the temporary memory malloc'ed in plD_init_memcairo
03006     free( aStream->cairo_format_memory );
03007 }
03008 
03009 #endif
03010 
03011 //--------------------------------------------------------------------------
03012 //--------------------------------------------------------------------------
03013 //
03014 // That which is specific to the cairo external context driver.
03015 //
03016 //--------------------------------------------------------------------------
03017 //--------------------------------------------------------------------------
03018 
03019 #if defined ( PLD_extcairo )
03020 
03021 void extcairo_setbackground( PLStream * );
03022 void plD_dispatch_init_extcairo( PLDispatchTable *pdt );
03023 void plD_init_extcairo( PLStream * );
03024 void plD_bop_extcairo( PLStream * );
03025 void plD_eop_extcairo( PLStream * );
03026 void plD_esc_extcairo( PLStream *, PLINT, void * );
03027 void plD_tidy_extcairo( PLStream * );
03028 
03029 //--------------------------------------------------------------------------
03030 // extcairo_setbackground()
03031 //
03032 // Set the background color for the extcairo device
03033 //--------------------------------------------------------------------------
03034 
03035 void extcairo_setbackground( PLStream *pls )
03036 {
03037     PLCairo *aStream;
03038 
03039     aStream = (PLCairo *) pls->dev;
03040 
03041     // Fill the context with the background color if the user so desires.
03042     if ( aStream->cairoContext != NULL )
03043     {
03044         cairo_rectangle( aStream->cairoContext, 0.0, 0.0, pls->xlength, pls->ylength );
03045         cairo_set_source_rgba( aStream->cairoContext,
03046             (double) pls->cmap0[0].r / 255.0,
03047             (double) pls->cmap0[0].g / 255.0,
03048             (double) pls->cmap0[0].b / 255.0,
03049             (double) pls->cmap0[0].a );
03050         cairo_fill( aStream->cairoContext );
03051     }
03052 }
03053 
03054 //--------------------------------------------------------------------------
03055 // dispatch_init_init()
03056 //
03057 // Initialize device dispatch table
03058 //--------------------------------------------------------------------------
03059 
03060 // extcairo
03061 void plD_dispatch_init_extcairo( PLDispatchTable *pdt )
03062 {
03063 #ifndef ENABLE_DYNDRIVERS
03064     pdt->pl_MenuStr = "Cairo external context driver";
03065     pdt->pl_DevName = "extcairo";
03066 #endif
03067     pdt->pl_type     = plDevType_Interactive;
03068     pdt->pl_seq      = 106;
03069     pdt->pl_init     = (plD_init_fp) plD_init_extcairo;
03070     pdt->pl_line     = (plD_line_fp) plD_line_cairo;
03071     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
03072     pdt->pl_bop      = (plD_bop_fp) plD_bop_extcairo;
03073     pdt->pl_eop      = (plD_eop_fp) plD_eop_extcairo;
03074     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_extcairo;
03075     pdt->pl_state    = (plD_state_fp) plD_state_cairo;
03076     pdt->pl_esc      = (plD_esc_fp) plD_esc_extcairo;
03077 }
03078 
03079 //--------------------------------------------------------------------------
03080 // plD_init_extcairo()
03081 //
03082 // Initialize Cairo external context driver.
03083 //--------------------------------------------------------------------------
03084 
03085 void plD_init_extcairo( PLStream *pls )
03086 {
03087     PLCairo *aStream;
03088 
03089     // Setup the PLStream and the font lookup table
03090     aStream = stream_and_font_setup( pls, 0 );
03091 
03092     // Save the pointer to the structure in the PLplot stream
03093     pls->dev = aStream;
03094 }
03095 
03096 //--------------------------------------------------------------------------
03097 // plD_bop_extcairo()
03098 //
03099 // Set up for the next page.
03100 //--------------------------------------------------------------------------
03101 
03102 void plD_bop_extcairo( PLStream *pls )
03103 {
03104     PLCairo *aStream;
03105 
03106     aStream = (PLCairo *) pls->dev;
03107 
03108     // Set background if desired
03109     if ( aStream->set_background )
03110     {
03111         extcairo_setbackground( pls );
03112     }
03113 }
03114 
03115 //--------------------------------------------------------------------------
03116 // plD_eop_extcairo()
03117 //
03118 // End of page.
03119 //--------------------------------------------------------------------------
03120 
03121 void plD_eop_extcairo( PLStream * PL_UNUSED( pls ) )
03122 {
03123     // nothing to do here, we leave it to the calling program to display
03124     // (or not) the update cairo context.
03125 }
03126 
03127 //--------------------------------------------------------------------------
03128 // plD_esc_extcairo()
03129 //
03130 // The generic escape function, extended so that user can pass in
03131 // an external Cairo context to use for rendering.
03132 //--------------------------------------------------------------------------
03133 
03134 void plD_esc_extcairo( PLStream *pls, PLINT op, void *ptr )
03135 {
03136     PLCairo *aStream;
03137 
03138     aStream = (PLCairo *) pls->dev;
03139 
03140     switch ( op )
03141     {
03142     case PLESC_DEVINIT: // Set external context
03143         aStream->cairoContext = (cairo_t *) ptr;
03144         // Set graphics aliasing
03145         cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
03146 
03147         // Invert the surface so that the graphs are drawn right side up.
03148         rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, (float) pls->ylength, FALSE );
03149 
03150         // Should adjust plot size to fit in the given cairo context?
03151         // Cairo does not provide a way to query the dimensions of a context?
03152 
03153         // Set background if desired
03154         if ( aStream->set_background )
03155         {
03156             extcairo_setbackground( pls );
03157         }
03158 
03159         // Set fill rule for the case of self-intersecting boundaries.
03160         if ( pls->dev_eofill )
03161             cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
03162         else
03163             cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
03164         break;
03165     default: // Fall back on default Cairo actions
03166         plD_esc_cairo( pls, op, ptr );
03167         break;
03168     }
03169 }
03170 
03171 //--------------------------------------------------------------------------
03172 // plD_tidy_extcairo()
03173 //
03174 // This is nop, it is up to the calling program to clean up the Cairo
03175 // context, etc...
03176 //--------------------------------------------------------------------------
03177 
03178 void plD_tidy_extcairo( PLStream * PL_UNUSED( pls ) )
03179 {
03180 }
03181 
03182 #endif
03183 
03184 
03185 //--------------------------------------------------------------------------
03186 //--------------------------------------------------------------------------
03187 //
03188 // That which is specific to the cairo microsoft windows driver.
03189 //
03190 // Much of the Windows specific code here was lifted from the wingcc
03191 // driver.
03192 //
03193 //--------------------------------------------------------------------------
03194 //--------------------------------------------------------------------------
03195 
03196 #if defined ( PLD_wincairo )
03197 
03198 static char* szWndClass = "PLplot WinCairo";
03199 
03200 void plD_dispatch_init_wincairo( PLDispatchTable *pdt );
03201 void plD_init_wincairo( PLStream * );
03202 //void plD_bop_extcairo( PLStream * );
03203 void plD_eop_wincairo( PLStream * );
03204 void plD_esc_wincairo( PLStream *, PLINT, void * );
03205 void plD_tidy_wincairo( PLStream * );
03206 
03207 //--------------------------------------------------------------------------
03208 // blit_to_win()
03209 //
03210 // Blit the offscreen image to the Windows window.
03211 //--------------------------------------------------------------------------
03212 
03213 void blit_to_win( PLCairo *aStream )
03214 {
03215     cairo_set_source_surface( aStream->cairoContext_win, aStream->cairoSurface, 0.0, 0.0 );
03216     cairo_paint( aStream->cairoContext_win );
03217 }
03218 
03219 //--------------------------------------------------------------------------
03220 // This is the window function for the plot window. Whenever a message is
03221 // dispatched using DispatchMessage (or sent with SendMessage) this function
03222 // gets called with the contents of the message.
03223 //--------------------------------------------------------------------------
03224 
03225 LRESULT CALLBACK PlplotCairoWndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
03226 {
03227     PLStream *pls = NULL;
03228     PLCairo  *dev = NULL;
03229 
03230 //
03231 // The window carries a 32bit user defined pointer which points to the
03232 // plplot stream (pls). This is used for tracking the window.
03233 // Unfortunately, this is "attached" to the window AFTER it is created
03234 // so we can not initialise PLStream or wincairo "blindly" because
03235 // they may not yet have been initialised.
03236 // WM_CREATE is called before we get to initialise those variables, so
03237 // we wont try to set them.
03238 //
03239 
03240     if ( nMsg == WM_CREATE )
03241     {
03242         return ( 0 );
03243     }
03244     else
03245     {
03246         pls = (PLStream *) GetWindowLong( hwnd, GWL_USERDATA ); // Try to get the address to pls for this window
03247         if ( pls )                                              // If we got it, then we will initialise this windows plplot private data area
03248         {
03249             dev = (PLCairo *) pls->dev;
03250         }
03251     }
03252 
03253 //
03254 // Process the windows messages
03255 //
03256 // Everything except WM_CREATE is done here and it is generally hoped that
03257 // pls and dev are defined already by this stage.
03258 // That will be true MOST of the time. Some times WM_PAINT will be called
03259 // before we get to initialise the user data area of the window with the
03260 // pointer to the windows plplot stream
03261 //
03262 
03263     switch ( nMsg )
03264     {
03265     case WM_DESTROY:
03266         //        if ( dev )
03267         //            Debug( "WM_DESTROY\t" );
03268         PostQuitMessage( 0 );
03269         return ( 0 );
03270         break;
03271 
03272     case WM_PAINT:
03273         blit_to_win( dev );
03274         return ( 1 );
03275         break;
03276 
03277     case WM_SIZE:
03278         GetClientRect( dev->hwnd, &dev->rect );
03279         return ( 0 );
03280         break;
03281 
03282     case WM_ENTERSIZEMOVE:
03283         return ( 0 );
03284         break;
03285 
03286     case WM_EXITSIZEMOVE:
03287         return ( 0 );
03288         break;
03289 
03290     case WM_ERASEBKGND:
03291         if ( dev )
03292         {
03293             dev->oldcolour = SetBkColor( dev->hdc, RGB( pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b ) );
03294             ExtTextOut( dev->hdc, 0, 0, ETO_OPAQUE, &dev->rect, "", 0, 0 );
03295             SetBkColor( dev->hdc, dev->oldcolour );
03296         }
03297         return ( 1 );
03298         break;
03299 
03300     case WM_COMMAND:
03301         return ( 0 );
03302         break;
03303     }
03304 
03305     // If we don't handle a message completely we hand it to the system
03306     // provided default window function.
03307     return DefWindowProc( hwnd, nMsg, wParam, lParam );
03308 }
03309 
03310 //--------------------------------------------------------------------------
03311 // handle_locate()
03312 //
03313 // Handle getting the cursor location.
03314 //--------------------------------------------------------------------------
03315 
03316 void
03317 handle_locate( PLStream *pls, PLGraphicsIn *gin )
03318 {
03319     int     located  = 0;
03320     PLCairo *aStream = (PLCairo *) pls->dev;
03321 
03322     // Initialize PLplot mouse event structure
03323     plGinInit( gin );
03324 
03325     while ( GetMessage( &aStream->msg, NULL, 0, 0 ) && !located )
03326     {
03327         TranslateMessage( &aStream->msg );
03328 
03329         switch ( (int) aStream->msg.message )
03330         {
03331         case WM_MOUSEMOVE:
03332         case WM_LBUTTONDOWN:
03333             gin->state  = 1;
03334             gin->button = 1;
03335             gin->pX     = LOWORD( aStream->msg.lParam );
03336             gin->pY     = pls->ylength - HIWORD( aStream->msg.lParam );
03337             gin->dX     = (PLFLT) LOWORD( aStream->msg.lParam ) / ( (PLFLT) pls->xlength );
03338             gin->dY     = (PLFLT) ( pls->ylength - HIWORD( aStream->msg.lParam ) ) / ( (PLFLT) pls->ylength );
03339             break;
03340         case WM_CHAR:
03341             gin->keysym = aStream->msg.wParam;
03342             located     = 1;
03343             break;
03344 
03345         default:
03346             DispatchMessage( &aStream->msg );
03347             break;
03348         }
03349     }
03350 }
03351 
03352 //--------------------------------------------------------------------------
03353 // dispatch_init_init()
03354 //
03355 // Initialize device dispatch table
03356 //--------------------------------------------------------------------------
03357 
03358 // extcairo
03359 void plD_dispatch_init_wincairo( PLDispatchTable *pdt )
03360 {
03361 #ifndef ENABLE_DYNDRIVERS
03362     pdt->pl_MenuStr = "Cairo Microsoft Windows driver";
03363     pdt->pl_DevName = "wincairo";
03364 #endif
03365     pdt->pl_type     = plDevType_Interactive;
03366     pdt->pl_seq      = 107;
03367     pdt->pl_init     = (plD_init_fp) plD_init_wincairo;
03368     pdt->pl_line     = (plD_line_fp) plD_line_cairo;
03369     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_cairo;
03370     pdt->pl_bop      = (plD_bop_fp) plD_bop_cairo;
03371     pdt->pl_eop      = (plD_eop_fp) plD_eop_wincairo;
03372     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_wincairo;
03373     pdt->pl_state    = (plD_state_fp) plD_state_cairo;
03374     pdt->pl_esc      = (plD_esc_fp) plD_esc_wincairo;
03375 }
03376 
03377 //--------------------------------------------------------------------------
03378 // plD_init_wincairo()
03379 //
03380 // Initialize Cairo Microsoft Windows driver.
03381 //--------------------------------------------------------------------------
03382 
03383 void plD_init_wincairo( PLStream *pls )
03384 {
03385     PLCairo *aStream;
03386 
03387     // Setup the PLStream and the font lookup table
03388     aStream = stream_and_font_setup( pls, 1 );
03389 
03390     // Save the pointer to the structure in the PLplot stream
03391     pls->dev = aStream;
03392 
03393     // Create window
03394     memset( &aStream->wndclass, 0, sizeof ( WNDCLASSEX ) );
03395 
03396     // This class is called WinTestWin
03397     aStream->wndclass.lpszClassName = szWndClass;
03398 
03399     // cbSize gives the size of the structure for extensibility.
03400     aStream->wndclass.cbSize = sizeof ( WNDCLASSEX );
03401 
03402     // All windows of this class redraw when resized.
03403     aStream->wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC | CS_PARENTDC;
03404 
03405     // All windows of this class use the PlplotCairoWndProc window function.
03406     aStream->wndclass.lpfnWndProc = PlplotCairoWndProc;
03407 
03408     // This class is used with the current program instance.
03409 
03410     aStream->wndclass.hInstance = GetModuleHandle( NULL );
03411 
03412     // Use standard application icon and arrow cursor provided by the OS
03413     aStream->wndclass.hIcon   = LoadIcon( NULL, IDI_APPLICATION );
03414     aStream->wndclass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
03415     aStream->wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
03416     // Color the background white
03417     aStream->wndclass.hbrBackground = NULL;
03418 
03419     aStream->wndclass.cbWndExtra = sizeof ( pls );
03420 
03421 
03422     //
03423     // Now register the window class for use.
03424     //
03425 
03426     RegisterClassEx( &aStream->wndclass );
03427 
03428     //
03429     // Create our main window using that window class.
03430     //
03431     aStream->hwnd = CreateWindowEx( WS_EX_WINDOWEDGE + WS_EX_LEFT,
03432         szWndClass,                                         // Class name
03433         pls->program,                                       // Caption
03434         WS_OVERLAPPEDWINDOW,                                // Style
03435         pls->xoffset,                                       // Initial x (use default)
03436         pls->yoffset,                                       // Initial y (use default)
03437                                                             // This is a little lame since the window border size might change.
03438         pls->xlength + 5,                                   // Initial x size (use default)
03439         pls->ylength + 30,                                  // Initial y size (use default)
03440         NULL,                                               // No parent window
03441         NULL,                                               // No menu
03442         aStream->wndclass.hInstance,                        // This program instance
03443         NULL                                                // Creation parameters
03444         );
03445 
03446 
03447 //
03448 // Attach a pointer to the stream to the window's user area
03449 // this pointer will be used by the windows call back for
03450 // process this window
03451 //
03452 
03453     SetWindowLong( aStream->hwnd, GWL_USERDATA, (long) pls );
03454     aStream->SCRN_hdc = aStream->hdc = GetDC( aStream->hwnd );
03455 
03456 //
03457 //  Setup the popup menu
03458 //
03459 
03460 //
03461 //  dev->PopupMenu = CreatePopupMenu();
03462 //  AppendMenu( dev->PopupMenu, MF_STRING, PopupPrint, "Print" );
03463 //  AppendMenu( dev->PopupMenu, MF_STRING, PopupNextPage, "Next Page" );
03464 //  AppendMenu( dev->PopupMenu, MF_STRING, PopupQuit, "Quit" );
03465 //
03466 
03467     //    plD_state_wingcc( pls, PLSTATE_COLOR0 );
03468     //
03469     // Display the window which we just created (using the nShow
03470     // passed by the OS, which allows for start minimized and that
03471     // sort of thing).
03472     //
03473     ShowWindow( aStream->hwnd, SW_SHOWDEFAULT );
03474     SetForegroundWindow( aStream->hwnd );
03475 
03476 //
03477 //  Now we have to find out, from windows, just how big our drawing area is
03478 //  when we specified the page size earlier on, that includes the borders,
03479 //  title bar etc... so now that windows has done all its initialisations,
03480 //  we will ask how big the drawing area is, and tell plplot
03481 //
03482 
03483 //
03484 //  GetClientRect( dev->hwnd, &dev->rect );
03485 //  dev->width  = dev->rect.right;
03486 //  dev->height = dev->rect.bottom;
03487 //
03488 
03489 //
03490 // Initialize Cairo Surface using the windows hdc.
03491 //
03492 
03493     // This is the Win32 Cairo surface.
03494     aStream->cairoSurface_win = (cairo_surface_t *) cairo_win32_surface_create( aStream->hdc );
03495     aStream->cairoContext_win = cairo_create( aStream->cairoSurface_win );
03496 
03497     // This is the Cairo surface PLplot will actually plot to.
03498     aStream->cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, pls->xlength, pls->ylength );
03499     aStream->cairoContext = cairo_create( aStream->cairoSurface );
03500 
03501     // Invert the surface so that the graphs are drawn right side up.
03502     rotate_cairo_surface( pls, 1.0, 0.0, 0.0, -1.0, 0.0, pls->ylength, FALSE );
03503 
03504     // Set graphics aliasing
03505     cairo_set_antialias( aStream->cairoContext, aStream->graphics_anti_aliasing );
03506 
03507     // Set fill rule for the case of self-intersecting boundaries.
03508     if ( pls->dev_eofill )
03509         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_EVEN_ODD );
03510     else
03511         cairo_set_fill_rule( aStream->cairoContext, CAIRO_FILL_RULE_WINDING );
03512 }
03513 
03514 //--------------------------------------------------------------------------
03515 // plD_eop_wincairo()
03516 //
03517 // Clean up Cairo Microsoft Windows driver.
03518 //--------------------------------------------------------------------------
03519 
03520 void
03521 plD_eop_wincairo( PLStream *pls )
03522 {
03523     PLCairo *aStream = (PLCairo *) pls->dev;
03524 
03525     if ( !pls->nopause )
03526     {
03527         while ( GetMessage( &aStream->msg, NULL, 0, 0 ) )
03528         {
03529             TranslateMessage( &aStream->msg );
03530             switch ( (int) aStream->msg.message )
03531             {
03532             case WM_CHAR:
03533                 if ( ( (TCHAR) ( aStream->msg.wParam ) == 13 ) ||
03534                      ( (TCHAR) ( aStream->msg.wParam ) == 'q' ) ||
03535                      ( (TCHAR) ( aStream->msg.wParam ) == 'Q' ) )
03536                 {
03537                     PostQuitMessage( 0 );
03538                 }
03539                 break;
03540 
03541             default:
03542                 DispatchMessage( &aStream->msg );
03543                 break;
03544             }
03545         }
03546     }
03547 }
03548 
03549 //--------------------------------------------------------------------------
03550 // plD_tidy_wincairo()
03551 //
03552 // Clean up Cairo Microsoft Windows driver.
03553 //--------------------------------------------------------------------------
03554 
03555 void plD_tidy_wincairo( PLStream *pls )
03556 {
03557     PLCairo *aStream = (PLCairo *) pls->dev;
03558 
03559     plD_tidy_cairo( pls );
03560 
03561     // Also free up the Cairo win32 surface and context
03562     cairo_destroy( aStream->cairoContext_win );
03563     cairo_surface_destroy( aStream->cairoSurface_win );
03564 
03565     if ( aStream != NULL )
03566     {
03567         if ( aStream->hdc != NULL )
03568             ReleaseDC( aStream->hwnd, aStream->hdc );
03569         free_mem( pls->dev );
03570     }
03571 }
03572 
03573 //--------------------------------------------------------------------------
03574 // plD_esc_wincairo()
03575 //
03576 // Escape function, specialized for the wincairo driver
03577 //--------------------------------------------------------------------------
03578 
03579 void plD_esc_wincairo( PLStream *pls, PLINT op, void *ptr )
03580 {
03581     PLCairo *aStream;
03582 
03583     aStream = (PLCairo *) pls->dev;
03584 
03585     switch ( op )
03586     {
03587     case PLESC_FLUSH:
03588         InvalidateRect( aStream->hwnd, NULL, TRUE );
03589         break;
03590     case PLESC_GETC:
03591         handle_locate( pls, (PLGraphicsIn *) ptr );
03592         break;
03593     default:
03594         plD_esc_cairo( pls, op, ptr );
03595         break;
03596     }
03597 }
03598 
03599 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines