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