• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

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

Generated on Wed Oct 12 2011 20:42:21 for PLplot by  doxygen 1.7.1