23 #include "gvplugin_skillgui_cairo.h"
25 #include <utils/math/angle.h>
26 #include <utils/time/tracker.h>
30 #include <gvplugin_device.h>
31 #include <gvplugin_render.h>
33 #define NOEXPORT __attribute__((visibility("hidden")))
37 #if CAIROMM_MAJOR_VERSION > 1 || (CAIROMM_MAJOR_VERSION == 1 && CAIROMM_MINO_VERSION > 8)
38 NOEXPORT std::vector<double> skillgui_cairo_render_dashed_;
39 NOEXPORT std::vector<double> skillgui_cairo_render_dotted_;
41 NOEXPORT std::valarray<double> skillgui_cairo_render_dashed_(1);
42 NOEXPORT std::valarray<double> skillgui_cairo_render_dotted_(2);
45 #ifdef USE_GVPLUGIN_TIMETRACKER
47 NOEXPORT
unsigned int ttc_page_ = tt_.add_class(
"Page");
48 NOEXPORT
unsigned int ttc_beginpage_ = tt_.add_class(
"Begin Page");
49 NOEXPORT
unsigned int ttc_ellipse_ = tt_.add_class(
"Ellipse");
50 NOEXPORT
unsigned int ttc_bezier_ = tt_.add_class(
"Bezier");
51 NOEXPORT
unsigned int ttc_polygon_ = tt_.add_class(
"Polygon");
52 NOEXPORT
unsigned int ttc_polyline_ = tt_.add_class(
"Polyline");
53 NOEXPORT
unsigned int ttc_text_ = tt_.add_class(
"Text");
54 NOEXPORT
unsigned int ttc_text_1_ = tt_.add_class(
"Text 1");
55 NOEXPORT
unsigned int ttc_text_2_ = tt_.add_class(
"Text 2");
56 NOEXPORT
unsigned int ttc_text_3_ = tt_.add_class(
"Text 3");
57 NOEXPORT
unsigned int ttc_text_4_ = tt_.add_class(
"Text 4");
58 NOEXPORT
unsigned int ttc_text_5_ = tt_.add_class(
"Text 5");
59 NOEXPORT
unsigned int tt_count_ = 0;
60 NOEXPORT
unsigned int num_ellipse_ = 0;
61 NOEXPORT
unsigned int num_bezier_ = 0;
62 NOEXPORT
unsigned int num_polygon_ = 0;
63 NOEXPORT
unsigned int num_polyline_ = 0;
64 NOEXPORT
unsigned int num_text_ = 0;
127 skillgui_cairo_device_init(GVJ_t *firstjob)
132 skillgui_cairo_device_finalize(GVJ_t *firstjob)
134 firstjob->context = (
void *)sgcri_;
135 firstjob->external_context = TRUE;
138 (firstjob->callbacks->refresh)(firstjob);
142 skillgui_cairo_set_color(Cairo::RefPtr<Cairo::Context> cairo, gvcolor_t *color)
144 cairo->set_source_rgba(color->u.RGBA[0], color->u.RGBA[1], color->u.RGBA[2], color->u.RGBA[3]);
148 skillgui_cairo_set_penstyle(Cairo::RefPtr<Cairo::Context> cairo, GVJ_t *job)
150 obj_state_t *obj = job->obj;
152 if (obj->pen == PEN_DASHED) {
153 cairo->set_dash(skillgui_cairo_render_dashed_, 0.0);
154 }
else if (obj->pen == PEN_DOTTED) {
155 cairo->set_dash(skillgui_cairo_render_dotted_, 0.0);
157 #if CAIROMM_MAJOR_VERSION > 1 || (CAIROMM_MAJOR_VERSION == 1 && CAIROMM_MINO_VERSION > 8)
158 std::vector<double> empty;
160 std::valarray<double> empty;
162 cairo->set_dash(empty, 0.0);
164 cairo->set_line_width(obj->penwidth);
168 skillgui_cairo_render_begin_page(GVJ_t *job)
170 #ifdef USE_GVPLUGIN_TIMETRACKER
171 tt_.ping_start(ttc_page_);
172 tt_.ping_start(ttc_beginpage_);
176 float bbwidth = job->bb.UR.x - job->bb.LL.x;
177 float bbheight = job->bb.UR.y - job->bb.LL.y;
179 cri->
set_bb(bbwidth, bbheight);
180 cri->
set_pad(job->pad.x, job->pad.y);
181 Cairo::RefPtr<Cairo::Context> cairo = cri->
get_cairo();
190 double avwidth, avheight;
192 float translate_x = 0;
193 float translate_y = 0;
197 float zwidth = bbwidth * zoom;
198 float zheight = bbheight * zoom;
199 translate_x += (avwidth - zwidth) / 2.;
200 translate_y += (avheight - zheight) / 2.;
202 double translate_x, translate_y;
205 cairo->translate(translate_x, translate_y);
206 cairo->scale(zoom, zoom);
209 float zoom_w = avwidth / bbwidth;
210 float zoom_h = avheight / bbheight;
211 float zoom = std::min(zoom_w, zoom_h);
213 if (bbwidth > avwidth || bbheight > avheight) {
214 float zwidth = bbwidth * zoom;
215 float zheight = bbheight * zoom;
216 translate_x += (avwidth - zwidth) / 2.;
217 translate_y += (avheight - zheight) / 2. + zheight;
220 translate_x += (avwidth - bbwidth) / 2.;
221 translate_y += (avheight - bbheight) / 2. + bbheight;
227 cairo->translate(translate_x + pad_x * zoom, translate_y - pad_y * zoom);
228 cairo->scale(zoom, zoom);
231 #ifdef USE_GVPLUGIN_TIMETRACKER
238 tt_.ping_end(ttc_beginpage_);
243 skillgui_cairo_render_end_page(GVJ_t *job)
247 #ifdef USE_GVPLUGIN_TIMETRACKER
248 tt_.ping_end(ttc_page_);
249 if (++tt_count_ >= 10) {
251 tt_.print_to_stdout();
253 printf(
"Num Ellipse: %u\n"
268 #if GRAPHVIZ_VERSION >= 23600
269 skillgui_cairo_render_textpara(GVJ_t *job, pointf p, textspan_t *para)
271 skillgui_cairo_render_textpara(GVJ_t *job, pointf p, textpara_t *para)
274 #ifdef USE_GVPLUGIN_TIMETRACKER
275 tt_.ping_start(ttc_text_);
279 Cairo::RefPtr<Cairo::Context> cairo = cri->
get_cairo();
280 obj_state_t * obj = job->obj;
282 Cairo::FontWeight weight = Cairo::FONT_WEIGHT_NORMAL;
283 Cairo::FontSlant slant = Cairo::FONT_SLANT_NORMAL;
284 char * fontweight = NULL;
285 if (obj->type == CLUSTER_OBJTYPE) {
286 fontweight = agget(obj->u.sg, (
char *)
"fontweight");
287 }
else if (obj->type == ROOTGRAPH_OBJTYPE) {
288 fontweight = agget(obj->u.g, (
char *)
"fontweight");
289 }
else if (obj->type == NODE_OBJTYPE) {
290 fontweight = agget(obj->u.n, (
char *)
"fontweight");
291 }
else if (obj->type == EDGE_OBJTYPE) {
292 fontweight = agget(obj->u.e, (
char *)
"fontweight");
294 if (fontweight && (strcmp(fontweight,
"bold") == 0)) {
295 weight = Cairo::FONT_WEIGHT_BOLD;
298 char *fontslant = NULL;
299 if (obj->type == CLUSTER_OBJTYPE) {
300 fontslant = agget(obj->u.sg, (
char *)
"fontslant");
301 }
else if (obj->type == ROOTGRAPH_OBJTYPE) {
302 fontslant = agget(obj->u.g, (
char *)
"fontslant");
303 }
else if (obj->type == NODE_OBJTYPE) {
304 fontslant = agget(obj->u.n, (
char *)
"fontslant");
305 }
else if (obj->type == EDGE_OBJTYPE) {
306 fontslant = agget(obj->u.e, (
char *)
"fontslant");
308 if (fontslant && (strcmp(fontslant,
"italic") == 0)) {
309 slant = Cairo::FONT_SLANT_ITALIC;
312 double offsetx = 0.0;
313 double offsety = 0.0;
316 if ((obj->type == EDGE_OBJTYPE) && obj->headlabel && (strcmp(para->str, obj->headlabel) == 0)) {
317 char *labelrotate = agget(obj->u.e, (
char *)
"labelrotate");
318 if (labelrotate && (strlen(labelrotate) > 0)) {
321 char *labeloffsetx = agget(obj->u.e, (
char *)
"labeloffsetx");
322 if (labeloffsetx && (strlen(labeloffsetx) > 0)) {
323 offsetx = atof(labeloffsetx);
325 char *labeloffsety = agget(obj->u.e, (
char *)
"labeloffsety");
326 if (labeloffsety && (strlen(labeloffsety) > 0)) {
327 offsety = atof(labeloffsety);
332 Cairo::Matrix old_matrix;
333 cairo->get_matrix(old_matrix);
335 #if GRAPHVIZ_VERSION >= 23600
336 cairo->select_font_face(para->font->name, slant, weight);
337 cairo->set_font_size(para->font->size);
339 cairo->select_font_face(para->fontname, slant, weight);
340 cairo->set_font_size(para->fontsize);
346 Cairo::TextExtents extents;
347 cairo->get_text_extents(para->str, extents);
349 if (para->just ==
'r') {
350 p.x -= extents.width;
351 }
else if (para->just !=
'l') {
352 p.x -= extents.width / 2.0;
355 cairo->move_to(p.x + offsetx, -p.y + offsety);
356 cairo->rotate(rotate);
357 skillgui_cairo_set_color(cairo, &(obj->pencolor));
358 cairo->text_path(para->str);
361 cairo->set_matrix(old_matrix);
364 #ifdef USE_GVPLUGIN_TIMETRACKER
365 tt_.ping_end(ttc_text_);
370 skillgui_cairo_render_ellipse(GVJ_t *job, pointf *A,
int filled)
372 #ifdef USE_GVPLUGIN_TIMETRACKER
373 tt_.ping_start(ttc_ellipse_);
378 Cairo::RefPtr<Cairo::Context> cairo = cri->
get_cairo();
379 obj_state_t * obj = job->obj;
381 Cairo::Matrix old_matrix;
382 cairo->get_matrix(old_matrix);
384 skillgui_cairo_set_penstyle(cairo, job);
386 cairo->translate(A[0].x, -A[0].y);
388 double rx = A[1].x - A[0].x;
389 double ry = A[1].y - A[0].y;
390 cairo->scale(1, ry / rx);
391 cairo->move_to(rx, 0);
392 cairo->arc(0, 0, rx, 0, 2 * M_PI);
395 cairo->set_matrix(old_matrix);
398 skillgui_cairo_set_color(cairo, &(obj->fillcolor));
399 cairo->fill_preserve();
401 skillgui_cairo_set_color(cairo, &(obj->pencolor));
404 #ifdef USE_GVPLUGIN_TIMETRACKER
405 tt_.ping_end(ttc_ellipse_);
410 skillgui_cairo_render_polygon(GVJ_t *job, pointf *A,
int n,
int filled)
412 #ifdef USE_GVPLUGIN_TIMETRACKER
413 tt_.ping_start(ttc_polygon_);
418 Cairo::RefPtr<Cairo::Context> cairo = cri->
get_cairo();
419 obj_state_t * obj = job->obj;
421 skillgui_cairo_set_penstyle(cairo, job);
423 cairo->move_to(A[0].x, -A[0].y);
424 for (
int i = 1; i < n; ++i) {
425 cairo->line_to(A[i].x, -A[i].y);
430 skillgui_cairo_set_color(cairo, &(obj->fillcolor));
431 cairo->fill_preserve();
435 if (obj->type == CLUSTER_OBJTYPE) {
436 obj->pencolor.u.RGBA[0] = 0.666;
437 obj->pencolor.u.RGBA[1] = 0.666;
438 obj->pencolor.u.RGBA[2] = 1.0;
439 obj->pencolor.u.RGBA[3] = 1.0;
441 skillgui_cairo_set_color(cairo, &(obj->pencolor));
444 #ifdef USE_GVPLUGIN_TIMETRACKER
445 tt_.ping_end(ttc_polygon_);
450 skillgui_cairo_render_bezier(GVJ_t * job,
457 #ifdef USE_GVPLUGIN_TIMETRACKER
458 tt_.ping_start(ttc_bezier_);
463 Cairo::RefPtr<Cairo::Context> cairo = cri->
get_cairo();
464 obj_state_t * obj = job->obj;
466 skillgui_cairo_set_penstyle(cairo, job);
468 cairo->move_to(A[0].x, -A[0].y);
469 for (
int i = 1; i < n; i += 3)
470 cairo->curve_to(A[i].x, -A[i].y, A[i + 1].x, -A[i + 1].y, A[i + 2].x, -A[i + 2].y);
472 skillgui_cairo_set_color(cairo, &(obj->fillcolor));
473 cairo->fill_preserve();
475 skillgui_cairo_set_color(cairo, &(obj->pencolor));
478 #ifdef USE_GVPLUGIN_TIMETRACKER
479 tt_.ping_end(ttc_bezier_);
484 skillgui_cairo_render_polyline(GVJ_t *job, pointf *A,
int n)
486 #ifdef USE_GVPLUGIN_TIMETRACKER
487 tt_.ping_start(ttc_polyline_);
492 Cairo::RefPtr<Cairo::Context> cairo = cri->
get_cairo();
493 obj_state_t * obj = job->obj;
495 skillgui_cairo_set_penstyle(cairo, job);
498 cairo->move_to(A[0].x, -A[0].y);
499 for (
int i = 1; i < n; i++) {
500 cairo->line_to(A[i].x, -A[i].y);
502 skillgui_cairo_set_color(cairo, &(obj->pencolor));
505 #ifdef USE_GVPLUGIN_TIMETRACKER
506 tt_.ping_end(ttc_polyline_);
510 static gvrender_engine_t skillgui_cairo_render_engine = {
517 skillgui_cairo_render_begin_page,
518 skillgui_cairo_render_end_page,
533 skillgui_cairo_render_textpara,
535 skillgui_cairo_render_ellipse,
536 skillgui_cairo_render_polygon,
537 skillgui_cairo_render_bezier,
538 skillgui_cairo_render_polyline,
543 static gvdevice_engine_t skillgui_cairo_device_engine = {
544 skillgui_cairo_device_init,
546 skillgui_cairo_device_finalize,
553 static gvrender_features_t skillgui_cairo_render_features = {
554 GVRENDER_Y_GOES_DOWN | GVRENDER_DOES_LABELS | GVRENDER_DOES_TRANSFORM
555 | GVRENDER_NO_WHITE_BG,
562 static gvdevice_features_t skillgui_cairo_device_features = {
563 GVDEVICE_DOES_TRUECOLOR | GVDEVICE_EVENTS,
569 gvplugin_installed_t gvdevice_types_skillgui_cairo[] = {{0,
570 (
char *)
"skillguicairo:skillguicairo",
572 &skillgui_cairo_device_engine,
573 &skillgui_cairo_device_features},
574 {0, NULL, 0, NULL, NULL}};
576 gvplugin_installed_t gvrender_types_skillgui_cairo[] = {
577 {0, (
char *)
"skillguicairo", 10, &skillgui_cairo_render_engine, &skillgui_cairo_render_features},
578 {0, NULL, 0, NULL, NULL}};
580 static gvplugin_api_t apis[] = {
581 {API_device, gvdevice_types_skillgui_cairo},
582 {API_render, gvrender_types_skillgui_cairo},
586 gvplugin_library_t gvplugin_skillgui_cairo_LTX_library = {(
char *)
"skillguicairo", apis};
596 gvAddLibrary(gvc, &gvplugin_skillgui_cairo_LTX_library);
598 #if CAIROMM_MAJOR_VERSION > 1 || (CAIROMM_MAJOR_VERSION == 1 && CAIROMM_MINO_VERSION > 8)
599 skillgui_cairo_render_dashed_.clear();
600 skillgui_cairo_render_dashed_.push_back(6.0);
601 skillgui_cairo_render_dotted_.clear();
602 skillgui_cairo_render_dotted_.push_back(2.0);
603 skillgui_cairo_render_dotted_.push_back(6.0);
605 skillgui_cairo_render_dashed_[0] = 6.0;
606 skillgui_cairo_render_dotted_[0] = 2.0;
607 skillgui_cairo_render_dotted_[1] = 6.0;
Graphviz Cairo render plugin instructor.
virtual void get_pad(double &pad_x, double &pad_y)=0
Get padding.
virtual void get_dimensions(double &width, double &height)=0
Get available space dimensions.
virtual void set_scale(double scale)=0
Set scale.
virtual void get_translation(double &tx, double &ty)=0
Get translation values.
virtual void set_translation(double tx, double ty)=0
Set translation.
virtual double get_scale()=0
Get scale factor.
virtual Cairo::RefPtr< Cairo::Context > get_cairo()=0
Get Cairo context.
virtual void set_pad(double pad_x, double pad_y)=0
Set padding.
virtual bool scale_override()=0
Check if scale override is enabled.
virtual void set_bb(double bbw, double bbh)=0
Set the bounding box.
float deg2rad(float deg)
Convert an angle given in degrees to radians.