gvplugin_skillgui_cairo.cpp

00001
00002 /***************************************************************************
00003  *  gvplugin_skillgui_cairo.cpp - Graphviz plugin for Skill GUI using cairo
00004  *
00005  *  Created: Fri Dec 19 12:01:39 2008
00006  *  Copyright  2008-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program 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  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022
00023 #include "gvplugin_skillgui_cairo.h"
00024
00025 #include <utils/math/angle.h>
00026 #include <utils/time/tracker.h>
00027
00028 #include <gvplugin_device.h>
00029 #include <gvplugin_render.h>
00030
00031 #include <algorithm>
00032 #include <cstdio>
00033
00034 #define NOEXPORT __attribute__ ((visibility("hidden")))
00035 
00036 NOEXPORT SkillGuiCairoRenderInstructor *__sgcri = NULL;
00037
00038 NOEXPORT std::vector<double> __skillgui_cairo_render_dashed;
00039 NOEXPORT std::vector<double> __skillgui_cairo_render_dotted;
00040
00041 #ifdef USE_GVPLUGIN_TIMETRACKER
00042 NOEXPORT fawkes::TimeTracker __tt;
00043 NOEXPORT unsigned int __ttc_page = __tt.add_class("Page");
00044 NOEXPORT unsigned int __ttc_beginpage = __tt.add_class("Begin Page");
00045 NOEXPORT unsigned int __ttc_ellipse = __tt.add_class("Ellipse");
00046 NOEXPORT unsigned int __ttc_bezier = __tt.add_class("Bezier");
00047 NOEXPORT unsigned int __ttc_polygon = __tt.add_class("Polygon");
00048 NOEXPORT unsigned int __ttc_polyline = __tt.add_class("Polyline");
00049 NOEXPORT unsigned int __ttc_text = __tt.add_class("Text");
00050 NOEXPORT unsigned int __ttc_text_1 = __tt.add_class("Text 1");
00051 NOEXPORT unsigned int __ttc_text_2 = __tt.add_class("Text 2");
00052 NOEXPORT unsigned int __ttc_text_3 = __tt.add_class("Text 3");
00053 NOEXPORT unsigned int __ttc_text_4 = __tt.add_class("Text 4");
00054 NOEXPORT unsigned int __ttc_text_5 = __tt.add_class("Text 5");
00055 NOEXPORT unsigned int __tt_count = 0;
00056 NOEXPORT unsigned int __num_ellipse = 0;
00057 NOEXPORT unsigned int __num_bezier = 0;
00058 NOEXPORT unsigned int __num_polygon = 0;
00059 NOEXPORT unsigned int __num_polyline = 0;
00060 NOEXPORT unsigned int __num_text = 0;
00061 #endif
00062 
00063 
00064 /** @class SkillGuiCairoRenderInstructor
00065  * Graphviz Cairo render plugin instructor.
00066  * @author Tim Niemueller
00067  *
00068  * @fn Cairo::RefPtr<Cairo::Context> SkillGuiCairoRenderInstructor::get_cairo()
00069  * Get Cairo context.
00070  * @return cairo context to use for drawing
00071  *
00072  * @fn bool   SkillGuiCairoRenderInstructor::scale_override()
00073  * Check if scale override is enabled.
00074  * @return true if the instructor determines the scaling, false to have the
00075  * plugin do this.
00076  *
00077  * @fn void   SkillGuiCairoRenderInstructor::get_dimensions(double &width, double &height)
00078  * Get available space dimensions.
00079  * @param width upon return contains the available width
00080  * @param height upon return contains the available height
00081  *
00082  * @fn double SkillGuiCairoRenderInstructor::get_scale()
00083  * Get scale factor.
00084  * If scale_override() returns true, shall return the requested scale value.
00085  *
00086  * @fn void   SkillGuiCairoRenderInstructor::set_scale(double scale)
00087  * Set scale.
00088  * Set the scale value that the plugin determined.
00089  * @param scale scale determined by plugin
00090  *
00091  * @fn void   SkillGuiCairoRenderInstructor::get_translation(double &tx, double &ty)
00092  * Get translation values.
00093  * If scale_override() returns true, shall return the requested translation values.
00094  * @param tx upon return contains translation in x
00095  * @param ty upon return contains translation in y
00096  *
00097  * @fn void   SkillGuiCairoRenderInstructor::set_translation(double tx, double ty)
00098  * Set translation.
00099  * Set the translation values the plugin determined.
00100  * @param tx translation in x
00101  * @param ty translation in y
00102  *
00103  * @fn void   SkillGuiCairoRenderInstructor::set_bb(double bbw, double bbh)
00104  * Set the bounding box.
00105  * Set by the plugin before calling any other function.
00106  * @param bbw bounding box width
00107  * @param bbh bounding box height
00108  *
00109  * @fn void   SkillGuiCairoRenderInstructor::set_pad(double pad_x, double pad_y)
00110  * Set padding.
00111  * Set by the plugin immediately after set_bb() is called.
00112  * @param pad_x padding in x
00113  * @param pad_y padding in y
00114  *
00115  * @fn void   SkillGuiCairoRenderInstructor::get_pad(double &pad_x, double &pad_y)
00116  * Get padding.
00117  * If scale_override() returns true, shall return the requested padding values.
00118  * @param pad_x upon return contains padding in x
00119  * @param pad_y upon return contains padding in y
00120  */
00121
00122 static void
00123 skillgui_cairo_device_init(GVJ_t *firstjob)
00124 {
00125 }
00126
00127 static void
00128 skillgui_cairo_device_finalize(GVJ_t *firstjob)
00129 {
00130   firstjob->context = (void *)__sgcri;
00131   firstjob->external_context = TRUE;
00132
00133   // Render!
00134   (firstjob->callbacks->refresh)(firstjob);
00135 }
00136
00137 static inline void
00138 skillgui_cairo_set_color(Cairo::RefPtr<Cairo::Context> cairo, gvcolor_t * color)
00139 {
00140   cairo->set_source_rgba(color->u.RGBA[0], color->u.RGBA[1],
00141                          color->u.RGBA[2], color->u.RGBA[3]);
00142 }
00143
00144 static inline void
00145 skillgui_cairo_set_penstyle(Cairo::RefPtr<Cairo::Context> cairo, GVJ_t *job)
00146 {
00147   obj_state_t *obj = job->obj;
00148
00149   if (obj->pen == PEN_DASHED) {
00150     cairo->set_dash(__skillgui_cairo_render_dashed, 0.0);
00151   } else if (obj->pen == PEN_DOTTED) {
00152     cairo->set_dash(__skillgui_cairo_render_dotted, 0.0);
00153   } else {
00154     std::vector<double> empty;
00155     cairo->set_dash(empty, 0.0);
00156   }
00157   cairo->set_line_width(obj->penwidth);
00158 }
00159
00160
00161 static void
00162 skillgui_cairo_render_begin_page(GVJ_t *job)
00163 {
00164 #ifdef USE_GVPLUGIN_TIMETRACKER
00165   __tt.ping_start(__ttc_page);
00166   __tt.ping_start(__ttc_beginpage);
00167 #endif
00168   SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00169
00170   float bbwidth  = job->bb.UR.x - job->bb.LL.x;
00171   float bbheight = job->bb.UR.y - job->bb.LL.y;
00172
00173   cri->set_bb(bbwidth, bbheight);
00174   cri->set_pad(job->pad.x, job->pad.y);
00175   Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00176
00177   double pad_x, pad_y;
00178   cri->get_pad(pad_x, pad_y);
00179
00180   // For internal calculations we need to care about the padding
00181   //bbwidth  += 2 * pad_x;
00182   //bbheight += 2 * pad_y;
00183
00184   double avwidth, avheight;
00185   cri->get_dimensions(avwidth, avheight);
00186   float translate_x = 0;
00187   float translate_y = 0;
00188
00189   if ( cri->scale_override() ) {
00190     float zoom = cri->get_scale();
00191     float zwidth  = bbwidth * zoom;
00192     float zheight = bbheight * zoom;
00193     translate_x += (avwidth  - zwidth ) / 2.;
00194     translate_y += (avheight - zheight) / 2.;
00195
00196     double translate_x, translate_y;
00197     cri->get_translation(translate_x, translate_y);
00198
00199     cairo->translate(translate_x, translate_y);
00200     cairo->scale(zoom, zoom);
00201
00202   } else {
00203     float zoom_w = avwidth  / bbwidth;
00204     float zoom_h = avheight / bbheight;
00205     float zoom   = std::min(zoom_w, zoom_h);
00206
00207     if (bbwidth > avwidth || bbheight > avheight) {
00208       float zwidth  = bbwidth * zoom;
00209       float zheight = bbheight * zoom;
00210       translate_x += (avwidth  - zwidth ) / 2.;
00211       translate_y += (avheight - zheight) / 2. + zheight;
00212     } else {
00213       zoom = 1.0;
00214       translate_x += (avwidth  - bbwidth)  / 2.;
00215       translate_y += (avheight - bbheight) / 2. + bbheight;
00216     }
00217
00218     cri->set_scale(zoom);
00219     cri->set_translation(translate_x, translate_y);
00220
00221     cairo->translate(translate_x + pad_x * zoom, translate_y - pad_y * zoom);
00222     cairo->scale(zoom, zoom);
00223   }
00224
00225
00226
00227 #ifdef USE_GVPLUGIN_TIMETRACKER
00228   __num_ellipse = 0;
00229   __num_bezier = 0;
00230   __num_polygon = 0;
00231   __num_polyline = 0;
00232   __num_text = 0;
00233
00234   __tt.ping_end(__ttc_beginpage);
00235 #endif
00236 }
00237
00238 static void
00239 skillgui_cairo_render_end_page(GVJ_t * job)
00240 {
00241   //SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00242   //cri->queue_draw();  
00243 #ifdef USE_GVPLUGIN_TIMETRACKER
00244   __tt.ping_end(__ttc_page);
00245   if ( ++__tt_count >= 10 ) {
00246     __tt_count = 0;
00247     __tt.print_to_stdout();
00248
00249     printf("Num Ellipse:   %u\n"
00250            "Num Bezier:    %u\n"
00251            "Num Polygon:   %u\n"
00252            "Num Polyline:  %u\n"
00253            "Num Text:      %u\n", __num_ellipse, __num_bezier,
00254            __num_polygon, __num_polyline, __num_text);
00255   }
00256 #endif
00257 }
00258
00259 static void
00260 skillgui_cairo_render_textpara(GVJ_t *job, pointf p, textpara_t *para)
00261 {
00262 #ifdef USE_GVPLUGIN_TIMETRACKER
00263   __tt.ping_start(__ttc_text);
00264   ++__num_text;
00265 #endif
00266   SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00267   Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00268   obj_state_t *obj = job->obj;
00269
00270   Cairo::FontWeight weight = Cairo::FONT_WEIGHT_NORMAL;
00271   Cairo::FontSlant slant   = Cairo::FONT_SLANT_NORMAL;
00272   char *fontweight;
00273   if (obj->type == CLUSTER_OBJTYPE) {
00274     fontweight = agget(obj->u.sg, (char *)"fontweight");
00275   } else if (obj->type == ROOTGRAPH_OBJTYPE) {
00276     fontweight = agget(obj->u.g, (char *)"fontweight");
00277   } else if (obj->type == NODE_OBJTYPE) {
00278     fontweight = agget(obj->u.n, (char *)"fontweight");
00279   } else if (obj->type == EDGE_OBJTYPE) {
00280     fontweight = agget(obj->u.e, (char *)"fontweight");
00281   }
00282   if (fontweight && (strcmp(fontweight, "bold") == 0)) {
00283     weight = Cairo::FONT_WEIGHT_BOLD;
00284     p.x -= 8;
00285   }
00286   char *fontslant;
00287   if (obj->type == CLUSTER_OBJTYPE) {
00288     fontslant = agget(obj->u.sg, (char *)"fontslant");
00289   } else if (obj->type == ROOTGRAPH_OBJTYPE) {
00290     fontslant = agget(obj->u.g, (char *)"fontslant");
00291   } else if (obj->type == NODE_OBJTYPE) {
00292     fontslant = agget(obj->u.n, (char *)"fontslant");
00293   } else if (obj->type == EDGE_OBJTYPE) {
00294     fontslant = agget(obj->u.e, (char *)"fontslant");
00295   }
00296   if (fontslant && (strcmp(fontslant, "italic") == 0)) {
00297     slant = Cairo::FONT_SLANT_ITALIC;
00298   }
00299
00300   double offsetx = 0.0;
00301   double offsety = 0.0;
00302   double rotate  = 0.0;
00303
00304   if ( (obj->type == EDGE_OBJTYPE) && (strcmp(para->str, obj->headlabel) == 0) ) {
00305     char *labelrotate = agget(obj->u.e, (char *)"labelrotate");
00306     if (labelrotate && (strlen(labelrotate) > 0)) {
00307       rotate = fawkes::deg2rad(atof(labelrotate));
00308     }
00309     char *labeloffsetx = agget(obj->u.e, (char *)"labeloffsetx");
00310     if (labeloffsetx && (strlen(labeloffsetx) > 0)) {
00311       offsetx = atof(labeloffsetx);
00312     }
00313     char *labeloffsety = agget(obj->u.e, (char *)"labeloffsety");
00314     if (labeloffsety && (strlen(labeloffsety) > 0)) {
00315       offsety = atof(labeloffsety);
00316     }
00317   }
00318   //__tt.ping_start(__ttc_text_1);
00319
00320   Cairo::Matrix old_matrix;
00321   cairo->get_matrix(old_matrix);
00322
00323   cairo->select_font_face(para->fontname, slant, weight);
00324   cairo->set_font_size(para->fontsize);
00325   //cairo->set_font_options ( Cairo::FontOptions() );
00326   //cairo->set_line_width(1.0);
00327
00328   Cairo::TextExtents extents;
00329   cairo->get_text_extents(para->str, extents);
00330
00331   if (para->just == 'r') {
00332     p.x -= extents.width;
00333   } else if (para->just != 'l') {
00334     p.x -= extents.width / 2.0;
00335   }
00336
00337   cairo->move_to(p.x + offsetx, -p.y + offsety);
00338   cairo->rotate(rotate);
00339   skillgui_cairo_set_color(cairo, &(obj->pencolor));
00340   cairo->text_path( para->str );
00341   cairo->fill();
00342
00343   cairo->set_matrix(old_matrix);
00344
00345   //__tt.ping_end(__ttc_text_5);
00346 #ifdef USE_GVPLUGIN_TIMETRACKER
00347   __tt.ping_end(__ttc_text);
00348 #endif
00349 }
00350
00351 static void
00352 skillgui_cairo_render_ellipse(GVJ_t *job, pointf *A, int filled)
00353 {
00354 #ifdef USE_GVPLUGIN_TIMETRACKER
00355   __tt.ping_start(__ttc_ellipse);
00356   ++__num_ellipse;
00357 #endif
00358   //printf("Render ellipse\n");
00359   SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00360   Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00361   obj_state_t *obj = job->obj;
00362
00363   Cairo::Matrix old_matrix;
00364   cairo->get_matrix(old_matrix);
00365
00366   skillgui_cairo_set_penstyle(cairo, job);
00367
00368   cairo->translate(A[0].x, -A[0].y);
00369
00370   double rx = A[1].x - A[0].x;
00371   double ry = A[1].y - A[0].y;
00372   cairo->scale(1, ry / rx);
00373   cairo->move_to(rx, 0);
00374   cairo->arc(0, 0, rx, 0, 2 * M_PI);
00375   cairo->close_path();
00376
00377   cairo->set_matrix(old_matrix);
00378
00379   if (filled) {
00380     skillgui_cairo_set_color(cairo, &(obj->fillcolor));
00381     cairo->fill_preserve();
00382   }
00383   skillgui_cairo_set_color(cairo, &(obj->pencolor));
00384   cairo->stroke();
00385
00386 #ifdef USE_GVPLUGIN_TIMETRACKER
00387   __tt.ping_end(__ttc_ellipse);
00388 #endif
00389 }
00390
00391 static void
00392 skillgui_cairo_render_polygon(GVJ_t *job, pointf *A, int n, int filled)
00393 {
00394 #ifdef USE_GVPLUGIN_TIMETRACKER
00395   __tt.ping_start(__ttc_polygon);
00396   ++__num_polygon;
00397 #endif
00398   //printf("Polygon\n");
00399   SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00400   Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00401   obj_state_t *obj = job->obj;
00402
00403   skillgui_cairo_set_penstyle(cairo, job);
00404
00405   cairo->move_to(A[0].x, -A[0].y);
00406   for (int i = 1; i < n; ++i) {
00407     cairo->line_to(A[i].x, -A[i].y);
00408   }
00409   cairo->close_path();
00410
00411   if (filled) {
00412     skillgui_cairo_set_color(cairo, &(obj->fillcolor));
00413     cairo->fill_preserve();
00414   }
00415
00416   // HACK to workaround graphviz bug any get the Tim style...
00417   if ( obj->type == CLUSTER_OBJTYPE ) {
00418     obj->pencolor.u.RGBA[0] = 0.666;
00419     obj->pencolor.u.RGBA[1] = 0.666;
00420     obj->pencolor.u.RGBA[2] = 1.0;
00421     obj->pencolor.u.RGBA[3] = 1.0;
00422   }
00423   skillgui_cairo_set_color(cairo, &(obj->pencolor));
00424   cairo->stroke();
00425
00426 #ifdef USE_GVPLUGIN_TIMETRACKER
00427   __tt.ping_end(__ttc_polygon);
00428 #endif
00429 }
00430
00431 static void
00432 skillgui_cairo_render_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00433                 int arrow_at_end, int filled)
00434 {
00435 #ifdef USE_GVPLUGIN_TIMETRACKER
00436   __tt.ping_start(__ttc_bezier);
00437   ++__num_bezier;
00438 #endif
00439   //printf("Bezier\n");
00440   SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00441   Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00442   obj_state_t *obj = job->obj;
00443
00444   skillgui_cairo_set_penstyle(cairo, job);
00445
00446   cairo->move_to(A[0].x, -A[0].y);
00447   for (int i = 1; i < n; i += 3)
00448     cairo->curve_to(A[i].x, -A[i].y, A[i + 1].x, -A[i + 1].y,
00449                     A[i + 2].x, -A[i + 2].y);
00450   if (filled) {
00451     skillgui_cairo_set_color(cairo, &(obj->fillcolor));
00452     cairo->fill_preserve();
00453   }
00454   skillgui_cairo_set_color(cairo, &(obj->pencolor));
00455   cairo->stroke();
00456
00457 #ifdef USE_GVPLUGIN_TIMETRACKER
00458   __tt.ping_end(__ttc_bezier);
00459 #endif
00460 }
00461
00462 static void
00463 skillgui_cairo_render_polyline(GVJ_t * job, pointf * A, int n)
00464 {
00465 #ifdef USE_GVPLUGIN_TIMETRACKER
00466   __tt.ping_start(__ttc_polyline);
00467   ++__num_polyline;
00468 #endif
00469   //printf("Polyline\n");
00470   SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00471   Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00472   obj_state_t *obj = job->obj;
00473
00474   skillgui_cairo_set_penstyle(cairo, job);
00475
00476   //cairo->set_line_width(obj->penwidth * job->scale.x);
00477   cairo->move_to(A[0].x, -A[0].y);
00478   for (int i = 1; i < n; i++) {
00479     cairo->line_to(A[i].x, -A[i].y);
00480   }
00481   skillgui_cairo_set_color(cairo, &(obj->pencolor));
00482   cairo->stroke();
00483
00484 #ifdef USE_GVPLUGIN_TIMETRACKER
00485   __tt.ping_end(__ttc_polyline);
00486 #endif
00487 }
00488
00489
00490 static gvrender_engine_t skillgui_cairo_render_engine = {
00491     0,                          /* skillgui_cairo_render_begin_job */
00492     0,                          /* skillgui_cairo_render_end_job */
00493     0,                          /* skillgui_cairo_render_begin_graph */
00494     0,                          /* skillgui_cairo_render_end_graph */
00495     0,                          /* skillgui_cairo_render_begin_layer */
00496     0,                          /* skillgui_cairo_render_end_layer */
00497     skillgui_cairo_render_begin_page,
00498     skillgui_cairo_render_end_page,
00499     0,                          /* skillgui_cairo_render_begin_cluster */
00500     0,                          /* skillgui_cairo_render_end_cluster */
00501     0,                          /* skillgui_cairo_render_begin_nodes */
00502     0,                          /* skillgui_cairo_render_end_nodes */
00503     0,                          /* skillgui_cairo_render_begin_edges */
00504     0,                          /* skillgui_cairo_render_end_edges */
00505     0,                          /* skillgui_cairo_render_begin_node */
00506     0,                          /* skillgui_cairo_render_end_node */
00507     0,                          /* skillgui_cairo_render_begin_edge */
00508     0,                          /* skillgui_cairo_render_end_edge */
00509     0,                          /* skillgui_cairo_render_begin_anchor */
00510     0,                          /* skillgui_cairo_render_end_anchor */
00511     0,                          /* skillgui_cairo_begin_label */
00512     0,                          /* skillgui_cairo_end_label */
00513     skillgui_cairo_render_textpara,
00514     0,                          /* skillgui_cairo_render_resolve_color */
00515     skillgui_cairo_render_ellipse,
00516     skillgui_cairo_render_polygon,
00517     skillgui_cairo_render_bezier,
00518     skillgui_cairo_render_polyline,
00519     0,                          /* skillgui_cairo_render_comment */
00520     0,                          /* skillgui_cairo_render_library_shape */
00521 };
00522
00523 static gvdevice_engine_t skillgui_cairo_device_engine = {
00524     skillgui_cairo_device_init,
00525     NULL,                       /* skillgui_cairo_device_format */
00526     skillgui_cairo_device_finalize,
00527 };
00528
00529
00530 #ifdef __cplusplus
00531 extern "C" {
00532 #endif
00533 
00534
00535 static gvrender_features_t skillgui_cairo_render_features = {
00536   GVRENDER_Y_GOES_DOWN |
00537   GVRENDER_DOES_LABELS |
00538   GVRENDER_DOES_TRANSFORM |
00539   GVRENDER_NO_WHITE_BG,                         /* flags */
00540   8,                                            /* default pad - graph units */
00541   0,                                            /* knowncolors */
00542   0,                                            /* sizeof knowncolors */
00543   RGBA_DOUBLE,                                  /* color_type */
00544 };
00545
00546
00547 static gvdevice_features_t skillgui_cairo_device_features = {
00548   GVDEVICE_DOES_TRUECOLOR | GVDEVICE_EVENTS,    /* flags */
00549   {0.,0.},                                      /* default margin - points */
00550   {0.,0.},                                      /* default page width, height - points */
00551   {96.,96.},                                    /* dpi */
00552 };
00553
00554 gvplugin_installed_t gvdevice_types_skillgui_cairo[] = {
00555   {0, ( char *)"skillguicairo:skillguicairo", 0, &skillgui_cairo_device_engine, &skillgui_cairo_device_features},
00556   {0, NULL, 0, NULL, NULL}
00557 };
00558
00559 gvplugin_installed_t gvrender_types_skillgui_cairo[] = {
00560   {0, (char *)"skillguicairo", 10, &skillgui_cairo_render_engine, &skillgui_cairo_render_features},
00561   {0, NULL, 0, NULL, NULL}
00562 };
00563
00564 static gvplugin_api_t apis[] = {
00565   {API_device, gvdevice_types_skillgui_cairo},
00566   {API_render, gvrender_types_skillgui_cairo},
00567   {(api_t)0, 0},
00568 };
00569
00570 gvplugin_library_t gvplugin_skillgui_cairo_LTX_library = { (char *)"skillguicairo", apis };
00571
00572 #ifdef __cplusplus
00573 }
00574 #endif
00575 
00576
00577 void
00578 gvplugin_skillgui_cairo_setup(GVC_t *gvc, SkillGuiCairoRenderInstructor *sgcri)
00579 {
00580   __sgcri = sgcri;
00581   gvAddLibrary(gvc, &gvplugin_skillgui_cairo_LTX_library);
00582
00583   __skillgui_cairo_render_dashed.clear();
00584   __skillgui_cairo_render_dashed.push_back(6.0);
00585   __skillgui_cairo_render_dotted.clear();
00586   __skillgui_cairo_render_dotted.push_back(2.0);
00587   __skillgui_cairo_render_dotted.push_back(6.0);
00588 }