GRASS Programmer's Manual  6.4.2(2012)
cairodriver/Graph.c
Go to the documentation of this file.
00001 
00015 #include "cairodriver.h"
00016 
00017 #if CAIRO_HAS_PS_SURFACE
00018 #include <cairo-ps.h>
00019 #endif
00020 #if CAIRO_HAS_PDF_SURFACE
00021 #include <cairo-pdf.h>
00022 #endif
00023 #if CAIRO_HAS_SVG_SURFACE
00024 #include <cairo-svg.h>
00025 #endif
00026 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
00027 #include <cairo-xlib.h>
00028 #include <cairo-xlib-xrender.h>
00029 #endif
00030 
00031 #include <unistd.h>
00032 #ifndef __MINGW32__
00033 #include <fcntl.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <sys/mman.h>
00037 #endif
00038 
00039 #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE
00040 #include <X11/X.h>
00041 #include <X11/Xlib.h>
00042 #include <X11/Xutil.h>
00043 #endif
00044 
00045 /* globals */
00046 char *file_name;
00047 int file_type;
00048 int is_vector;
00049 int width, height, stride;
00050 unsigned char *grid;
00051 int modified;
00052 int auto_write;
00053 int mapped;
00054 
00055 /* background color */
00056 double bgcolor_r, bgcolor_g, bgcolor_b, bgcolor_a;
00057 
00058 /* cairo objects */
00059 cairo_surface_t *surface;
00060 cairo_t *cairo;
00061 
00062 static void init_cairo(void);
00063 static int ends_with(const char *string, const char *suffix);
00064 static void map_file(void);
00065 
00066 #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE
00067 static int init_xlib(void)
00068 {
00069     Display *dpy;
00070     Drawable win;
00071     unsigned long xid;
00072     XVisualInfo templ;
00073     XVisualInfo *vinfo;
00074     int count;
00075     Window root;
00076     unsigned int depth;
00077     int si;
00078     unsigned int ui;
00079     Visual *visual;
00080     char *p;
00081 
00082     p = getenv("GRASS_CAIRO_DRAWABLE");
00083     if (!p || sscanf(p, "%li", &xid) != 1)
00084         G_fatal_error("invalid Drawable XID: %s", p);
00085     win = xid;
00086 
00087     dpy = XOpenDisplay(NULL);
00088     if (!dpy)
00089         G_fatal_error("Unable to open display");
00090 
00091     p = getenv("GRASS_CAIRO_VISUAL");
00092     if (!p || sscanf(p, "%li", &xid) != 1)
00093         G_fatal_error("invalid Visual XID: %s", p);
00094     templ.visualid = xid;
00095 
00096     vinfo = XGetVisualInfo(dpy, VisualIDMask, &templ, &count);
00097     if (!vinfo || !count)
00098         G_fatal_error("Unable to obtain visual");
00099     visual = vinfo[0].visual;
00100 
00101     if (!XGetGeometry
00102         (dpy, win, &root, &si, &si, &width, &height, &ui, &depth))
00103         G_fatal_error("Unable to query drawable");
00104 
00105     surface = cairo_xlib_surface_create(dpy, win, visual, width, height);
00106 
00107     if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
00108         G_fatal_error("Failed to initialize Xlib surface");
00109 
00110     cairo = cairo_create(surface);
00111 
00112     file_name = "<X11>";
00113     file_type = FTYPE_X11;
00114 
00115     screen_right = screen_left + width;
00116     screen_bottom = screen_top + height;
00117 
00118     return 0;
00119 }
00120 #endif
00121 
00122 static int init_file(void)
00123 {
00124     int do_read = 0;
00125     int do_map = 0;
00126     char *p;
00127 
00128     /* set image properties */
00129     width = screen_right - screen_left;
00130     height = screen_bottom - screen_top;
00131     stride = width * 4;
00132 
00133     /* get file name */
00134     p = getenv("GRASS_CAIROFILE");
00135     if (!p || strlen(p) == 0)
00136         p = DEFAULT_FILE_NAME;
00137 
00138     file_name = p;
00139 
00140     /* get file type (from extension) */
00141     if (file_type == FTYPE_X11) ;       /* skip */
00142     else if (ends_with(file_name, ".ppm"))
00143         file_type = FTYPE_PPM;
00144     else if (ends_with(file_name, ".bmp"))
00145         file_type = FTYPE_BMP;
00146 #if CAIRO_HAS_PNG_FUNCTIONS
00147     else if (ends_with(file_name, ".png"))
00148         file_type = FTYPE_PNG;
00149 #endif
00150 #if CAIRO_HAS_PDF_SURFACE
00151     else if (ends_with(file_name, ".pdf"))
00152         file_type = FTYPE_PDF;
00153 #endif
00154 #if CAIRO_HAS_PS_SURFACE
00155     else if (ends_with(file_name, ".ps"))
00156         file_type = FTYPE_PS;
00157 #endif
00158 #if CAIRO_HAS_SVG_SURFACE
00159     else if (ends_with(file_name, ".svg"))
00160         file_type = FTYPE_SVG;
00161 #endif
00162     else
00163         G_fatal_error("Unknown file extension: %s", p);
00164     G_debug(1, "File type: %s (%d)", file_name, file_type);
00165 
00166     switch (file_type) {
00167     case FTYPE_PDF:
00168     case FTYPE_PS:
00169     case FTYPE_SVG:
00170         is_vector = 1;
00171         break;
00172     }
00173 
00174     p = getenv("GRASS_CAIRO_MAPPED");
00175     do_map = p && strcmp(p, "TRUE") == 0 && ends_with(file_name, ".bmp");
00176 
00177     p = getenv("GRASS_CAIRO_READ");
00178     do_read = p && strcmp(p, "TRUE") == 0;
00179 
00180     if (is_vector) {
00181         do_read = do_map = 0;
00182         bgcolor_a = 1.0;
00183     }
00184 
00185     if (do_read && access(file_name, 0) != 0)
00186         do_read = 0;
00187 
00188     G_message
00189         ("cairo: collecting to file: %s,\n     GRASS_WIDTH=%d, GRASS_HEIGHT=%d",
00190          file_name, width, height);
00191 
00192     if (do_read && do_map)
00193         map_file();
00194 
00195     if (!mapped && !is_vector)
00196         grid = G_malloc(height * stride);
00197 
00198     init_cairo();
00199 
00200     if (!do_read && !is_vector) {
00201         Cairo_Erase();
00202         modified = 1;
00203     }
00204 
00205     if (do_read && !mapped)
00206         read_image();
00207 
00208     if (do_map && !mapped) {
00209         write_image();
00210         map_file();
00211         init_cairo();
00212     }
00213 
00214     return 0;
00215 }
00216 
00217 int Cairo_Graph_set(int argc, char **argv)
00218 {
00219     char *p;
00220 
00221     G_gisinit("Cairo driver");
00222     G_debug(1, "Cairo_Graph_set");
00223 
00224     /* get background color */
00225     p = getenv("GRASS_BACKGROUNDCOLOR");
00226     if (p && *p) {
00227         unsigned int red, green, blue;
00228 
00229         if (sscanf(p, "%02x%02x%02x", &red, &green, &blue) == 3) {
00230             bgcolor_r = CAIROCOLOR(red);
00231             bgcolor_g = CAIROCOLOR(green);
00232             bgcolor_b = CAIROCOLOR(blue);
00233         }
00234         else
00235             G_fatal_error("Unknown background color: %s", p);
00236     }
00237     else
00238         bgcolor_r = bgcolor_g = bgcolor_b = 1.0;
00239 
00240     /* get background transparency setting */
00241     p = getenv("GRASS_TRANSPARENT");
00242     if (p && strcmp(p, "TRUE") == 0)
00243         bgcolor_a = 0.0;
00244     else
00245         bgcolor_a = 1.0;
00246 
00247     p = getenv("GRASS_AUTO_WRITE");
00248     auto_write = p && strcmp(p, "TRUE") == 0;
00249 
00250 #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE
00251     p = getenv("GRASS_CAIRO_DRAWABLE");
00252     if (p)
00253         return init_xlib();
00254 #endif
00255     return init_file();
00256 }
00257 
00258 void Cairo_Graph_close(void)
00259 {
00260     G_debug(1, "Cairo_Graph_close");
00261 
00262     write_image();
00263 
00264     if (cairo) {
00265         cairo_destroy(cairo);
00266         cairo = NULL;
00267     }
00268     if (surface) {
00269         cairo_surface_destroy(surface);
00270         surface = NULL;
00271     }
00272 }
00273 
00274 static void init_cairo(void)
00275 {
00276     G_debug(1, "init_cairo");
00277 
00278     /* create cairo surface */
00279     switch (file_type) {
00280     case FTYPE_PPM:
00281     case FTYPE_BMP:
00282     case FTYPE_PNG:
00283         surface =
00284             (cairo_surface_t *) cairo_image_surface_create_for_data(grid,
00285                                                                     CAIRO_FORMAT_ARGB32,
00286                                                                     width,
00287                                                                     height,
00288                                                                     stride);
00289         break;
00290 #if CAIRO_HAS_PDF_SURFACE
00291     case FTYPE_PDF:
00292         surface =
00293             (cairo_surface_t *) cairo_pdf_surface_create(file_name,
00294                                                          (double)width,
00295                                                          (double)height);
00296         break;
00297 #endif
00298 #if CAIRO_HAS_PS_SURFACE
00299     case FTYPE_PS:
00300         surface =
00301             (cairo_surface_t *) cairo_ps_surface_create(file_name,
00302                                                         (double)width,
00303                                                         (double)height);
00304         break;
00305 #endif
00306 #if CAIRO_HAS_SVG_SURFACE
00307     case FTYPE_SVG:
00308         surface =
00309             (cairo_surface_t *) cairo_svg_surface_create(file_name,
00310                                                          (double)width,
00311                                                          (double)height);
00312         break;
00313 #endif
00314     default:
00315         G_fatal_error("Unknown Cairo surface type");
00316         break;
00317     }
00318 
00319     if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
00320         G_fatal_error("Failed to initialize Cairo surface");
00321 
00322     cairo = cairo_create(surface);
00323 }
00324 
00325 /* Returns TRUE if string ends with suffix (case insensitive) */
00326 static int ends_with(const char *string, const char *suffix)
00327 {
00328     if (strlen(string) < strlen(suffix))
00329         return FALSE;
00330 
00331     return G_strcasecmp(suffix,
00332                         string + strlen(string) - strlen(suffix)) == 0;
00333 }
00334 
00335 static void map_file(void)
00336 {
00337 #ifndef __MINGW32__
00338     size_t size = HEADER_SIZE + width * height * sizeof(unsigned int);
00339     void *ptr;
00340     int fd;
00341 
00342     fd = open(file_name, O_RDWR);
00343     if (fd < 0)
00344         return;
00345 
00346     ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t) 0);
00347     if (ptr == MAP_FAILED)
00348         return;
00349 
00350     if (grid) {
00351         cairo_destroy(cairo);
00352         cairo_surface_destroy(surface);
00353         G_free(grid);
00354     }
00355     grid = (unsigned char *)ptr + HEADER_SIZE;
00356 
00357     close(fd);
00358 
00359     mapped = 1;
00360 #endif
00361 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines