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 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
00065
00066
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 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
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
00181
00182
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
00242
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
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
00326
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
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
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
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
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
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
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
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,
00492 0,
00493 0,
00494 0,
00495 0,
00496 0,
00497 skillgui_cairo_render_begin_page,
00498 skillgui_cairo_render_end_page,
00499 0,
00500 0,
00501 0,
00502 0,
00503 0,
00504 0,
00505 0,
00506 0,
00507 0,
00508 0,
00509 0,
00510 0,
00511 0,
00512 0,
00513 skillgui_cairo_render_textpara,
00514 0,
00515 skillgui_cairo_render_ellipse,
00516 skillgui_cairo_render_polygon,
00517 skillgui_cairo_render_bezier,
00518 skillgui_cairo_render_polyline,
00519 0,
00520 0,
00521 };
00522
00523 static gvdevice_engine_t skillgui_cairo_device_engine = {
00524 skillgui_cairo_device_init,
00525 NULL,
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,
00540 8,
00541 0,
00542 0,
00543 RGBA_DOUBLE,
00544 };
00545
00546
00547 static gvdevice_features_t skillgui_cairo_device_features = {
00548 GVDEVICE_DOES_TRUECOLOR | GVDEVICE_EVENTS,
00549 {0.,0.},
00550 {0.,0.},
00551 {96.,96.},
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 }