00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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 #if CAIROMM_MAJOR_VERSION > 1 || (CAIROMM_MAJOR_VERSION == 1 && CAIROMM_MINO_VERSION > 8)
00039 NOEXPORT std::vector<double> __skillgui_cairo_render_dashed;
00040 NOEXPORT std::vector<double> __skillgui_cairo_render_dotted;
00041 #else
00042 NOEXPORT std::valarray<double> __skillgui_cairo_render_dashed(1);
00043 NOEXPORT std::valarray<double> __skillgui_cairo_render_dotted(2);
00044 #endif
00045
00046 #ifdef USE_GVPLUGIN_TIMETRACKER
00047 NOEXPORT fawkes::TimeTracker __tt;
00048 NOEXPORT unsigned int __ttc_page = __tt.add_class("Page");
00049 NOEXPORT unsigned int __ttc_beginpage = __tt.add_class("Begin Page");
00050 NOEXPORT unsigned int __ttc_ellipse = __tt.add_class("Ellipse");
00051 NOEXPORT unsigned int __ttc_bezier = __tt.add_class("Bezier");
00052 NOEXPORT unsigned int __ttc_polygon = __tt.add_class("Polygon");
00053 NOEXPORT unsigned int __ttc_polyline = __tt.add_class("Polyline");
00054 NOEXPORT unsigned int __ttc_text = __tt.add_class("Text");
00055 NOEXPORT unsigned int __ttc_text_1 = __tt.add_class("Text 1");
00056 NOEXPORT unsigned int __ttc_text_2 = __tt.add_class("Text 2");
00057 NOEXPORT unsigned int __ttc_text_3 = __tt.add_class("Text 3");
00058 NOEXPORT unsigned int __ttc_text_4 = __tt.add_class("Text 4");
00059 NOEXPORT unsigned int __ttc_text_5 = __tt.add_class("Text 5");
00060 NOEXPORT unsigned int __tt_count = 0;
00061 NOEXPORT unsigned int __num_ellipse = 0;
00062 NOEXPORT unsigned int __num_bezier = 0;
00063 NOEXPORT unsigned int __num_polygon = 0;
00064 NOEXPORT unsigned int __num_polyline = 0;
00065 NOEXPORT unsigned int __num_text = 0;
00066 #endif
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 static void
00129 skillgui_cairo_device_init(GVJ_t *firstjob)
00130 {
00131 }
00132
00133 static void
00134 skillgui_cairo_device_finalize(GVJ_t *firstjob)
00135 {
00136 firstjob->context = (void *)__sgcri;
00137 firstjob->external_context = TRUE;
00138
00139
00140 (firstjob->callbacks->refresh)(firstjob);
00141 }
00142
00143 static inline void
00144 skillgui_cairo_set_color(Cairo::RefPtr<Cairo::Context> cairo, gvcolor_t * color)
00145 {
00146 cairo->set_source_rgba(color->u.RGBA[0], color->u.RGBA[1],
00147 color->u.RGBA[2], color->u.RGBA[3]);
00148 }
00149
00150 static inline void
00151 skillgui_cairo_set_penstyle(Cairo::RefPtr<Cairo::Context> cairo, GVJ_t *job)
00152 {
00153 obj_state_t *obj = job->obj;
00154
00155 if (obj->pen == PEN_DASHED) {
00156 cairo->set_dash(__skillgui_cairo_render_dashed, 0.0);
00157 } else if (obj->pen == PEN_DOTTED) {
00158 cairo->set_dash(__skillgui_cairo_render_dotted, 0.0);
00159 } else {
00160 #if CAIROMM_MAJOR_VERSION > 1 || (CAIROMM_MAJOR_VERSION == 1 && CAIROMM_MINO_VERSION > 8)
00161 std::vector<double> empty;
00162 #else
00163 std::valarray<double> empty;
00164 #endif
00165 cairo->set_dash(empty, 0.0);
00166 }
00167 cairo->set_line_width(obj->penwidth);
00168 }
00169
00170
00171 static void
00172 skillgui_cairo_render_begin_page(GVJ_t *job)
00173 {
00174 #ifdef USE_GVPLUGIN_TIMETRACKER
00175 __tt.ping_start(__ttc_page);
00176 __tt.ping_start(__ttc_beginpage);
00177 #endif
00178 SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00179
00180 float bbwidth = job->bb.UR.x - job->bb.LL.x;
00181 float bbheight = job->bb.UR.y - job->bb.LL.y;
00182
00183 cri->set_bb(bbwidth, bbheight);
00184 cri->set_pad(job->pad.x, job->pad.y);
00185 Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00186
00187 double pad_x, pad_y;
00188 cri->get_pad(pad_x, pad_y);
00189
00190
00191
00192
00193
00194 double avwidth, avheight;
00195 cri->get_dimensions(avwidth, avheight);
00196 float translate_x = 0;
00197 float translate_y = 0;
00198
00199 if ( cri->scale_override() ) {
00200 float zoom = cri->get_scale();
00201 float zwidth = bbwidth * zoom;
00202 float zheight = bbheight * zoom;
00203 translate_x += (avwidth - zwidth ) / 2.;
00204 translate_y += (avheight - zheight) / 2.;
00205
00206 double translate_x, translate_y;
00207 cri->get_translation(translate_x, translate_y);
00208
00209 cairo->translate(translate_x, translate_y);
00210 cairo->scale(zoom, zoom);
00211
00212 } else {
00213 float zoom_w = avwidth / bbwidth;
00214 float zoom_h = avheight / bbheight;
00215 float zoom = std::min(zoom_w, zoom_h);
00216
00217 if (bbwidth > avwidth || bbheight > avheight) {
00218 float zwidth = bbwidth * zoom;
00219 float zheight = bbheight * zoom;
00220 translate_x += (avwidth - zwidth ) / 2.;
00221 translate_y += (avheight - zheight) / 2. + zheight;
00222 } else {
00223 zoom = 1.0;
00224 translate_x += (avwidth - bbwidth) / 2.;
00225 translate_y += (avheight - bbheight) / 2. + bbheight;
00226 }
00227
00228 cri->set_scale(zoom);
00229 cri->set_translation(translate_x, translate_y);
00230
00231 cairo->translate(translate_x + pad_x * zoom, translate_y - pad_y * zoom);
00232 cairo->scale(zoom, zoom);
00233 }
00234
00235
00236
00237 #ifdef USE_GVPLUGIN_TIMETRACKER
00238 __num_ellipse = 0;
00239 __num_bezier = 0;
00240 __num_polygon = 0;
00241 __num_polyline = 0;
00242 __num_text = 0;
00243
00244 __tt.ping_end(__ttc_beginpage);
00245 #endif
00246 }
00247
00248 static void
00249 skillgui_cairo_render_end_page(GVJ_t * job)
00250 {
00251
00252
00253 #ifdef USE_GVPLUGIN_TIMETRACKER
00254 __tt.ping_end(__ttc_page);
00255 if ( ++__tt_count >= 10 ) {
00256 __tt_count = 0;
00257 __tt.print_to_stdout();
00258
00259 printf("Num Ellipse: %u\n"
00260 "Num Bezier: %u\n"
00261 "Num Polygon: %u\n"
00262 "Num Polyline: %u\n"
00263 "Num Text: %u\n", __num_ellipse, __num_bezier,
00264 __num_polygon, __num_polyline, __num_text);
00265 }
00266 #endif
00267 }
00268
00269 static void
00270 skillgui_cairo_render_textpara(GVJ_t *job, pointf p, textpara_t *para)
00271 {
00272 #ifdef USE_GVPLUGIN_TIMETRACKER
00273 __tt.ping_start(__ttc_text);
00274 ++__num_text;
00275 #endif
00276 SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00277 Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00278 obj_state_t *obj = job->obj;
00279
00280 Cairo::FontWeight weight = Cairo::FONT_WEIGHT_NORMAL;
00281 Cairo::FontSlant slant = Cairo::FONT_SLANT_NORMAL;
00282 char *fontweight = NULL;
00283 if (obj->type == CLUSTER_OBJTYPE) {
00284 fontweight = agget(obj->u.sg, (char *)"fontweight");
00285 } else if (obj->type == ROOTGRAPH_OBJTYPE) {
00286 fontweight = agget(obj->u.g, (char *)"fontweight");
00287 } else if (obj->type == NODE_OBJTYPE) {
00288 fontweight = agget(obj->u.n, (char *)"fontweight");
00289 } else if (obj->type == EDGE_OBJTYPE) {
00290 fontweight = agget(obj->u.e, (char *)"fontweight");
00291 }
00292 if (fontweight && (strcmp(fontweight, "bold") == 0)) {
00293 weight = Cairo::FONT_WEIGHT_BOLD;
00294 p.x -= 8;
00295 }
00296 char *fontslant = NULL;
00297 if (obj->type == CLUSTER_OBJTYPE) {
00298 fontslant = agget(obj->u.sg, (char *)"fontslant");
00299 } else if (obj->type == ROOTGRAPH_OBJTYPE) {
00300 fontslant = agget(obj->u.g, (char *)"fontslant");
00301 } else if (obj->type == NODE_OBJTYPE) {
00302 fontslant = agget(obj->u.n, (char *)"fontslant");
00303 } else if (obj->type == EDGE_OBJTYPE) {
00304 fontslant = agget(obj->u.e, (char *)"fontslant");
00305 }
00306 if (fontslant && (strcmp(fontslant, "italic") == 0)) {
00307 slant = Cairo::FONT_SLANT_ITALIC;
00308 }
00309
00310 double offsetx = 0.0;
00311 double offsety = 0.0;
00312 double rotate = 0.0;
00313
00314 if ( (obj->type == EDGE_OBJTYPE) && (strcmp(para->str, obj->headlabel) == 0) ) {
00315 char *labelrotate = agget(obj->u.e, (char *)"labelrotate");
00316 if (labelrotate && (strlen(labelrotate) > 0)) {
00317 rotate = fawkes::deg2rad(atof(labelrotate));
00318 }
00319 char *labeloffsetx = agget(obj->u.e, (char *)"labeloffsetx");
00320 if (labeloffsetx && (strlen(labeloffsetx) > 0)) {
00321 offsetx = atof(labeloffsetx);
00322 }
00323 char *labeloffsety = agget(obj->u.e, (char *)"labeloffsety");
00324 if (labeloffsety && (strlen(labeloffsety) > 0)) {
00325 offsety = atof(labeloffsety);
00326 }
00327 }
00328
00329
00330 Cairo::Matrix old_matrix;
00331 cairo->get_matrix(old_matrix);
00332
00333 cairo->select_font_face(para->fontname, slant, weight);
00334 cairo->set_font_size(para->fontsize);
00335
00336
00337
00338 Cairo::TextExtents extents;
00339 cairo->get_text_extents(para->str, extents);
00340
00341 if (para->just == 'r') {
00342 p.x -= extents.width;
00343 } else if (para->just != 'l') {
00344 p.x -= extents.width / 2.0;
00345 }
00346
00347 cairo->move_to(p.x + offsetx, -p.y + offsety);
00348 cairo->rotate(rotate);
00349 skillgui_cairo_set_color(cairo, &(obj->pencolor));
00350 cairo->text_path( para->str );
00351 cairo->fill();
00352
00353 cairo->set_matrix(old_matrix);
00354
00355
00356 #ifdef USE_GVPLUGIN_TIMETRACKER
00357 __tt.ping_end(__ttc_text);
00358 #endif
00359 }
00360
00361 static void
00362 skillgui_cairo_render_ellipse(GVJ_t *job, pointf *A, int filled)
00363 {
00364 #ifdef USE_GVPLUGIN_TIMETRACKER
00365 __tt.ping_start(__ttc_ellipse);
00366 ++__num_ellipse;
00367 #endif
00368
00369 SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00370 Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00371 obj_state_t *obj = job->obj;
00372
00373 Cairo::Matrix old_matrix;
00374 cairo->get_matrix(old_matrix);
00375
00376 skillgui_cairo_set_penstyle(cairo, job);
00377
00378 cairo->translate(A[0].x, -A[0].y);
00379
00380 double rx = A[1].x - A[0].x;
00381 double ry = A[1].y - A[0].y;
00382 cairo->scale(1, ry / rx);
00383 cairo->move_to(rx, 0);
00384 cairo->arc(0, 0, rx, 0, 2 * M_PI);
00385 cairo->close_path();
00386
00387 cairo->set_matrix(old_matrix);
00388
00389 if (filled) {
00390 skillgui_cairo_set_color(cairo, &(obj->fillcolor));
00391 cairo->fill_preserve();
00392 }
00393 skillgui_cairo_set_color(cairo, &(obj->pencolor));
00394 cairo->stroke();
00395
00396 #ifdef USE_GVPLUGIN_TIMETRACKER
00397 __tt.ping_end(__ttc_ellipse);
00398 #endif
00399 }
00400
00401 static void
00402 skillgui_cairo_render_polygon(GVJ_t *job, pointf *A, int n, int filled)
00403 {
00404 #ifdef USE_GVPLUGIN_TIMETRACKER
00405 __tt.ping_start(__ttc_polygon);
00406 ++__num_polygon;
00407 #endif
00408
00409 SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00410 Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00411 obj_state_t *obj = job->obj;
00412
00413 skillgui_cairo_set_penstyle(cairo, job);
00414
00415 cairo->move_to(A[0].x, -A[0].y);
00416 for (int i = 1; i < n; ++i) {
00417 cairo->line_to(A[i].x, -A[i].y);
00418 }
00419 cairo->close_path();
00420
00421 if (filled) {
00422 skillgui_cairo_set_color(cairo, &(obj->fillcolor));
00423 cairo->fill_preserve();
00424 }
00425
00426
00427 if ( obj->type == CLUSTER_OBJTYPE ) {
00428 obj->pencolor.u.RGBA[0] = 0.666;
00429 obj->pencolor.u.RGBA[1] = 0.666;
00430 obj->pencolor.u.RGBA[2] = 1.0;
00431 obj->pencolor.u.RGBA[3] = 1.0;
00432 }
00433 skillgui_cairo_set_color(cairo, &(obj->pencolor));
00434 cairo->stroke();
00435
00436 #ifdef USE_GVPLUGIN_TIMETRACKER
00437 __tt.ping_end(__ttc_polygon);
00438 #endif
00439 }
00440
00441 static void
00442 skillgui_cairo_render_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00443 int arrow_at_end, int filled)
00444 {
00445 #ifdef USE_GVPLUGIN_TIMETRACKER
00446 __tt.ping_start(__ttc_bezier);
00447 ++__num_bezier;
00448 #endif
00449
00450 SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00451 Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00452 obj_state_t *obj = job->obj;
00453
00454 skillgui_cairo_set_penstyle(cairo, job);
00455
00456 cairo->move_to(A[0].x, -A[0].y);
00457 for (int i = 1; i < n; i += 3)
00458 cairo->curve_to(A[i].x, -A[i].y, A[i + 1].x, -A[i + 1].y,
00459 A[i + 2].x, -A[i + 2].y);
00460 if (filled) {
00461 skillgui_cairo_set_color(cairo, &(obj->fillcolor));
00462 cairo->fill_preserve();
00463 }
00464 skillgui_cairo_set_color(cairo, &(obj->pencolor));
00465 cairo->stroke();
00466
00467 #ifdef USE_GVPLUGIN_TIMETRACKER
00468 __tt.ping_end(__ttc_bezier);
00469 #endif
00470 }
00471
00472 static void
00473 skillgui_cairo_render_polyline(GVJ_t * job, pointf * A, int n)
00474 {
00475 #ifdef USE_GVPLUGIN_TIMETRACKER
00476 __tt.ping_start(__ttc_polyline);
00477 ++__num_polyline;
00478 #endif
00479
00480 SkillGuiCairoRenderInstructor *cri = (SkillGuiCairoRenderInstructor *)job->context;
00481 Cairo::RefPtr<Cairo::Context> cairo = cri->get_cairo();
00482 obj_state_t *obj = job->obj;
00483
00484 skillgui_cairo_set_penstyle(cairo, job);
00485
00486
00487 cairo->move_to(A[0].x, -A[0].y);
00488 for (int i = 1; i < n; i++) {
00489 cairo->line_to(A[i].x, -A[i].y);
00490 }
00491 skillgui_cairo_set_color(cairo, &(obj->pencolor));
00492 cairo->stroke();
00493
00494 #ifdef USE_GVPLUGIN_TIMETRACKER
00495 __tt.ping_end(__ttc_polyline);
00496 #endif
00497 }
00498
00499
00500 static gvrender_engine_t skillgui_cairo_render_engine = {
00501 0,
00502 0,
00503 0,
00504 0,
00505 0,
00506 0,
00507 skillgui_cairo_render_begin_page,
00508 skillgui_cairo_render_end_page,
00509 0,
00510 0,
00511 0,
00512 0,
00513 0,
00514 0,
00515 0,
00516 0,
00517 0,
00518 0,
00519 0,
00520 0,
00521 0,
00522 0,
00523 skillgui_cairo_render_textpara,
00524 0,
00525 skillgui_cairo_render_ellipse,
00526 skillgui_cairo_render_polygon,
00527 skillgui_cairo_render_bezier,
00528 skillgui_cairo_render_polyline,
00529 0,
00530 0,
00531 };
00532
00533 static gvdevice_engine_t skillgui_cairo_device_engine = {
00534 skillgui_cairo_device_init,
00535 NULL,
00536 skillgui_cairo_device_finalize,
00537 };
00538
00539
00540 #ifdef __cplusplus
00541 extern "C" {
00542 #endif
00543
00544
00545 static gvrender_features_t skillgui_cairo_render_features = {
00546 GVRENDER_Y_GOES_DOWN |
00547 GVRENDER_DOES_LABELS |
00548 GVRENDER_DOES_TRANSFORM |
00549 GVRENDER_NO_WHITE_BG,
00550 8,
00551 0,
00552 0,
00553 RGBA_DOUBLE,
00554 };
00555
00556
00557 static gvdevice_features_t skillgui_cairo_device_features = {
00558 GVDEVICE_DOES_TRUECOLOR | GVDEVICE_EVENTS,
00559 {0.,0.},
00560 {0.,0.},
00561 {96.,96.},
00562 };
00563
00564 gvplugin_installed_t gvdevice_types_skillgui_cairo[] = {
00565 {0, ( char *)"skillguicairo:skillguicairo", 0, &skillgui_cairo_device_engine, &skillgui_cairo_device_features},
00566 {0, NULL, 0, NULL, NULL}
00567 };
00568
00569 gvplugin_installed_t gvrender_types_skillgui_cairo[] = {
00570 {0, (char *)"skillguicairo", 10, &skillgui_cairo_render_engine, &skillgui_cairo_render_features},
00571 {0, NULL, 0, NULL, NULL}
00572 };
00573
00574 static gvplugin_api_t apis[] = {
00575 {API_device, gvdevice_types_skillgui_cairo},
00576 {API_render, gvrender_types_skillgui_cairo},
00577 {(api_t)0, 0},
00578 };
00579
00580 gvplugin_library_t gvplugin_skillgui_cairo_LTX_library = { (char *)"skillguicairo", apis };
00581
00582 #ifdef __cplusplus
00583 }
00584 #endif
00585
00586
00587 void
00588 gvplugin_skillgui_cairo_setup(GVC_t *gvc, SkillGuiCairoRenderInstructor *sgcri)
00589 {
00590 __sgcri = sgcri;
00591 gvAddLibrary(gvc, &gvplugin_skillgui_cairo_LTX_library);
00592
00593 #if CAIROMM_MAJOR_VERSION > 1 || (CAIROMM_MAJOR_VERSION == 1 && CAIROMM_MINO_VERSION > 8)
00594 __skillgui_cairo_render_dashed.clear();
00595 __skillgui_cairo_render_dashed.push_back(6.0);
00596 __skillgui_cairo_render_dotted.clear();
00597 __skillgui_cairo_render_dotted.push_back(2.0);
00598 __skillgui_cairo_render_dotted.push_back(6.0);
00599 #else
00600 __skillgui_cairo_render_dashed[0] = 6.0;
00601 __skillgui_cairo_render_dotted[0] = 2.0;
00602 __skillgui_cairo_render_dotted[1] = 6.0;
00603 #endif
00604 }