00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include "render.h"
00028 #include "agxbuf.h"
00029 #include "htmltable.h"
00030
00031 #define P2RECT(p, pr, sx, sy) (pr[0].x = p.x - sx, pr[0].y = p.y - sy, pr[1].x = p.x + sx, pr[1].y = p.y + sy)
00032 #define FUZZ 3
00033 #define EPSILON .0001
00034
00035 static char *defaultlinestyle[3] = { "solid\0", "setlinewidth\0001\0", 0 };
00036
00037
00038 obj_state_t* push_obj_state(GVJ_t *job)
00039 {
00040 obj_state_t *obj, *parent;
00041
00042 if (! (obj = zmalloc(sizeof(obj_state_t))))
00043 agerr(AGERR, "no memory from zmalloc()\n");
00044
00045 parent = obj->parent = job->obj;
00046 job->obj = obj;
00047 if (parent) {
00048 obj->pencolor = parent->pencolor;
00049 obj->fillcolor = parent->fillcolor;
00050 obj->pen = parent->pen;
00051 obj->fill = parent->fill;
00052 obj->penwidth = parent->penwidth;
00053 }
00054 else {
00055
00056
00057 obj->pen = PEN_SOLID;
00058 obj->fill = FILL_NONE;
00059 obj->penwidth = PENWIDTH_NORMAL;
00060 }
00061 return obj;
00062 }
00063
00064
00065 void pop_obj_state(GVJ_t *job)
00066 {
00067 obj_state_t *obj = job->obj;
00068
00069 assert(obj);
00070
00071 free(obj->url);
00072 free(obj->labelurl);
00073 free(obj->tailurl);
00074 free(obj->headurl);
00075 free(obj->tooltip);
00076 free(obj->labeltooltip);
00077 free(obj->tailtooltip);
00078 free(obj->headtooltip);
00079 free(obj->target);
00080 free(obj->labeltarget);
00081 free(obj->tailtarget);
00082 free(obj->headtarget);
00083 free(obj->url_map_p);
00084 free(obj->url_bsplinemap_p);
00085 free(obj->url_bsplinemap_n);
00086
00087 job->obj = obj->parent;
00088 free(obj);
00089 }
00090
00091
00092
00093
00094
00095
00096 int
00097 initMapData (GVJ_t* job, char* lbl, char* url, char* tooltip, char* target,
00098 void* gobj)
00099 {
00100 obj_state_t *obj = job->obj;
00101 int flags = job->flags;
00102 int assigned = 0;
00103
00104 if ((flags & GVRENDER_DOES_LABELS) && lbl)
00105 obj->label = lbl;
00106 if ((flags & GVRENDER_DOES_MAPS) && url && url[0]) {
00107 obj->url = strdup_and_subst_obj(url, gobj);
00108 assigned = 1;
00109 }
00110 if (flags & GVRENDER_DOES_TOOLTIPS) {
00111 if (tooltip && tooltip[0]) {
00112 obj->tooltip = strdup_and_subst_obj(tooltip, gobj);
00113 obj->explicit_tooltip = TRUE;
00114 assigned = 1;
00115 }
00116 else if (obj->label) {
00117 obj->tooltip = strdup(obj->label);
00118 assigned = 1;
00119 }
00120 }
00121 if ((flags & GVRENDER_DOES_TARGETS) && target && target[0]) {
00122 obj->target = strdup_and_subst_obj(target, gobj);
00123 assigned = 1;
00124 }
00125 return assigned;
00126 }
00127
00128 static void
00129 initObjMapData (GVJ_t* job, textlabel_t *lab, void* gobj)
00130 {
00131 char* lbl;
00132 char* url = agget(gobj, "href");
00133 char* tooltip = agget(gobj, "tooltip");
00134 char* target = agget(gobj, "target");
00135
00136 if (lab) lbl = lab->text;
00137 else lbl = NULL;
00138 if (!url || !*url) url = agget(gobj, "URL");
00139 initMapData (job, lbl, url, tooltip, target, gobj);
00140 }
00141
00142 static void map_point(GVJ_t *job, point P)
00143 {
00144 obj_state_t *obj = job->obj;
00145 int flags = job->flags;
00146 pointf *p, pf;
00147
00148 if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
00149 if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
00150 obj->url_map_shape = MAP_RECTANGLE;
00151 obj->url_map_n = 2;
00152 }
00153 else {
00154 obj->url_map_shape = MAP_POLYGON;
00155 obj->url_map_n = 4;
00156 }
00157 free(obj->url_map_p);
00158 obj->url_map_p = p = N_NEW(obj->url_map_n, pointf);
00159 P2PF(P,pf);
00160 P2RECT(pf, p, FUZZ, FUZZ);
00161 if (! (flags & GVRENDER_DOES_TRANSFORM))
00162 gvrender_ptf_A(job, p, p, 2);
00163 if (! (flags & GVRENDER_DOES_MAP_RECTANGLE))
00164 rect2poly(p);
00165 }
00166 }
00167
00168 void emit_map_rect(GVJ_t *job, point LL, point UR)
00169 {
00170 obj_state_t *obj = job->obj;
00171 int flags = job->flags;
00172 pointf *p;
00173
00174 if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
00175 if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
00176 obj->url_map_shape = MAP_RECTANGLE;
00177 obj->url_map_n = 2;
00178 }
00179 else {
00180 obj->url_map_shape = MAP_POLYGON;
00181 obj->url_map_n = 4;
00182 }
00183 free(obj->url_map_p);
00184 obj->url_map_p = p = N_NEW(obj->url_map_n, pointf);
00185 P2PF(LL,p[0]);
00186 P2PF(UR,p[1]);
00187 if (! (flags & GVRENDER_DOES_TRANSFORM))
00188 gvrender_ptf_A(job, p, p, 2);
00189 if (! (flags & GVRENDER_DOES_MAP_RECTANGLE))
00190 rect2poly(p);
00191 }
00192 }
00193
00194 static void map_label(GVJ_t *job, textlabel_t *lab)
00195 {
00196 obj_state_t *obj = job->obj;
00197 int flags = job->flags;
00198 pointf *p;
00199
00200 if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
00201 if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
00202 obj->url_map_shape = MAP_RECTANGLE;
00203 obj->url_map_n = 2;
00204 }
00205 else {
00206 obj->url_map_shape = MAP_POLYGON;
00207 obj->url_map_n = 4;
00208 }
00209 free(obj->url_map_p);
00210 obj->url_map_p = p = N_NEW(obj->url_map_n, pointf);
00211 P2RECT(lab->p, p, lab->dimen.x / 2., lab->dimen.y / 2.);
00212 if (! (flags & GVRENDER_DOES_TRANSFORM))
00213 gvrender_ptf_A(job, p, p, 2);
00214 if (! (flags & GVRENDER_DOES_MAP_RECTANGLE))
00215 rect2poly(p);
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224 static boolean isRect(polygon_t * p)
00225 {
00226 return (p->sides == 4 && (ROUND(p->orientation) % 90) == 0
00227 && p->distortion == 0.0 && p->skew == 0.0);
00228 }
00229
00230
00231
00232
00233
00234 static int ifFilled(node_t * n)
00235 {
00236 char *style, *p, **pp;
00237 int r = 0;
00238 style = late_nnstring(n, N_style, "");
00239 if (style[0]) {
00240 pp = parse_style(style);
00241 while ((p = *pp)) {
00242 if (strcmp(p, "filled") == 0)
00243 r = 1;
00244 pp++;
00245 }
00246 }
00247 return r;
00248 }
00249
00250
00251
00252
00253
00254
00255
00256 static pointf *pEllipse(double a, double b, int np)
00257 {
00258 double theta = 0.0;
00259 double deltheta = 2 * M_PI / np;
00260 int i;
00261 pointf *ps;
00262
00263 ps = N_NEW(np, pointf);
00264 for (i = 0; i < np; i++) {
00265 ps[i].x = a * cos(theta);
00266 ps[i].y = b * sin(theta);
00267 theta += deltheta;
00268 }
00269 return ps;
00270 }
00271
00272 #define HW 2.0
00273
00274
00275
00276
00277
00278
00279
00280 static int check_control_points(pointf *cp)
00281 {
00282 double dis1 = ptToLine2 (cp[0], cp[3], cp[1]);
00283 double dis2 = ptToLine2 (cp[0], cp[3], cp[2]);
00284 if (dis1 < HW*HW && dis2 < HW*HW)
00285 return 1;
00286 else
00287 return 0;
00288 }
00289
00290 #ifdef DEBUG
00291 static void psmapOutput (pointf* ps, int n)
00292 {
00293 int i;
00294 fprintf (stdout, "newpath %f %f moveto\n", ps[0].x, ps[0].y);
00295 for (i=1; i < n; i++)
00296 fprintf (stdout, "%f %f lineto\n", ps[i].x, ps[i].y);
00297 fprintf (stdout, "closepath stroke\n");
00298 }
00299 #endif
00300
00301 typedef struct segitem_s {
00302 pointf p;
00303 struct segitem_s* next;
00304 } segitem_t;
00305
00306 #define MARK_FIRST_SEG(L) ((L)->next = (segitem_t*)1)
00307 #define FIRST_SEG(L) ((L)->next == (segitem_t*)1)
00308 #define INIT_SEG(P,L) {(L)->next = 0; (L)->p = P;}
00309
00310 static segitem_t* appendSeg (pointf p, segitem_t* lp)
00311 {
00312 segitem_t* s = GNEW(segitem_t);
00313 INIT_SEG (p, s);
00314 lp->next = s;
00315 return s;
00316 }
00317
00318
00319
00320
00321
00322 static void map_bspline_poly(pointf **pbs_p, int **pbs_n, int *pbs_poly_n, int n, pointf* p1, pointf* p2)
00323 {
00324 int i = 0, nump = 0, last = 2*n-1;
00325
00326 for ( ; i < *pbs_poly_n; i++)
00327 nump += (*pbs_n)[i];
00328
00329 (*pbs_poly_n)++;
00330 *pbs_n = grealloc(*pbs_n, (*pbs_poly_n) * sizeof(int));
00331 (*pbs_n)[i] = 2*n;
00332 *pbs_p = grealloc(*pbs_p, (nump + 2*n) * sizeof(pointf));
00333
00334 for (i = 0; i < n; i++) {
00335 (*pbs_p)[nump+i] = p1[i];
00336 (*pbs_p)[nump+last-i] = p2[i];
00337 }
00338 #ifdef DEBUG
00339 psmapOutput (*pbs_p + nump, last+1);
00340 #endif
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 static segitem_t* approx_bezier (pointf *cp, segitem_t* lp)
00353 {
00354 pointf sub_curves[8];
00355
00356 if (check_control_points(cp)) {
00357 if (FIRST_SEG (lp)) INIT_SEG (cp[0], lp);
00358 lp = appendSeg (cp[3], lp);
00359 }
00360 else {
00361 Bezier (cp, 3, 0.5, sub_curves, sub_curves+4);
00362 lp = approx_bezier (sub_curves, lp);
00363 lp = approx_bezier (sub_curves+4, lp);
00364 }
00365 return lp;
00366 }
00367
00368
00369
00370
00371
00372
00373 static double bisect (pointf pp, pointf cp, pointf np)
00374 {
00375 double ang, theta, phi;
00376 theta = atan2(np.y - cp.y,np.x - cp.x);
00377 phi = atan2(pp.y - cp.y,pp.x - cp.x);
00378 ang = theta - phi;
00379 if (ang > 0) ang -= 2*M_PI;
00380
00381 return (phi + ang/2.0);
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 static void mkSegPts (segitem_t* prv, segitem_t* cur, segitem_t* nxt,
00393 pointf* p1, pointf* p2, double w2)
00394 {
00395 pointf cp, pp, np;
00396 double theta, delx, dely;
00397 pointf p;
00398
00399 cp = cur->p;
00400
00401
00402
00403
00404 if (prv) {
00405 pp = prv->p;
00406 if (nxt)
00407 np = nxt->p;
00408 else {
00409 np.x = 2*cp.x - pp.x;
00410 np.y = 2*cp.y - pp.y;
00411 }
00412 }
00413 else {
00414 np = nxt->p;
00415 pp.x = 2*cp.x - np.x;
00416 pp.y = 2*cp.y - np.y;
00417 }
00418 theta = bisect(pp,cp,np);
00419 delx = w2*cos(theta);
00420 dely = w2*sin(theta);
00421 p.x = cp.x + delx;
00422 p.y = cp.y + dely;
00423 *p1 = p;
00424 p.x = cp.x - delx;
00425 p.y = cp.y - dely;
00426 *p2 = p;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 static void map_output_bspline (pointf **pbs, int **pbs_n, int *pbs_poly_n, bezier* bp, double w2)
00438 {
00439 segitem_t* segl = GNEW(segitem_t);
00440 segitem_t* segp = segl;
00441 segitem_t* segprev;
00442 segitem_t* segnext;
00443 int nc, j, k, cnt;
00444 pointf pts[4];
00445 pointf pt1[50], pt2[50];
00446
00447 MARK_FIRST_SEG(segl);
00448 nc = (bp->size - 1)/3;
00449 for (j = 0; j < nc; j++) {
00450 for (k = 0; k < 4; k++) {
00451 pts[k].x = (double)bp->list[3*j + k].x;
00452 pts[k].y = (double)bp->list[3*j + k].y;
00453 }
00454 segp = approx_bezier (pts, segp);
00455 }
00456
00457 segp = segl;
00458 segprev = 0;
00459 cnt = 0;
00460 while (segp) {
00461 segnext = segp->next;
00462 mkSegPts (segprev, segp, segnext, pt1+cnt, pt2+cnt, w2);
00463 cnt++;
00464 if ((segnext == NULL) || (cnt == 50)) {
00465 map_bspline_poly (pbs, pbs_n, pbs_poly_n, cnt, pt1, pt2);
00466 pt1[0] = pt1[cnt-1];
00467 pt2[0] = pt2[cnt-1];
00468 cnt = 1;
00469 }
00470 segprev = segp;
00471 segp = segnext;
00472 }
00473
00474
00475 while (segl) {
00476 segp = segl->next;
00477 free (segl);
00478 segl = segp;
00479 }
00480 }
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 static int parse_layers(GVC_t *gvc, graph_t * g, char *p)
00491 {
00492 int ntok;
00493 char *tok;
00494 int sz;
00495
00496 gvc->layerDelims = agget(g, "layersep");
00497 if (!gvc->layerDelims)
00498 gvc->layerDelims = DEFAULT_LAYERSEP;
00499
00500 ntok = 0;
00501 sz = 0;
00502 gvc->layers = strdup(p);
00503
00504 for (tok = strtok(gvc->layers, gvc->layerDelims); tok;
00505 tok = strtok(NULL, gvc->layerDelims)) {
00506 ntok++;
00507 if (ntok > sz) {
00508 sz += SMALLBUF;
00509 gvc->layerIDs = ALLOC(sz, gvc->layerIDs, char *);
00510 }
00511 gvc->layerIDs[ntok] = tok;
00512 }
00513 if (ntok) {
00514 gvc->layerIDs = RALLOC(ntok + 2, gvc->layerIDs, char *);
00515 gvc->layerIDs[0] = NULL;
00516 gvc->layerIDs[ntok + 1] = NULL;
00517 }
00518
00519 return ntok;
00520 }
00521
00522
00523
00524
00525
00526 static int chkOrder(graph_t * g)
00527 {
00528 char *p = agget(g, "outputorder");
00529 if (p) {
00530 char c = *p;
00531 if ((c == 'n') && !strcmp(p + 1, "odesfirst"))
00532 return EMIT_SORTED;
00533 if ((c == 'e') && !strcmp(p + 1, "dgesfirst"))
00534 return EMIT_EDGE_SORTED;
00535 }
00536 return 0;
00537 }
00538
00539 static void init_layering(GVC_t * gvc, graph_t * g)
00540 {
00541 char *str;
00542
00543
00544 if (gvc->layers)
00545 free(gvc->layers);
00546 if (gvc->layerIDs)
00547 free(gvc->layerIDs);
00548
00549 if ((str = agget(g, "layers")) != 0) {
00550 gvc->numLayers = parse_layers(gvc, g, str);
00551 } else {
00552 gvc->layerIDs = NULL;
00553 gvc->numLayers = 1;
00554 }
00555 }
00556
00557 static void firstlayer(GVJ_t *job)
00558 {
00559 job->numLayers = job->gvc->numLayers;
00560 if ((job->numLayers > 1)
00561 && (! (job->flags & GVDEVICE_DOES_LAYERS))) {
00562 agerr(AGWARN, "layers not supported in %s output\n",
00563 job->output_langname);
00564 job->numLayers = 1;
00565 }
00566
00567 job->layerNum = 1;
00568 }
00569
00570 static boolean validlayer(GVJ_t *job)
00571 {
00572 return (job->layerNum <= job->numLayers);
00573 }
00574
00575 static void nextlayer(GVJ_t *job)
00576 {
00577 job->layerNum++;
00578 }
00579
00580 static point pagecode(GVJ_t *job, char c)
00581 {
00582 point rv;
00583 rv.x = rv.y = 0;
00584 switch (c) {
00585 case 'T':
00586 job->pagesArrayFirst.y = job->pagesArraySize.y - 1;
00587 rv.y = -1;
00588 break;
00589 case 'B':
00590 rv.y = 1;
00591 break;
00592 case 'L':
00593 rv.x = 1;
00594 break;
00595 case 'R':
00596 job->pagesArrayFirst.x = job->pagesArraySize.x - 1;
00597 rv.x = -1;
00598 break;
00599 }
00600 return rv;
00601 }
00602
00603 static void init_job_pagination(GVJ_t * job, graph_t *g)
00604 {
00605 GVC_t *gvc = job->gvc;
00606 pointf pageSize;
00607 pointf imageSize;
00608 pointf margin;
00609 pointf centering = {0.0, 0.0};
00610
00611
00612 imageSize = job->view;
00613
00614
00615 if (job->rotation)
00616 imageSize = exch_xyf(imageSize);
00617
00618
00619 margin = job->margin;
00620
00621
00622 if (gvc->graph_sets_pageSize) {
00623
00624
00625
00626 pageSize.x = gvc->pageSize.x - 2 * margin.x;
00627 pageSize.y = gvc->pageSize.y - 2 * margin.y;
00628
00629 if (pageSize.x < EPSILON)
00630 job->pagesArraySize.x = 1;
00631 else {
00632 job->pagesArraySize.x = (int)(imageSize.x / pageSize.x);
00633 if ((imageSize.x - (job->pagesArraySize.x * pageSize.x)) > EPSILON)
00634 job->pagesArraySize.x++;
00635 }
00636 if (pageSize.y < EPSILON)
00637 job->pagesArraySize.y = 1;
00638 else {
00639 job->pagesArraySize.y = (int)(imageSize.y / pageSize.y);
00640 if ((imageSize.y - (job->pagesArraySize.y * pageSize.y)) > EPSILON)
00641 job->pagesArraySize.y++;
00642 }
00643 job->numPages = job->pagesArraySize.x * job->pagesArraySize.y;
00644
00645
00646 imageSize.x = MIN(imageSize.x, pageSize.x);
00647 imageSize.y = MIN(imageSize.y, pageSize.y);
00648 } else {
00649
00650 if (job->render.features) {
00651 pageSize.x = job->device.features->default_pagesize.x - 2*margin.x;
00652 if (pageSize.x < 0.)
00653 pageSize.x = 0.;
00654 pageSize.y = job->device.features->default_pagesize.y - 2*margin.y;
00655 if (pageSize.y < 0.)
00656 pageSize.y = 0.;
00657 }
00658 else
00659 pageSize.x = pageSize.y = 0.;
00660 job->pagesArraySize.x = job->pagesArraySize.y = job->numPages = 1;
00661
00662 if (pageSize.x < imageSize.x)
00663 pageSize.x = imageSize.x;
00664 if (pageSize.y < imageSize.y)
00665 pageSize.y = imageSize.y;
00666 }
00667
00668
00669 job->width = ROUND((pageSize.x + 2*margin.x) * job->dpi.x / POINTS_PER_INCH);
00670 job->height = ROUND((pageSize.y + 2*margin.y) * job->dpi.y / POINTS_PER_INCH);
00671
00672
00673 job->pagesArrayMajor.x = job->pagesArrayMajor.y
00674 = job->pagesArrayMinor.x = job->pagesArrayMinor.y = 0;
00675 job->pagesArrayFirst.x = job->pagesArrayFirst.y = 0;
00676 job->pagesArrayMajor = pagecode(job, gvc->pagedir[0]);
00677 job->pagesArrayMinor = pagecode(job, gvc->pagedir[1]);
00678 if ((abs(job->pagesArrayMajor.x + job->pagesArrayMinor.x) != 1)
00679 || (abs(job->pagesArrayMajor.y + job->pagesArrayMinor.y) != 1)) {
00680 job->pagesArrayMajor = pagecode(job, 'B');
00681 job->pagesArrayMinor = pagecode(job, 'L');
00682 agerr(AGWARN, "pagedir=%s ignored\n", gvc->pagedir);
00683 }
00684
00685
00686 if (GD_drawing(g)->centered) {
00687 if (pageSize.x > imageSize.x)
00688 centering.x = (pageSize.x - imageSize.x) / 2;
00689 if (pageSize.y > imageSize.y)
00690 centering.y = (pageSize.y - imageSize.y) / 2;
00691 }
00692
00693
00694 if (job->rotation) {
00695 imageSize = exch_xyf(imageSize);
00696 pageSize = exch_xyf(pageSize);
00697 margin = exch_xyf(margin);
00698 centering = exch_xyf(centering);
00699 }
00700
00701
00702 job->canvasBox.LL.x = margin.x + centering.x;
00703 job->canvasBox.LL.y = margin.y + centering.y;
00704 job->canvasBox.UR.x = margin.x + centering.x + imageSize.x;
00705 job->canvasBox.UR.y = margin.y + centering.y + imageSize.y;
00706
00707
00708 job->pageSize.x = imageSize.x / job->zoom;
00709 job->pageSize.y = imageSize.y / job->zoom;
00710 }
00711
00712 static void firstpage(GVJ_t *job)
00713 {
00714 job->pagesArrayElem = job->pagesArrayFirst;
00715 }
00716
00717 static boolean validpage(GVJ_t *job)
00718 {
00719 return ((job->pagesArrayElem.x >= 0)
00720 && (job->pagesArrayElem.x < job->pagesArraySize.x)
00721 && (job->pagesArrayElem.y >= 0)
00722 && (job->pagesArrayElem.y < job->pagesArraySize.y));
00723 }
00724
00725 static void nextpage(GVJ_t *job)
00726 {
00727 job->pagesArrayElem = add_points(job->pagesArrayElem, job->pagesArrayMinor);
00728 if (validpage(job) == FALSE) {
00729 if (job->pagesArrayMajor.y)
00730 job->pagesArrayElem.x = job->pagesArrayFirst.x;
00731 else
00732 job->pagesArrayElem.y = job->pagesArrayFirst.y;
00733 job->pagesArrayElem = add_points(job->pagesArrayElem, job->pagesArrayMajor);
00734 }
00735 }
00736
00737 static boolean write_edge_test(Agraph_t * g, Agedge_t * e)
00738 {
00739 Agraph_t *sg;
00740 int c;
00741
00742 for (c = 1; c <= GD_n_cluster(g); c++) {
00743 sg = GD_clust(g)[c];
00744 if (agcontains(sg, e))
00745 return FALSE;
00746 }
00747 return TRUE;
00748 }
00749
00750 static boolean write_node_test(Agraph_t * g, Agnode_t * n)
00751 {
00752 Agraph_t *sg;
00753 int c;
00754
00755 for (c = 1; c <= GD_n_cluster(g); c++) {
00756 sg = GD_clust(g)[c];
00757 if (agcontains(sg, n))
00758 return FALSE;
00759 }
00760 return TRUE;
00761 }
00762
00763 void emit_background(GVJ_t * job, graph_t *g)
00764 {
00765 char *str;
00766
00767 if (! ((str = agget(g, "bgcolor")) && str[0])) {
00768 if (job->flags & GVRENDER_NO_BG)
00769 str = "transparent";
00770 else
00771 str = "white";
00772 }
00773
00774 gvrender_set_fillcolor(job, str);
00775 gvrender_set_pencolor(job, str);
00776 gvrender_box(job, job->clip, TRUE);
00777 }
00778
00779 static void setup_page(GVJ_t * job, graph_t * g)
00780 {
00781 point pagesArrayElem = job->pagesArrayElem, pagesArraySize = job->pagesArraySize;
00782
00783 if (job->rotation) {
00784 pagesArrayElem = exch_xy(pagesArrayElem);
00785 pagesArraySize = exch_xy(pagesArraySize);
00786 }
00787
00788
00789 job->pageBox.LL.x = pagesArrayElem.x * job->pageSize.x - job->pad.x;
00790 job->pageBox.LL.y = pagesArrayElem.y * job->pageSize.y - job->pad.y;
00791 job->pageBox.UR.x = job->pageBox.LL.x + job->pageSize.x;
00792 job->pageBox.UR.y = job->pageBox.LL.y + job->pageSize.y;
00793
00794
00795 job->pageBoundingBox.LL.x = ROUND(job->canvasBox.LL.x * job->dpi.x / POINTS_PER_INCH);
00796 job->pageBoundingBox.LL.y = ROUND(job->canvasBox.LL.y * job->dpi.y / POINTS_PER_INCH);
00797 job->pageBoundingBox.UR.x = ROUND(job->canvasBox.UR.x * job->dpi.x / POINTS_PER_INCH);
00798 job->pageBoundingBox.UR.y = ROUND(job->canvasBox.UR.y * job->dpi.y / POINTS_PER_INCH);
00799 if (job->rotation) {
00800 job->pageBoundingBox.LL = exch_xy(job->pageBoundingBox.LL);
00801 job->pageBoundingBox.UR = exch_xy(job->pageBoundingBox.UR);
00802 }
00803
00804
00805 if (job->common->viewNum == 0)
00806 job->boundingBox = job->pageBoundingBox;
00807 else
00808 EXPANDBB(job->boundingBox, job->pageBoundingBox);
00809
00810
00811
00812
00813 job->pageOffset.x = - job->pageSize.x * pagesArrayElem.x;
00814 job->pageOffset.y = - job->pageSize.y * pagesArrayElem.y;
00815 if (job->rotation) {
00816 job->clip.LL.x = job->focus.x - job->pageOffset.x - pagesArraySize.x * job->pageSize.x / 2.;
00817 job->clip.UR.y = job->focus.y + job->pageOffset.y + pagesArraySize.y * job->pageSize.y / 2.;
00818 job->clip.UR.x = job->clip.LL.x + job->view.x - 2 * job->margin.y / job->zoom;
00819 job->clip.LL.y = job->clip.UR.y - job->view.y + 2 * job->margin.x / job->zoom;
00820 job->translation.y = - job->clip.UR.y - job->canvasBox.LL.y / job->zoom;
00821 if ((job->flags & GVRENDER_Y_GOES_DOWN) || (Y_invert))
00822 job->translation.x = - job->clip.UR.x - job->canvasBox.LL.x / job->zoom;
00823 else
00824 job->translation.x = - job->clip.LL.x + job->canvasBox.LL.x / job->zoom;
00825 }
00826 else {
00827 job->clip.LL.x = job->focus.x - job->pageOffset.x - pagesArraySize.x * job->pageSize.x / 2.;
00828 job->clip.LL.y = job->focus.y - job->pageOffset.y - pagesArraySize.y * job->pageSize.y / 2.;
00829 job->clip.UR.x = job->clip.LL.x + job->view.x - 2 * job->margin.x / job->zoom;
00830 job->clip.UR.y = job->clip.LL.y + job->view.y - 2 * job->margin.y / job->zoom;
00831
00832 job->translation.x = - job->clip.LL.x + job->canvasBox.LL.x / job->zoom;
00833 if ((job->flags & GVRENDER_Y_GOES_DOWN) || (Y_invert))
00834 job->translation.y = - job->clip.UR.y - job->canvasBox.LL.y / job->zoom;
00835 else
00836 job->translation.y = - job->clip.LL.y + job->canvasBox.LL.y / job->zoom;
00837 }
00838
00839 #if 0
00840 fprintf(stderr,"width=%d height=%d dpi=%g,%g\npad=%g,%g focus=%g,%g view=%g,%g zoom=%g\npageBox=%g,%g,%g,%g pagesArraySize=%d,%d pageSize=%g,%g canvasBox=%g,%g,%g,%g pageOffset=%g,%g\ntranslation=%g,%g clip=%g,%g,%g,%g margin=%g,%g\n",
00841 job->width, job->height,
00842 job->dpi.x, job->dpi.y,
00843 job->pad.x, job->pad.y,
00844 job->focus.x, job->focus.y,
00845 job->view.x, job->view.y,
00846 job->zoom,
00847 job->pageBox.LL.x, job->pageBox.LL.y, job->pageBox.UR.x, job->pageBox.UR.y,
00848 job->pagesArraySize.x, job->pagesArraySize.y,
00849 job->pageSize.x, job->pageSize.y,
00850 job->canvasBox.LL.x, job->canvasBox.LL.y, job->canvasBox.UR.x, job->canvasBox.UR.y,
00851 job->pageOffset.x, job->pageOffset.y,
00852 job->translation.x, job->translation.y,
00853 job->clip.LL.x, job->clip.LL.y, job->clip.UR.x, job->clip.UR.y,
00854 job->margin.x, job->margin.y);
00855 #endif
00856 }
00857
00858 static boolean is_natural_number(char *sstr)
00859 {
00860 unsigned char *str = (unsigned char *) sstr;
00861
00862 while (*str)
00863 if (NOT(isdigit(*str++)))
00864 return FALSE;
00865 return TRUE;
00866 }
00867
00868 static int layer_index(GVC_t *gvc, char *str, int all)
00869 {
00870 GVJ_t *job = gvc->job;
00871 int i;
00872
00873 if (streq(str, "all"))
00874 return all;
00875 if (is_natural_number(str))
00876 return atoi(str);
00877 if (gvc->layerIDs)
00878 for (i = 1; i <= job->numLayers; i++)
00879 if (streq(str, gvc->layerIDs[i]))
00880 return i;
00881 return -1;
00882 }
00883
00884 static boolean selectedlayer(GVJ_t *job, char *spec)
00885 {
00886 GVC_t *gvc = job->gvc;
00887 int n0, n1;
00888 unsigned char buf[SMALLBUF];
00889 char *w0, *w1;
00890 agxbuf xb;
00891 boolean rval = FALSE;
00892
00893 agxbinit(&xb, SMALLBUF, buf);
00894 agxbput(&xb, spec);
00895 w1 = w0 = strtok(agxbuse(&xb), gvc->layerDelims);
00896 if (w0)
00897 w1 = strtok(NULL, gvc->layerDelims);
00898 switch ((w0 != NULL) + (w1 != NULL)) {
00899 case 0:
00900 rval = FALSE;
00901 break;
00902 case 1:
00903 n0 = layer_index(gvc, w0, job->layerNum);
00904 rval = (n0 == job->layerNum);
00905 break;
00906 case 2:
00907 n0 = layer_index(gvc, w0, 0);
00908 n1 = layer_index(gvc, w1, job->numLayers);
00909 if ((n0 < 0) || (n1 < 0))
00910 rval = TRUE;
00911 else if (n0 > n1) {
00912 int t = n0;
00913 n0 = n1;
00914 n1 = t;
00915 }
00916 rval = BETWEEN(n0, job->layerNum, n1);
00917 break;
00918 }
00919 agxbfree(&xb);
00920 return rval;
00921 }
00922
00923 static boolean node_in_layer(GVJ_t *job, graph_t * g, node_t * n)
00924 {
00925 char *pn, *pe;
00926 edge_t *e;
00927
00928 if (job->numLayers <= 1)
00929 return TRUE;
00930 pn = late_string(n, N_layer, "");
00931 if (selectedlayer(job, pn))
00932 return TRUE;
00933 if (pn[0])
00934 return FALSE;
00935 if ((e = agfstedge(g, n)) == NULL)
00936 return TRUE;
00937 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00938 pe = late_string(e, E_layer, "");
00939 if ((pe[0] == '\0') || selectedlayer(job, pe))
00940 return TRUE;
00941 }
00942 return FALSE;
00943 }
00944
00945 static boolean edge_in_layer(GVJ_t *job, graph_t * g, edge_t * e)
00946 {
00947 char *pe, *pn;
00948 int cnt;
00949
00950 if (job->numLayers <= 1)
00951 return TRUE;
00952 pe = late_string(e, E_layer, "");
00953 if (selectedlayer(job, pe))
00954 return TRUE;
00955 if (pe[0])
00956 return FALSE;
00957 for (cnt = 0; cnt < 2; cnt++) {
00958 pn = late_string(cnt < 1 ? e->tail : e->head, N_layer, "");
00959 if ((pn[0] == '\0') || selectedlayer(job, pn))
00960 return TRUE;
00961 }
00962 return FALSE;
00963 }
00964
00965 static boolean clust_in_layer(GVJ_t *job, graph_t * sg)
00966 {
00967 char *pg;
00968 node_t *n;
00969
00970 if (job->numLayers <= 1)
00971 return TRUE;
00972 pg = late_string(sg, agfindattr(sg, "layer"), "");
00973 if (selectedlayer(job, pg))
00974 return TRUE;
00975 if (pg[0])
00976 return FALSE;
00977 for (n = agfstnode(sg); n; n = agnxtnode(sg, n))
00978 if (node_in_layer(job, sg, n))
00979 return TRUE;
00980 return FALSE;
00981 }
00982
00983 static boolean node_in_box(node_t *n, boxf b)
00984 {
00985 return boxf_overlap(ND_bb(n), b);
00986 }
00987
00988 static void emit_begin_node(GVJ_t * job, node_t * n)
00989 {
00990 obj_state_t *obj;
00991 int flags = job->flags;
00992 int sides, peripheries, i, j, filled = 0, rect = 0, shape, nump = 0;
00993 polygon_t *poly = NULL;
00994 pointf *vertices, ldimen, *p = NULL;
00995 point coord;
00996 char *s;
00997
00998 obj = push_obj_state(job);
00999 obj->type = NODE_OBJTYPE;
01000 obj->u.n = n;
01001 obj->emit_state = EMIT_NDRAW;
01002
01003 if (flags & GVRENDER_DOES_Z) {
01004 obj->z = late_double(n, N_z, 0.0, -MAXFLOAT);
01005 }
01006 initObjMapData (job, ND_label(n), n);
01007 if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS))
01008 && (obj->url || obj->explicit_tooltip)) {
01009
01010
01011 shape = shapeOf(n);
01012
01013 coord = ND_coord_i(n);
01014
01015 filled = ifFilled(n);
01016
01017 if (shape == SH_POLY || shape == SH_POINT) {
01018 poly = (polygon_t *) ND_shape_info(n);
01019
01020
01021 if (isRect(poly) && (poly->peripheries || filled))
01022 rect = 1;
01023 }
01024
01025
01026
01027
01028
01029
01030 if (poly && !rect && (flags & GVRENDER_DOES_MAP_POLYGON)) {
01031
01032 if (poly->sides < 3)
01033 sides = 1;
01034 else
01035 sides = poly->sides;
01036
01037 if (poly->peripheries < 2)
01038 peripheries = 1;
01039 else
01040 peripheries = poly->peripheries;
01041
01042 vertices = poly->vertices;
01043
01044 if ((s = agget(n, "samplepoints")))
01045 nump = atoi(s);
01046
01047
01048
01049
01050 if ((nump < 4) || (nump > 60))
01051 nump = DFLT_SAMPLE;
01052
01053
01054
01055 if (poly->peripheries == 0 && !filled) {
01056 obj->url_map_shape = MAP_RECTANGLE;
01057 nump = 2;
01058 p = N_NEW(nump, pointf);
01059 ldimen = ND_label(n)->dimen;
01060 P2RECT(coord, p, ldimen.x / 2.0, ldimen.y / 2.0);
01061 }
01062
01063 else if (poly->sides < 3 && poly->skew == 0.0 && poly->distortion == 0.0) {
01064 if (poly->regular) {
01065 obj->url_map_shape = MAP_CIRCLE;
01066 nump = 2;
01067 p = N_NEW(nump, pointf);
01068 p[0].x = coord.x;
01069 p[0].y = coord.y;
01070
01071 p[1].x = coord.x - vertices[peripheries - 1].x;
01072 p[1].y = coord.y - vertices[peripheries - 1].y;
01073 }
01074 else {
01075 obj->url_map_shape= MAP_POLYGON;
01076 p = pEllipse((double)(vertices[peripheries - 1].x),
01077 (double)(vertices[peripheries - 1].y), nump);
01078 for (i = 0; i < nump; i++) {
01079 p[i].x += coord.x;
01080 p[i].y += coord.y;
01081 }
01082 }
01083 }
01084
01085 else {
01086 int offset = (peripheries - 1)*(poly->sides);
01087 obj->url_map_shape = MAP_POLYGON;
01088
01089
01090
01091 if (poly->sides >= nump) {
01092 int delta = poly->sides / nump;
01093 p = N_NEW(nump, pointf);
01094 for (i = 0, j = 0; j < nump; i += delta, j++) {
01095 p[j].x = coord.x + vertices[i + offset].x;
01096 p[j].y = coord.y + vertices[i + offset].y;
01097 }
01098 } else {
01099 nump = sides;
01100 p = N_NEW(nump, pointf);
01101 for (i = 0; i < nump; i++) {
01102 p[i].x = coord.x + vertices[i + offset].x;
01103 p[i].y = coord.y + vertices[i + offset].y;
01104 }
01105 }
01106 }
01107 }
01108 else {
01109
01110
01111
01112 obj->url_map_shape = MAP_RECTANGLE;
01113 nump = 2;
01114 p = N_NEW(nump, pointf);
01115 p[0].x = coord.x - ND_lw_i(n);
01116 p[0].y = coord.y - (ND_ht_i(n) / 2);
01117 p[1].x = coord.x + ND_rw_i(n);
01118 p[1].y = coord.y + (ND_ht_i(n) / 2);
01119 }
01120 if (! (flags & GVRENDER_DOES_TRANSFORM))
01121 gvrender_ptf_A(job, p, p, nump);
01122 obj->url_map_p = p;
01123 obj->url_map_n = nump;
01124 }
01125
01126 #ifdef WITH_CODEGENS
01127 Obj = NODE;
01128 #endif
01129 setColorScheme (agget (n, "colorscheme"));
01130 gvrender_begin_context(job);
01131 gvrender_begin_node(job, n);
01132 }
01133
01134 static void emit_end_node(GVJ_t * job)
01135 {
01136 gvrender_end_node(job);
01137 gvrender_end_context(job);
01138 #ifdef WITH_CODEGENS
01139 Obj = NONE;
01140 #endif
01141 pop_obj_state(job);
01142 }
01143
01144 static void emit_node(GVJ_t * job, node_t * n)
01145 {
01146 GVC_t *gvc = job->gvc;
01147 char *s;
01148
01149 if (ND_shape(n)
01150 && node_in_layer(job, n->graph, n)
01151 && node_in_box(n, job->clip)
01152 && (ND_state(n) != gvc->common.viewNum))
01153 {
01154 ND_state(n) = gvc->common.viewNum;
01155
01156 gvrender_comment(job, n->name);
01157 s = late_string(n, N_comment, "");
01158 if (s[0])
01159 gvrender_comment(job, s);
01160
01161 emit_begin_node(job, n);
01162 ND_shape(n)->fns->codefn(job, n);
01163 emit_end_node(job);
01164 }
01165 }
01166
01167
01168 static pointf computeoffset_p(pointf p, pointf q, double d)
01169 {
01170 pointf res;
01171 double x = p.x - q.x, y = p.y - q.y;
01172
01173
01174 d /= sqrt(x * x + y * y + EPSILON);
01175 res.x = y * d;
01176 res.y = -x * d;
01177 return res;
01178 }
01179
01180
01181 static pointf computeoffset_qr(pointf p, pointf q, pointf r, pointf s,
01182 double d)
01183 {
01184 pointf res;
01185 double len;
01186 double x = q.x - r.x, y = q.y - r.y;
01187
01188 len = sqrt(x * x + y * y);
01189 if (len < EPSILON) {
01190
01191
01192 x = p.x - s.x, y = p.y - s.y;
01193
01194 len = sqrt(x * x + y * y + EPSILON);
01195 }
01196 d /= len;
01197 res.x = y * d;
01198 res.y = -x * d;
01199 return res;
01200 }
01201
01202 static void emit_attachment(GVJ_t * job, textlabel_t * lp, splines * spl)
01203 {
01204 pointf sz, AF[3];
01205 point p;
01206 unsigned char *s;
01207
01208 for (s = (unsigned char *) (lp->text); *s; s++) {
01209 if (isspace(*s) == FALSE)
01210 break;
01211 }
01212 if (*s == 0)
01213 return;
01214
01215 sz = lp->dimen;
01216 AF[0] = pointfof((double)(lp->p.x) + sz.x / 2., (double)(lp->p.y) - sz.y / 2.);
01217 AF[1] = pointfof(AF[0].x - sz.x, AF[0].y);
01218 p = dotneato_closest(spl, lp->p);
01219 P2PF(p,AF[2]);
01220
01221 gvrender_set_style(job, job->gvc->defaultlinestyle);
01222
01223
01224
01225
01226 gvrender_set_pencolor(job, lp->fontcolor);
01227 gvrender_polyline(job, AF, 3);
01228 }
01229
01230
01231
01232 static char* default_pencolor(char *pencolor, char *deflt)
01233 {
01234 static char *buf;
01235 static int bufsz;
01236 char *p;
01237 int len, ncol;
01238
01239 ncol = 1;
01240 for (p = pencolor; *p; p++) {
01241 if (*p == ':')
01242 ncol++;
01243 }
01244 len = ncol * (strlen(deflt) + 1);
01245 if (bufsz < len) {
01246 bufsz = len + 10;
01247 buf = realloc(buf, bufsz);
01248 }
01249 strcpy(buf, deflt);
01250 while(--ncol) {
01251 strcat(buf, ":");
01252 strcat(buf, deflt);
01253 }
01254 return buf;
01255 }
01256
01257 static void emit_edge_graphics(GVJ_t * job, edge_t * e, char** styles)
01258 {
01259 int i, j, cnum, numc = 0;
01260 char *color, *pencolor, *fillcolor;
01261 char *headcolor, *tailcolor, *lastcolor;
01262 char *colors = NULL;
01263 bezier bz = { 0, 0, 0, 0 };
01264 bezierf bzf;
01265 splinesf offspl, tmpspl;
01266 pointf pf0, pf1, pf2 = { 0, 0 }, pf3, *offlist, *tmplist;
01267 double arrowsize, numc2;
01268 char* p;
01269
01270 #define SEP 2.0
01271
01272 setColorScheme (agget (e, "colorscheme"));
01273 if (ED_spl(e)) {
01274 arrowsize = late_double(e, E_arrowsz, 1.0, 0.0);
01275 color = late_string(e, E_color, "");
01276
01277
01278 for (p = color; *p; p++)
01279 if (*p == ':')
01280 numc++;
01281
01282 fillcolor = pencolor = color;
01283 if (ED_gui_state(e) & GUI_STATE_ACTIVE) {
01284 pencolor = late_nnstring(e, E_activepencolor,
01285 default_pencolor(pencolor, DEFAULT_ACTIVEPENCOLOR));
01286 fillcolor = late_nnstring(e, E_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
01287 }
01288 else if (ED_gui_state(e) & GUI_STATE_SELECTED) {
01289 pencolor = late_nnstring(e, E_selectedpencolor,
01290 default_pencolor(pencolor, DEFAULT_SELECTEDPENCOLOR));
01291 fillcolor = late_nnstring(e, E_selectedfillcolor, DEFAULT_SELECTEDFILLCOLOR);
01292 }
01293 else if (ED_gui_state(e) & GUI_STATE_DELETED) {
01294 pencolor = late_nnstring(e, E_deletedpencolor,
01295 default_pencolor(pencolor, DEFAULT_DELETEDPENCOLOR));
01296 fillcolor = late_nnstring(e, E_deletedfillcolor, DEFAULT_DELETEDFILLCOLOR);
01297 }
01298 else if (ED_gui_state(e) & GUI_STATE_VISITED) {
01299 pencolor = late_nnstring(e, E_visitedpencolor,
01300 default_pencolor(pencolor, DEFAULT_VISITEDPENCOLOR));
01301 fillcolor = late_nnstring(e, E_visitedfillcolor, DEFAULT_VISITEDFILLCOLOR);
01302 }
01303 if (pencolor != color)
01304 gvrender_set_pencolor(job, pencolor);
01305 if (fillcolor != color)
01306 gvrender_set_fillcolor(job, fillcolor);
01307 color = pencolor;
01308
01309 if (numc) {
01310
01311 tmpspl.size = offspl.size = ED_spl(e)->size;
01312 offspl.list = malloc(sizeof(bezier) * offspl.size);
01313 tmpspl.list = malloc(sizeof(bezier) * tmpspl.size);
01314 numc2 = (2 + numc) / 2.0;
01315 for (i = 0; i < offspl.size; i++) {
01316 bz = ED_spl(e)->list[i];
01317 tmpspl.list[i].size = offspl.list[i].size = bz.size;
01318 offlist = offspl.list[i].list =
01319 malloc(sizeof(pointf) * bz.size);
01320 tmplist = tmpspl.list[i].list =
01321 malloc(sizeof(pointf) * bz.size);
01322 P2PF(bz.list[0], pf3);
01323 for (j = 0; j < bz.size - 1; j += 3) {
01324 pf0 = pf3;
01325 P2PF(bz.list[j + 1], pf1);
01326
01327 if (j == 0)
01328 offlist[j] = computeoffset_p(pf0, pf1, SEP);
01329 else
01330 offlist[j] = computeoffset_p(pf2, pf1, SEP);
01331
01332 P2PF(bz.list[j + 2], pf2);
01333 P2PF(bz.list[j + 3], pf3);
01334 offlist[j + 1] = offlist[j + 2] =
01335 computeoffset_qr(pf0, pf1, pf2, pf3, SEP);
01336
01337 tmplist[j].x = pf0.x - numc2 * offlist[j].x;
01338 tmplist[j].y = pf0.y - numc2 * offlist[j].y;
01339 tmplist[j + 1].x = pf1.x - numc2 * offlist[j + 1].x;
01340 tmplist[j + 1].y = pf1.y - numc2 * offlist[j + 1].y;
01341 tmplist[j + 2].x = pf2.x - numc2 * offlist[j + 2].x;
01342 tmplist[j + 2].y = pf2.y - numc2 * offlist[j + 2].y;
01343 }
01344
01345 offlist[j] = computeoffset_p(pf2, pf3, SEP);
01346 tmplist[j].x = pf3.x - numc2 * offlist[j].x;
01347 tmplist[j].y = pf3.y - numc2 * offlist[j].y;
01348 }
01349 lastcolor = headcolor = tailcolor = color;
01350 colors = strdup(color);
01351 for (cnum = 0, color = strtok(colors, ":"); color;
01352 cnum++, color = strtok(0, ":")) {
01353 if (!color[0])
01354 color = DEFAULT_COLOR;
01355 if (color != lastcolor) {
01356 if (! (ED_gui_state(e) & (GUI_STATE_ACTIVE | GUI_STATE_SELECTED))) {
01357 gvrender_set_pencolor(job, color);
01358 gvrender_set_fillcolor(job, color);
01359 }
01360 lastcolor = color;
01361 }
01362 if (cnum == 0)
01363 headcolor = tailcolor = color;
01364 if (cnum == 1)
01365 tailcolor = color;
01366 for (i = 0; i < tmpspl.size; i++) {
01367 tmplist = tmpspl.list[i].list;
01368 offlist = offspl.list[i].list;
01369 for (j = 0; j < tmpspl.list[i].size; j++) {
01370 tmplist[j].x += offlist[j].x;
01371 tmplist[j].y += offlist[j].y;
01372 }
01373 gvrender_beziercurve(job, tmplist, tmpspl.list[i].size,
01374 FALSE, FALSE, FALSE);
01375 }
01376 }
01377 if (bz.sflag) {
01378 if (color != tailcolor) {
01379 color = tailcolor;
01380 if (! (ED_gui_state(e) & (GUI_STATE_ACTIVE | GUI_STATE_SELECTED))) {
01381 gvrender_set_pencolor(job, color);
01382 gvrender_set_fillcolor(job, color);
01383 }
01384 }
01385 arrow_gen(job, EMIT_TDRAW, bz.sp, bz.list[0],
01386 arrowsize, job->obj->penwidth, bz.sflag);
01387 }
01388 if (bz.eflag) {
01389 if (color != headcolor) {
01390 color = headcolor;
01391 if (! (ED_gui_state(e) & (GUI_STATE_ACTIVE | GUI_STATE_SELECTED))) {
01392 gvrender_set_pencolor(job, color);
01393 gvrender_set_fillcolor(job, color);
01394 }
01395 }
01396 arrow_gen(job, EMIT_HDRAW, bz.ep, bz.list[bz.size - 1],
01397 arrowsize, job->obj->penwidth, bz.eflag);
01398 }
01399 free(colors);
01400 for (i = 0; i < offspl.size; i++) {
01401 free(offspl.list[i].list);
01402 free(tmpspl.list[i].list);
01403 }
01404 free(offspl.list);
01405 free(tmpspl.list);
01406 } else {
01407 if (! (ED_gui_state(e) & (GUI_STATE_ACTIVE | GUI_STATE_SELECTED))) {
01408 if (color[0]) {
01409 gvrender_set_pencolor(job, color);
01410 gvrender_set_fillcolor(job, color);
01411 } else {
01412 gvrender_set_pencolor(job, DEFAULT_COLOR);
01413 gvrender_set_fillcolor(job, DEFAULT_COLOR);
01414 }
01415 }
01416 for (i = 0; i < ED_spl(e)->size; i++) {
01417 bz = ED_spl(e)->list[i];
01418
01419 bzf.size = bz.size;
01420 bzf.list = malloc(sizeof(pointf) * bzf.size);
01421 for (j = 0; j < bz.size; j++)
01422 P2PF(bz.list[j], bzf.list[j]);
01423 if (job->flags & GVRENDER_DOES_ARROWS) {
01424 gvrender_beziercurve(job, bzf.list, bz.size, bz.sflag,
01425 bz.eflag, FALSE);
01426 } else {
01427 gvrender_beziercurve(job, bzf.list, bz.size, FALSE,
01428 FALSE, FALSE);
01429 if (bz.sflag) {
01430 arrow_gen(job, EMIT_TDRAW, bz.sp, bz.list[0],
01431 arrowsize, job->obj->penwidth, bz.sflag);
01432 }
01433 if (bz.eflag) {
01434 arrow_gen(job, EMIT_HDRAW, bz.ep, bz.list[bz.size - 1],
01435 arrowsize, job->obj->penwidth, bz.eflag);
01436 }
01437
01438
01439
01440 if ((ED_spl(e)->size>1) && (bz.sflag||bz.eflag) && styles)
01441 gvrender_set_style(job, styles);
01442 }
01443 free(bzf.list);
01444 }
01445 }
01446 }
01447 }
01448
01449 static boolean edge_in_box(edge_t *e, boxf b)
01450 {
01451 splines *spl;
01452 textlabel_t *lp;
01453
01454 spl = ED_spl(e);
01455 if (spl && boxf_overlap(spl->bb, b))
01456 return TRUE;
01457
01458 lp = ED_label(e);
01459 if (lp && overlap_label(lp, b))
01460 return TRUE;
01461
01462 return FALSE;
01463 }
01464
01465 static void emit_begin_edge(GVJ_t * job, edge_t * e, char** styles)
01466 {
01467 obj_state_t *obj;
01468 int flags = job->flags;
01469 char *s;
01470 textlabel_t *lab = NULL, *tlab = NULL, *hlab = NULL;
01471 pointf *pbs = NULL;
01472 int i, nump, *pbs_n = NULL, pbs_poly_n = 0;
01473 char* dflt_url = NULL;
01474 char* dflt_target = NULL;
01475 double penwidth;
01476
01477 obj = push_obj_state(job);
01478 obj->type = EDGE_OBJTYPE;
01479 obj->u.e = e;
01480 obj->emit_state = EMIT_EDRAW;
01481
01482
01483
01484
01485 if (styles && ED_spl(e)) gvrender_set_style(job, styles);
01486
01487 if (E_penwidth && ((s=agxget(e,E_penwidth->index)) && s[0])) {
01488 penwidth = late_double(e, E_penwidth, 1.0, 0.0);
01489 gvrender_set_penwidth(job, penwidth);
01490 }
01491
01492 if (flags & GVRENDER_DOES_Z) {
01493 obj->tail_z= late_double(e->tail, N_z, 0.0, -1000.0);
01494 obj->head_z= late_double(e->head, N_z, 0.0, -MAXFLOAT);
01495 }
01496
01497 if (flags & GVRENDER_DOES_LABELS) {
01498 if ((lab = ED_label(e)))
01499 obj->label = lab->text;
01500 obj->taillabel = obj->headlabel = obj->label;
01501 if ((tlab = ED_tail_label(e)))
01502 obj->taillabel = tlab->text;
01503 if ((hlab = ED_head_label(e)))
01504 obj->headlabel = hlab->text;
01505 }
01506
01507 if (flags & GVRENDER_DOES_MAPS) {
01508 if (((s = agget(e, "href")) && s[0]) || ((s = agget(e, "URL")) && s[0]))
01509 dflt_url = strdup_and_subst_obj(s, (void*)e);
01510 if (((s = agget(e, "edgehref")) && s[0]) || ((s = agget(e, "edgeURL")) && s[0]))
01511 obj->url = strdup_and_subst_obj(s, (void*)e);
01512 else if (dflt_url)
01513 obj->url = strdup(dflt_url);
01514 if (((s = agget(e, "labelhref")) && s[0]) || ((s = agget(e, "labelURL")) && s[0]))
01515 obj->labelurl = strdup_and_subst_obj(s, (void*)e);
01516 else if (dflt_url)
01517 obj->labelurl = strdup(dflt_url);
01518 if (((s = agget(e, "tailhref")) && s[0]) || ((s = agget(e, "tailURL")) && s[0])) {
01519 obj->tailurl = strdup_and_subst_obj(s, (void*)e);
01520 obj->explicit_tailurl = TRUE;
01521 }
01522 else if (dflt_url)
01523 obj->tailurl = strdup(dflt_url);
01524 if (((s = agget(e, "headhref")) && s[0]) || ((s = agget(e, "headURL")) && s[0])) {
01525 obj->headurl = strdup_and_subst_obj(s, (void*)e);
01526 obj->explicit_headurl = TRUE;
01527 }
01528 else if (dflt_url)
01529 obj->headurl = strdup(dflt_url);
01530 }
01531
01532 if (flags & GVRENDER_DOES_TARGETS) {
01533 if ((s = agget(e, "target")) && s[0])
01534 dflt_target = strdup_and_subst_obj(s, (void*)e);
01535 if ((s = agget(e, "edgetarget")) && s[0]) {
01536 obj->explicit_edgetarget = TRUE;
01537 obj->target = strdup_and_subst_obj(s, (void*)e);
01538 }
01539 else if (dflt_target)
01540 obj->target = strdup(dflt_target);
01541 if ((s = agget(e, "labeltarget")) && s[0])
01542 obj->labeltarget = strdup_and_subst_obj(s, (void*)e);
01543 else if (dflt_target)
01544 obj->labeltarget = strdup(dflt_target);
01545 if ((s = agget(e, "tailtarget")) && s[0]) {
01546 obj->tailtarget = strdup_and_subst_obj(s, (void*)e);
01547 obj->explicit_tailtarget = TRUE;
01548 }
01549 else if (dflt_target)
01550 obj->tailtarget = strdup(dflt_target);
01551 if ((s = agget(e, "headtarget")) && s[0]) {
01552 obj->explicit_headtarget = TRUE;
01553 obj->headtarget = strdup_and_subst_obj(s, (void*)e);
01554 }
01555 else if (dflt_target)
01556 obj->headtarget = strdup(dflt_target);
01557 }
01558
01559 if (flags & GVRENDER_DOES_TOOLTIPS) {
01560 if (((s = agget(e, "tooltip")) && s[0]) ||
01561 ((s = agget(e, "edgetooltip")) && s[0])) {
01562 obj->tooltip = strdup_and_subst_obj(s, (void*)e);
01563 obj->explicit_tooltip = TRUE;
01564 }
01565 else if (obj->label)
01566 obj->tooltip = strdup(obj->label);
01567
01568 if ((s = agget(e, "labeltooltip")) && s[0]) {
01569 obj->labeltooltip = strdup_and_subst_obj(s, (void*)e);
01570 obj->explicit_labeltooltip = TRUE;
01571 }
01572 else if (obj->label)
01573 obj->labeltooltip = strdup(obj->label);
01574
01575 if ((s = agget(e, "tailtooltip")) && s[0]) {
01576 obj->tailtooltip = strdup_and_subst_obj(s, (void*)e);
01577 obj->explicit_tailtooltip = TRUE;
01578 }
01579 else if (obj->taillabel)
01580 obj->tailtooltip = strdup(obj->taillabel);
01581
01582 if ((s = agget(e, "headtooltip")) && s[0]) {
01583 obj->headtooltip = strdup_and_subst_obj(s, (void*)e);
01584 obj->explicit_headtooltip = TRUE;
01585 }
01586 else if (obj->headlabel)
01587 obj->headtooltip = strdup(obj->headlabel);
01588 }
01589
01590 free (dflt_url);
01591 free (dflt_target);
01592
01593 if (flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS)) {
01594 if (ED_spl(e) && (obj->url || obj->tooltip) && (flags & GVRENDER_DOES_MAP_POLYGON)) {
01595 int ns;
01596 splines *spl;
01597 double w2 = MAX(job->obj->penwidth/2.0,2.0);
01598
01599 spl = ED_spl(e);
01600 ns = spl->size;
01601 for (i = 0; i < ns; i++)
01602 map_output_bspline (&pbs, &pbs_n, &pbs_poly_n, spl->list+i, w2);
01603 obj->url_bsplinemap_poly_n = pbs_poly_n;
01604 obj->url_bsplinemap_n = pbs_n;
01605 if (! (flags & GVRENDER_DOES_TRANSFORM)) {
01606 for ( nump = 0, i = 0; i < pbs_poly_n; i++)
01607 nump += pbs_n[i];
01608 gvrender_ptf_A(job, pbs, pbs, nump);
01609 }
01610 obj->url_bsplinemap_p = pbs;
01611 obj->url_map_shape = MAP_POLYGON;
01612 obj->url_map_p = pbs;
01613 obj->url_map_n = pbs_n[0];
01614 }
01615 }
01616
01617 #ifdef WITH_CODEGENS
01618 Obj = EDGE;
01619 #endif
01620 gvrender_begin_context(job);
01621 gvrender_begin_edge(job, e);
01622 if (obj->url || obj->explicit_tooltip)
01623 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
01624 }
01625
01626 static void
01627 emit_edge_label(GVJ_t* job, textlabel_t* lbl, int lkind, int explicit,
01628 char* url, char* tooltip, char* target, splines* spl)
01629 {
01630 int flags = job->flags;
01631 if (lbl == NULL) return;
01632 if ((url || explicit) && !(flags & EMIT_CLUSTERS_LAST)) {
01633 map_label(job, lbl);
01634 gvrender_begin_anchor(job, url, tooltip, target);
01635 }
01636 emit_label(job, lkind, lbl);
01637 if (spl) emit_attachment(job, lbl, spl);
01638 if (url || explicit) {
01639 if (flags & EMIT_CLUSTERS_LAST) {
01640 map_label(job, lbl);
01641 gvrender_begin_anchor(job, url, tooltip, target);
01642 }
01643 gvrender_end_anchor(job);
01644 }
01645 }
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659 static void
01660 nodeIntersect (GVJ_t * job, point p,
01661 boolean explicit_iurl, char* iurl,
01662 boolean explicit_itooltip, char* itooltip,
01663 boolean explicit_itarget, char* itarget)
01664 {
01665 obj_state_t *obj = job->obj;
01666 char* url;
01667 char* tooltip;
01668 char* target;
01669 boolean explicit;
01670
01671 if (explicit_iurl) url = iurl;
01672 else url = obj->url;
01673 if (explicit_itooltip) {
01674 tooltip = itooltip;
01675 explicit = TRUE;
01676 }
01677 else if (obj->explicit_tooltip) {
01678 tooltip = obj->tooltip;
01679 explicit = TRUE;
01680 }
01681 else {
01682 explicit = FALSE;
01683 tooltip = itooltip;
01684 }
01685 if (explicit_itarget)
01686 target = itarget;
01687 else if (obj->explicit_edgetarget)
01688 target = obj->target;
01689 else
01690 target = itarget;
01691
01692 if (url || explicit) {
01693 map_point(job, p);
01694 gvrender_begin_anchor(job, url, tooltip, target);
01695 gvrender_end_anchor(job);
01696 }
01697 }
01698
01699 static void emit_end_edge(GVJ_t * job)
01700 {
01701 obj_state_t *obj = job->obj;
01702 edge_t *e = obj->u.e;
01703 int i, nump;
01704
01705 if (obj->url || obj->explicit_tooltip) {
01706 gvrender_end_anchor(job);
01707 if (obj->url_bsplinemap_poly_n) {
01708 for ( nump = obj->url_bsplinemap_n[0], i = 1; i < obj->url_bsplinemap_poly_n; i++) {
01709
01710 obj->url_map_n = obj->url_bsplinemap_n[i];
01711 obj->url_map_p = &(obj->url_bsplinemap_p[nump]);
01712 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
01713 gvrender_end_anchor(job);
01714 nump += obj->url_bsplinemap_n[i];
01715 }
01716 }
01717 }
01718 obj->url_map_n = 0;
01719 obj->url_map_p = NULL;
01720
01721 if (ED_spl(e)) {
01722 point p;
01723 bezier bz;
01724
01725
01726 bz = ED_spl(e)->list[0];
01727 if (bz.sflag)
01728 p = bz.sp;
01729 else
01730 p = bz.list[0];
01731 nodeIntersect (job, p, obj->explicit_tailurl, obj->tailurl,
01732 obj->explicit_tailtooltip, obj->tailtooltip,
01733 obj->explicit_tailtarget, obj->tailtarget);
01734
01735
01736 bz = ED_spl(e)->list[ED_spl(e)->size - 1];
01737 if (bz.eflag)
01738 p = bz.ep;
01739 else
01740 p = bz.list[bz.size - 1];
01741 nodeIntersect (job, p, obj->explicit_headurl, obj->headurl,
01742 obj->explicit_headtooltip, obj->headtooltip,
01743 obj->explicit_headtarget, obj->headtarget);
01744 }
01745
01746 emit_edge_label(job, ED_label(e), EMIT_ELABEL, obj->explicit_labeltooltip,
01747 obj->labelurl, obj->labeltooltip, obj->labeltarget,
01748 ((mapbool(late_string(e, E_decorate, "false")) && ED_spl(e)) ? ED_spl(e) : 0));
01749 emit_edge_label(job, ED_head_label(e), EMIT_HLABEL,
01750 obj->explicit_headtooltip, obj->headurl, obj->headtooltip, obj->headtarget, 0);
01751 emit_edge_label(job, ED_tail_label(e), EMIT_TLABEL,
01752 obj->explicit_tailtooltip, obj->tailurl, obj->tailtooltip, obj->tailtarget, 0);
01753
01754 gvrender_end_edge(job);
01755 gvrender_end_context(job);
01756 #ifdef WITH_CODEGENS
01757 Obj = NONE;
01758 #endif
01759 pop_obj_state(job);
01760 }
01761
01762 static void emit_edge(GVJ_t * job, edge_t * e)
01763 {
01764 char *s;
01765 char *style;
01766 char **styles = 0;
01767 char **sp;
01768 char *p;
01769
01770 if (edge_in_box(e, job->clip) && edge_in_layer(job, e->head->graph, e) ) {
01771
01772 s = malloc(strlen(e->tail->name) + 2 + strlen(e->head->name) + 1);
01773 strcpy(s,e->tail->name);
01774 if (AG_IS_DIRECTED(e->tail->graph))
01775 strcat(s,"->");
01776 else
01777 strcat(s,"--");
01778 strcat(s,e->head->name);
01779 gvrender_comment(job, s);
01780 free(s);
01781
01782 s = late_string(e, E_comment, "");
01783 if (s[0])
01784 gvrender_comment(job, s);
01785
01786 style = late_string(e, E_style, "");
01787
01788
01789
01790
01791 if (style[0]) {
01792 styles = parse_style(style);
01793 sp = styles;
01794 while ((p = *sp++)) {
01795 if (streq(p, "invis")) return;
01796 }
01797 }
01798
01799 emit_begin_edge(job, e, styles);
01800 emit_edge_graphics (job, e, styles);
01801 emit_end_edge(job);
01802 }
01803 }
01804
01805 static void init_gvc(GVC_t * gvc, graph_t * g)
01806 {
01807 double xf, yf;
01808 char *p;
01809 int i;
01810
01811 gvc->g = g;
01812
01813
01814 gvc->graph_sets_margin = FALSE;
01815 if ((p = agget(g, "margin"))) {
01816 i = sscanf(p, "%lf,%lf", &xf, &yf);
01817 if (i > 0) {
01818 gvc->margin.x = gvc->margin.y = xf * POINTS_PER_INCH;
01819 if (i > 1)
01820 gvc->margin.y = yf * POINTS_PER_INCH;
01821 gvc->graph_sets_margin = TRUE;
01822 }
01823 }
01824
01825
01826 gvc->graph_sets_pad = FALSE;
01827 if ((p = agget(g, "pad"))) {
01828 i = sscanf(p, "%lf,%lf", &xf, &yf);
01829 if (i > 0) {
01830 gvc->pad.x = gvc->pad.y = xf * POINTS_PER_INCH;
01831 if (i > 1)
01832 gvc->pad.y = yf * POINTS_PER_INCH;
01833 gvc->graph_sets_pad = TRUE;
01834 }
01835 }
01836
01837
01838 gvc->graph_sets_pageSize = FALSE;
01839 P2PF(GD_drawing(g)->page, gvc->pageSize);
01840 if ((GD_drawing(g)->page.x > 0) && (GD_drawing(g)->page.y > 0))
01841 gvc->graph_sets_pageSize = TRUE;
01842
01843
01844 if (GD_drawing(g)->landscape)
01845 gvc->rotation = 90;
01846 else
01847 gvc->rotation = 0;
01848
01849
01850 gvc->pagedir = "BL";
01851 if ((p = agget(g, "pagedir")) && p[0])
01852 gvc->pagedir = p;
01853
01854
01855 B2BF(GD_bb(g),gvc->bb);
01856
01857
01858 G_peripheries = agfindattr(g, "peripheries");
01859
01860 G_penwidth = agfindattr(g, "penwidth");
01861
01862
01863 gvc->defaultfontname = late_nnstring(g->proto->n,
01864 N_fontname, DEFAULT_FONTNAME);
01865 gvc->defaultfontsize = late_double(g->proto->n,
01866 N_fontsize, DEFAULT_FONTSIZE, MIN_FONTSIZE);
01867
01868
01869 gvc->defaultlinestyle = defaultlinestyle;
01870
01871 gvc->graphname = g->name;
01872 }
01873
01874 static void init_job_pad(GVJ_t *job)
01875 {
01876 GVC_t *gvc = job->gvc;
01877
01878 if (gvc->graph_sets_pad) {
01879 job->pad = gvc->pad;
01880 }
01881 else {
01882 switch (job->output_lang) {
01883 case GVRENDER_PLUGIN:
01884 job->pad.x = job->pad.y = job->render.features->default_pad;
01885 break;
01886 default:
01887 job->pad.x = job->pad.y = DEFAULT_GRAPH_PAD;
01888 break;
01889 }
01890 }
01891 }
01892
01893 static void init_job_margin(GVJ_t *job)
01894 {
01895 GVC_t *gvc = job->gvc;
01896
01897 if (gvc->graph_sets_margin) {
01898 job->margin = gvc->margin;
01899 }
01900 else {
01901
01902 switch (job->output_lang) {
01903 case GVRENDER_PLUGIN:
01904 job->margin = job->device.features->default_margin;
01905 break;
01906 case HPGL: case PCL: case MIF: case METAPOST: case VTX: case QPDF:
01907 job->margin.x = job->margin.y = DEFAULT_PRINT_MARGIN;
01908 break;
01909 default:
01910 job->margin.x = job->margin.y = DEFAULT_EMBED_MARGIN;
01911 break;
01912 }
01913 }
01914
01915 }
01916
01917 static void init_job_dpi(GVJ_t *job, graph_t *g)
01918 {
01919 GVJ_t *firstjob = job->gvc->active_jobs;
01920
01921 if (GD_drawing(g)->dpi != 0) {
01922 job->dpi.x = job->dpi.y = (double)(GD_drawing(g)->dpi);
01923 }
01924 else if (firstjob && firstjob->device_sets_dpi) {
01925 job->dpi = firstjob->device_dpi;
01926 }
01927 else {
01928
01929 switch (job->output_lang) {
01930 case GVRENDER_PLUGIN:
01931 job->dpi = job->device.features->default_dpi;
01932 break;
01933 default:
01934 job->dpi.x = job->dpi.y = (double)(DEFAULT_DPI);
01935 break;
01936 }
01937 }
01938 }
01939
01940 static void init_job_viewport(GVJ_t * job, graph_t * g)
01941 {
01942 GVC_t *gvc = job->gvc;
01943 pointf UR, size, sz;
01944 char *str;
01945 double X, Y, Z, x, y;
01946 int rv;
01947 Agnode_t *n;
01948 char *nodename = NULL;
01949
01950 assert((gvc->bb.LL.x == 0) && (gvc->bb.LL.y == 0));
01951 P2PF(gvc->bb.UR, UR);
01952
01953 job->bb.LL.x = -job->pad.x;
01954 job->bb.LL.y = -job->pad.y;
01955 job->bb.UR.x = UR.x + job->pad.x;
01956 job->bb.UR.y = UR.y + job->pad.y;
01957 sz.x = job->bb.UR.x - job->bb.LL.x;
01958 sz.y = job->bb.UR.y - job->bb.LL.y;
01959
01960
01961
01962
01963
01964 Z = 1.0;
01965 if (GD_drawing(g)->size.x > 0) {
01966 P2PF(GD_drawing(g)->size, size);
01967 if ((size.x < sz.x) || (size.y < sz.y)
01968 || ((GD_drawing(g)->filled)
01969 && (size.x > sz.x) && (size.y > sz.y)))
01970 Z = MIN(size.x/sz.x, size.y/sz.y);
01971 }
01972
01973
01974 x = UR.x / 2.;
01975 y = UR.y / 2.;
01976
01977
01978 job->rotation = job->gvc->rotation;
01979 X = sz.x * Z;
01980 Y = sz.y * Z;
01981
01982
01983 if ((str = agget(g, "viewport"))) {
01984 nodename = malloc(strlen(str)+1);
01985 rv = sscanf(str, "%lf,%lf,%lf,\'%[^\']\'", &X, &Y, &Z, nodename);
01986 if (rv == 4) {
01987 n = agfindnode(g->root, nodename);
01988 if (n) {
01989 x = ND_coord_i(n).x;
01990 y = ND_coord_i(n).y;
01991 }
01992 }
01993 else {
01994 rv = sscanf(str, "%lf,%lf,%lf,%lf,%lf", &X, &Y, &Z, &x, &y);
01995 }
01996 free (nodename);
01997 }
01998
01999
02000
02001
02002
02003
02004 job->view.x = X;
02005 job->view.y = Y;
02006 job->zoom = Z;
02007 job->focus.x = x;
02008 job->focus.y = y;
02009 #if 0
02010 fprintf(stderr, "view=%g,%g, zoom=%g, focus=%g,%g\n",
02011 job->view.x, job->view.y,
02012 job->zoom,
02013 job->focus.x, job->focus.y);
02014 #endif
02015 }
02016
02017 static void emit_colors(GVJ_t * job, graph_t * g)
02018 {
02019 graph_t *sg;
02020 node_t *n;
02021 edge_t *e;
02022 int c;
02023 char *str, *colors;
02024
02025 gvrender_set_fillcolor(job, DEFAULT_FILL);
02026 if (((str = agget(g, "bgcolor")) != 0) && str[0])
02027 gvrender_set_fillcolor(job, str);
02028 if (((str = agget(g, "fontcolor")) != 0) && str[0])
02029 gvrender_set_pencolor(job, str);
02030 for (c = 1; c <= GD_n_cluster(g); c++) {
02031 sg = GD_clust(g)[c];
02032 if (((str = agget(sg, "color")) != 0) && str[0])
02033 gvrender_set_pencolor(job, str);
02034 if (((str = agget(sg, "fillcolor")) != 0) && str[0])
02035 gvrender_set_fillcolor(job, str);
02036 if (((str = agget(sg, "fontcolor")) != 0) && str[0])
02037 gvrender_set_pencolor(job, str);
02038 }
02039 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
02040 if (((str = agget(n, "color")) != 0) && str[0])
02041 gvrender_set_pencolor(job, str);
02042 if (((str = agget(n, "fillcolor")) != 0) && str[0])
02043 gvrender_set_fillcolor(job, str);
02044 if (((str = agget(n, "fontcolor")) != 0) && str[0])
02045 gvrender_set_pencolor(job, str);
02046 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
02047 if (((str = agget(e, "color")) != 0) && str[0]) {
02048 if (strchr(str, ':')) {
02049 colors = strdup(str);
02050 for (str = strtok(colors, ":"); str;
02051 str = strtok(0, ":")) {
02052 if (str[0])
02053 gvrender_set_pencolor(job, str);
02054 }
02055 free(colors);
02056 } else
02057 gvrender_set_pencolor(job, str);
02058 }
02059 if (((str = agget(e, "fontcolor")) != 0) && str[0])
02060 gvrender_set_pencolor(job, str);
02061 }
02062 }
02063 }
02064
02065 static void emit_view(GVJ_t * job, graph_t * g, int flags)
02066 {
02067 GVC_t * gvc = job->gvc;
02068 node_t *n;
02069 edge_t *e;
02070
02071 gvc->common.viewNum++;
02072
02073 if (!(flags & EMIT_CLUSTERS_LAST))
02074 emit_clusters(job, g, flags);
02075 if (flags & EMIT_SORTED) {
02076
02077 gvrender_begin_nodes(job);
02078 for (n = agfstnode(g); n; n = agnxtnode(g, n))
02079 emit_node(job, n);
02080 gvrender_end_nodes(job);
02081 gvrender_begin_edges(job);
02082 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
02083 for (e = agfstout(g, n); e; e = agnxtout(g, e))
02084 emit_edge(job, e);
02085 }
02086 gvrender_end_edges(job);
02087 } else if (flags & EMIT_EDGE_SORTED) {
02088
02089 gvrender_begin_edges(job);
02090 for (n = agfstnode(g); n; n = agnxtnode(g, n))
02091 for (e = agfstout(g, n); e; e = agnxtout(g, e))
02092 emit_edge(job, e);
02093 gvrender_end_edges(job);
02094 gvrender_begin_nodes(job);
02095 for (n = agfstnode(g); n; n = agnxtnode(g, n))
02096 emit_node(job, n);
02097 gvrender_end_nodes(job);
02098 } else if (flags & EMIT_PREORDER) {
02099 gvrender_begin_nodes(job);
02100 for (n = agfstnode(g); n; n = agnxtnode(g, n))
02101 if (write_node_test(g, n))
02102 emit_node(job, n);
02103 gvrender_end_nodes(job);
02104 gvrender_begin_edges(job);
02105
02106 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
02107 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
02108 if (write_edge_test(g, e))
02109 emit_edge(job, e);
02110 }
02111 }
02112 gvrender_end_edges(job);
02113 } else {
02114
02115 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
02116 emit_node(job, n);
02117 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
02118 emit_node(job, e->head);
02119 emit_edge(job, e);
02120 }
02121 }
02122 }
02123
02124 if (flags & EMIT_CLUSTERS_LAST)
02125 emit_clusters(job, g, flags);
02126 }
02127
02128 static void emit_begin_graph(GVJ_t * job, graph_t * g)
02129 {
02130 obj_state_t *obj;
02131
02132 obj = push_obj_state(job);
02133 obj->type = ROOTGRAPH_OBJTYPE;
02134 obj->u.g = g;
02135 obj->emit_state = EMIT_GDRAW;
02136
02137 initObjMapData (job, GD_label(g), g);
02138
02139 #ifdef WITH_CODEGENS
02140 Obj = NONE;
02141 #endif
02142 gvrender_begin_graph(job, g);
02143 }
02144
02145 static void emit_end_graph(GVJ_t * job, graph_t * g)
02146 {
02147 gvrender_end_graph(job);
02148 #ifdef WITH_CODEGENS
02149 Obj = NONE;
02150 #endif
02151 pop_obj_state(job);
02152 }
02153
02154 static void emit_page(GVJ_t * job, graph_t * g)
02155 {
02156 GVC_t *gvc = job->gvc;
02157 obj_state_t *obj = job->obj;
02158 int nump = 0, flags = job->flags;
02159 textlabel_t *lab;
02160 point p1, p2;
02161 pointf *p = NULL;
02162
02163 setColorScheme (agget (g, "colorscheme"));
02164 setup_page(job, g);
02165 gvrender_begin_page(job);
02166 gvrender_set_pencolor(job, DEFAULT_COLOR);
02167 gvrender_set_fillcolor(job, DEFAULT_FILL);
02168 gvrender_set_font(job, gvc->defaultfontname, gvc->defaultfontsize);
02169 if ((flags & (GVRENDER_DOES_MAPS | GVRENDER_DOES_TOOLTIPS))
02170 && (obj->url || obj->explicit_tooltip)) {
02171 if (flags & (GVRENDER_DOES_MAP_RECTANGLE | GVRENDER_DOES_MAP_POLYGON)) {
02172 if (flags & GVRENDER_DOES_MAP_RECTANGLE) {
02173 obj->url_map_shape = MAP_RECTANGLE;
02174 nump = 2;
02175 }
02176 else {
02177 obj->url_map_shape = MAP_POLYGON;
02178 nump = 4;
02179 }
02180 p = N_NEW(nump, pointf);
02181 p[0] = job->pageBox.LL;
02182 p[1] = job->pageBox.UR;
02183 if (! (flags & (GVRENDER_DOES_MAP_RECTANGLE)))
02184 rect2poly(p);
02185 }
02186 if (! (flags & GVRENDER_DOES_TRANSFORM))
02187 gvrender_ptf_A(job, p, p, nump);
02188 obj->url_map_p = p;
02189 obj->url_map_n = nump;
02190 }
02191 if ((flags & GVRENDER_DOES_LABELS) && ((lab = GD_label(g))))
02192
02193 obj->label = lab->text;
02194
02195
02196
02197
02198 if (!(flags & EMIT_CLUSTERS_LAST) && (obj->url || obj->explicit_tooltip)) {
02199 PF2P(job->clip.LL, p1);
02200 PF2P(job->clip.UR, p2);
02201 emit_map_rect(job, p1, p2);
02202 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
02203 }
02204 if (job->numLayers == 1)
02205 emit_background(job, g);
02206 if (GD_label(g))
02207 emit_label(job, EMIT_GLABEL, GD_label(g));
02208 if (!(flags & EMIT_CLUSTERS_LAST) && (obj->url || obj->explicit_tooltip))
02209 gvrender_end_anchor(job);
02210 emit_view(job,g,flags);
02211 gvrender_end_page(job);
02212 }
02213
02214 void emit_graph(GVJ_t * job, graph_t * g)
02215 {
02216 node_t *n;
02217 char *s;
02218 int flags = job->flags;
02219
02220
02221 job->scale.x = job->zoom * job->dpi.x / POINTS_PER_INCH;
02222 job->scale.y = job->zoom * job->dpi.y / POINTS_PER_INCH;
02223
02224 job->devscale.x = job->dpi.x / POINTS_PER_INCH;
02225 job->devscale.y = job->dpi.y / POINTS_PER_INCH;
02226 if ((job->flags & GVRENDER_Y_GOES_DOWN) || (Y_invert))
02227 job->devscale.y *= -1;
02228
02229
02230 if (job->rotation) {
02231 job->view.y = job->width / job->scale.x;
02232 job->view.x = job->height / job->scale.y;
02233 }
02234 else {
02235 job->view.x = job->width / job->scale.x;
02236 job->view.y = job->height / job->scale.y;
02237 }
02238
02239 s = late_string(g, agfindattr(g, "comment"), "");
02240 gvrender_comment(job, s);
02241
02242 emit_begin_graph(job, g);
02243
02244 if (flags & EMIT_COLORS)
02245 emit_colors(job,g);
02246
02247
02248 for (n = agfstnode(g); n; n = agnxtnode(g, n))
02249 ND_state(n) = 0;
02250
02251 for (firstlayer(job); validlayer(job); nextlayer(job)) {
02252 if (job->numLayers > 1)
02253 gvrender_begin_layer(job);
02254
02255
02256 for (firstpage(job); validpage(job); nextpage(job))
02257 emit_page(job, g);
02258
02259 if (job->numLayers > 1)
02260 gvrender_end_layer(job);
02261 }
02262 emit_end_graph(job, g);
02263 }
02264
02265
02266 static void free_string_entry(Dict_t * dict, char *key, Dtdisc_t * disc)
02267 {
02268 agstrfree(key);
02269 }
02270
02271 static Dict_t *strings;
02272 static Dtdisc_t stringdict = {
02273 0,
02274 0,
02275 -1,
02276 NIL(Dtmake_f),
02277 (Dtfree_f) free_string_entry,
02278 NIL(Dtcompar_f),
02279 NIL(Dthash_f),
02280 NIL(Dtmemory_f),
02281 NIL(Dtevent_f)
02282 };
02283
02284 int emit_once(char *str)
02285 {
02286 if (strings == 0)
02287 strings = dtopen(&stringdict, Dtoset);
02288 if (!dtsearch(strings, str)) {
02289 dtinsert(strings, agstrdup(str));
02290 return TRUE;
02291 }
02292 return FALSE;
02293 }
02294
02295 void emit_once_reset(void)
02296 {
02297 if (strings) {
02298 dtclose(strings);
02299 strings = 0;
02300 }
02301 }
02302
02303 static char **checkClusterStyle(graph_t* sg, int *flagp)
02304 {
02305 char *style;
02306 char **pstyle = 0;
02307 int istyle = 0;
02308
02309 if (((style = agget(sg, "style")) != 0) && style[0]) {
02310 char **pp;
02311 char **qp;
02312 char *p;
02313 pp = pstyle = parse_style(style);
02314 while ((p = *pp)) {
02315 if (strcmp(p, "filled") == 0) {
02316 istyle |= FILLED;
02317 pp++;
02318 } else if (strcmp(p, "rounded") == 0) {
02319 istyle |= ROUNDED;
02320 qp = pp;
02321 do {
02322 qp++;
02323 *(qp-1) = *qp;
02324 } while (*qp);
02325 } else pp++;
02326 }
02327 }
02328
02329 *flagp = istyle;
02330 return pstyle;
02331 }
02332
02333 static void emit_begin_cluster(GVJ_t * job, Agraph_t * sg)
02334 {
02335 obj_state_t *obj;
02336
02337 obj = push_obj_state(job);
02338 obj->type = CLUSTER_OBJTYPE;
02339 obj->u.sg = sg;
02340 obj->emit_state = EMIT_CDRAW;
02341
02342 initObjMapData (job, GD_label(sg), sg);
02343
02344 #ifdef WITH_CODEGENS
02345 Obj = CLST;
02346 #endif
02347 gvrender_begin_cluster(job, sg);
02348 }
02349
02350 static void emit_end_cluster(GVJ_t * job, Agraph_t * g)
02351 {
02352 gvrender_end_cluster(job, g);
02353 #ifdef WITH_CODEGENS
02354 Obj = NONE;
02355 #endif
02356 pop_obj_state(job);
02357 }
02358
02359 void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
02360 {
02361 int c, istyle, filled;
02362 boxf BF;
02363 pointf AF[4];
02364 char *color, *fillcolor, *pencolor, **style, *s;
02365 graph_t *sg;
02366 node_t *n;
02367 edge_t *e;
02368 obj_state_t *obj;
02369 textlabel_t *lab;
02370 int doAnchor;
02371 double penwidth;
02372
02373 for (c = 1; c <= GD_n_cluster(g); c++) {
02374 sg = GD_clust(g)[c];
02375 if (clust_in_layer(job, sg) == FALSE)
02376 continue;
02377
02378 if (flags & EMIT_CLUSTERS_LAST)
02379 emit_clusters(job, sg, flags);
02380 emit_begin_cluster(job, sg);
02381 obj = job->obj;
02382 doAnchor = (obj->url || obj->explicit_tooltip);
02383 setColorScheme (agget (sg, "colorscheme"));
02384 gvrender_begin_context(job);
02385 if (doAnchor && !(flags & EMIT_CLUSTERS_LAST)) {
02386 emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR);
02387 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
02388 }
02389 filled = FALSE;
02390 istyle = 0;
02391 if ((style = checkClusterStyle(sg, &istyle))) {
02392 gvrender_set_style(job, style);
02393 if (istyle & FILLED)
02394 filled = TRUE;
02395 }
02396 fillcolor = pencolor = 0;
02397 if (GD_gui_state(sg) & GUI_STATE_ACTIVE) {
02398 pencolor = late_nnstring(sg, G_activepencolor, DEFAULT_ACTIVEPENCOLOR);
02399 fillcolor = late_nnstring(sg, G_activefillcolor, DEFAULT_ACTIVEFILLCOLOR);
02400 filled = TRUE;
02401 }
02402 else if (GD_gui_state(sg) & GUI_STATE_SELECTED) {
02403 pencolor = late_nnstring(sg, G_activepencolor, DEFAULT_SELECTEDPENCOLOR);
02404 fillcolor = late_nnstring(sg, G_activefillcolor, DEFAULT_SELECTEDFILLCOLOR);
02405 filled = TRUE;
02406 }
02407 else if (GD_gui_state(sg) & GUI_STATE_DELETED) {
02408 pencolor = late_nnstring(sg, G_deletedpencolor, DEFAULT_DELETEDPENCOLOR);
02409 fillcolor = late_nnstring(sg, G_deletedfillcolor, DEFAULT_DELETEDFILLCOLOR);
02410 filled = TRUE;
02411 }
02412 else if (GD_gui_state(sg) & GUI_STATE_VISITED) {
02413 pencolor = late_nnstring(sg, G_visitedpencolor, DEFAULT_VISITEDPENCOLOR);
02414 fillcolor = late_nnstring(sg, G_visitedfillcolor, DEFAULT_VISITEDFILLCOLOR);
02415 filled = TRUE;
02416 }
02417 else {
02418 if (((color = agget(sg, "pencolor")) != 0) && color[0])
02419 pencolor = color;
02420 else if (((color = agget(sg, "color")) != 0) && color[0])
02421 fillcolor = pencolor = color;
02422
02423 else if (((color = agget(sg, "bgcolor")) != 0) && color[0]) {
02424 fillcolor = color;
02425 filled = TRUE;
02426 }
02427 if (((color = agget(sg, "fillcolor")) != 0) && color[0])
02428 fillcolor = color;
02429 }
02430 if (!pencolor) pencolor = DEFAULT_COLOR;
02431 if (!fillcolor) fillcolor = DEFAULT_FILL;
02432
02433 if (G_penwidth && ((s=agxget(sg, G_penwidth->index)) && s[0])) {
02434 penwidth = late_double(sg, G_penwidth, 1.0, 0.0);
02435 gvrender_set_penwidth(job, penwidth);
02436 }
02437
02438 B2BF(GD_bb(sg), BF);
02439 if (istyle & ROUNDED) {
02440 if (late_int(sg, G_peripheries, 1, 0) || filled) {
02441 AF[0] = BF.LL;
02442 AF[2] = BF.UR;
02443 AF[1].x = AF[2].x;
02444 AF[1].y = AF[0].y;
02445 AF[3].x = AF[0].x;
02446 AF[3].y = AF[2].y;
02447 round_corners(job, fillcolor, pencolor, AF, 4, istyle);
02448 }
02449 }
02450 else {
02451 gvrender_set_pencolor(job, pencolor);
02452 gvrender_set_fillcolor(job, fillcolor);
02453 if (late_int(sg, G_peripheries, 1, 0))
02454 gvrender_box(job, BF, filled);
02455 else if (filled) {
02456 if (fillcolor && fillcolor != pencolor)
02457 gvrender_set_pencolor(job, fillcolor);
02458 gvrender_box(job, BF, filled);
02459 }
02460 }
02461 if ((lab = GD_label(sg)))
02462 emit_label(job, EMIT_CLABEL, lab);
02463
02464 if (doAnchor) {
02465 if (flags & EMIT_CLUSTERS_LAST) {
02466 emit_map_rect(job, GD_bb(sg).LL, GD_bb(sg).UR);
02467 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
02468 }
02469 gvrender_end_anchor(job);
02470 }
02471
02472 if (flags & EMIT_PREORDER) {
02473 for (n = agfstnode(sg); n; n = agnxtnode(sg, n)) {
02474 emit_node(job, n);
02475 for (e = agfstout(sg, n); e; e = agnxtout(sg, e))
02476 emit_edge(job, e);
02477 }
02478 }
02479 gvrender_end_context(job);
02480 emit_end_cluster(job, g);
02481
02482 if (!(flags & EMIT_CLUSTERS_LAST))
02483 emit_clusters(job, sg, flags);
02484 }
02485 }
02486
02487 static boolean is_style_delim(int c)
02488 {
02489 switch (c) {
02490 case '(':
02491 case ')':
02492 case ',':
02493 case '\0':
02494 return TRUE;
02495 default:
02496 return FALSE;
02497 }
02498 }
02499
02500 #define SID 1
02501
02502 static int style_token(char **s, agxbuf * xb)
02503 {
02504 char *p = *s;
02505 int token, rc;
02506 char c;
02507
02508 while (*p && (isspace(*p) || (*p == ',')))
02509 p++;
02510 switch (*p) {
02511 case '\0':
02512 token = 0;
02513 break;
02514 case '(':
02515 case ')':
02516 token = *p++;
02517 break;
02518 default:
02519 token = SID;
02520 while (!is_style_delim(c = *p)) {
02521 rc = agxbputc(xb, c);
02522 p++;
02523 }
02524 }
02525 *s = p;
02526 return token;
02527 }
02528
02529 #define FUNLIMIT 64
02530 static unsigned char outbuf[SMALLBUF];
02531 static agxbuf ps_xb;
02532
02533 static void cleanup(void)
02534 {
02535 agxbfree(&ps_xb);
02536 }
02537
02538
02539
02540
02541
02542
02543
02544
02545
02546 char **parse_style(char *s)
02547 {
02548 static char *parse[FUNLIMIT];
02549 static boolean is_first = TRUE;
02550 int fun = 0;
02551 boolean in_parens = FALSE;
02552 unsigned char buf[SMALLBUF];
02553 char *p;
02554 int c;
02555 agxbuf xb;
02556
02557 if (is_first) {
02558 agxbinit(&ps_xb, SMALLBUF, outbuf);
02559 atexit(cleanup);
02560 is_first = FALSE;
02561 }
02562
02563 agxbinit(&xb, SMALLBUF, buf);
02564 p = s;
02565 while ((c = style_token(&p, &xb)) != 0) {
02566 switch (c) {
02567 case '(':
02568 if (in_parens) {
02569 agerr(AGERR, "nesting not allowed in style: %s\n", s);
02570 parse[0] = (char *) 0;
02571 agxbfree(&xb);
02572 return parse;
02573 }
02574 in_parens = TRUE;
02575 break;
02576
02577 case ')':
02578 if (in_parens == FALSE) {
02579 agerr(AGERR, "unmatched ')' in style: %s\n", s);
02580 parse[0] = (char *) 0;
02581 agxbfree(&xb);
02582 return parse;
02583 }
02584 in_parens = FALSE;
02585 break;
02586
02587 default:
02588 if (in_parens == FALSE) {
02589 if (fun == FUNLIMIT - 1) {
02590 agerr(AGWARN, "truncating style '%s'\n", s);
02591 parse[fun] = (char *) 0;
02592 agxbfree(&xb);
02593 return parse;
02594 }
02595 agxbputc(&ps_xb, '\0');
02596 parse[fun++] = agxbnext(&ps_xb);
02597 }
02598 agxbput(&ps_xb, agxbuse(&xb));
02599 agxbputc(&ps_xb, '\0');
02600 }
02601 }
02602
02603 if (in_parens) {
02604 agerr(AGERR, "unmatched '(' in style: %s\n", s);
02605 parse[0] = (char *) 0;
02606 agxbfree(&xb);
02607 return parse;
02608 }
02609 parse[fun] = (char *) 0;
02610 agxbfree(&xb);
02611 (void)agxbuse(&ps_xb);
02612 return parse;
02613 }
02614
02615 static boxf bezier_bb(bezier bz)
02616 {
02617 int i;
02618 point p;
02619 box bb;
02620 boxf bbf;
02621
02622 assert(bz.size > 0);
02623 bb.LL = bb.UR = bz.list[0];
02624 for (i = 1; i < bz.size; i++) {
02625 p=bz.list[i];
02626 EXPANDBP(bb,p);
02627 }
02628 B2BF(bb, bbf);
02629 return bbf;
02630 }
02631
02632 static void init_splines_bb(splines *spl)
02633 {
02634 int i;
02635 bezier bz;
02636 boxf bb, b;
02637 pointf p, u;
02638
02639 assert(spl->size > 0);
02640 bz = spl->list[0];
02641 bb = bezier_bb(bz);
02642 for (i = 0; i < spl->size; i++) {
02643 if (i > 0) {
02644 bz = spl->list[i];
02645 b = bezier_bb(bz);
02646 EXPANDBB(bb, b);
02647 }
02648 if (bz.sflag) {
02649 P2PF(bz.sp, p);
02650 P2PF(bz.list[0], u);
02651 b = arrow_bb(p, u, 1, bz.sflag);
02652 EXPANDBB(bb, b);
02653 }
02654 if (bz.eflag) {
02655 P2PF(bz.ep, p);
02656 P2PF(bz.list[bz.size - 1], u);
02657 b = arrow_bb(p, u, 1, bz.eflag);
02658 EXPANDBB(bb, b);
02659 }
02660 }
02661 spl->bb = bb;
02662 }
02663
02664 static void init_bb_edge(edge_t *e)
02665 {
02666 splines *spl;
02667
02668 spl = ED_spl(e);
02669 if (spl)
02670 init_splines_bb(spl);
02671
02672
02673
02674
02675 }
02676
02677 static void init_bb_node(graph_t *g, node_t *n)
02678 {
02679 edge_t *e;
02680
02681 ND_bb(n).LL.x = ND_coord_i(n).x - ND_lw_i(n);
02682 ND_bb(n).LL.y = ND_coord_i(n).y - ND_ht_i(n) / 2.;
02683 ND_bb(n).UR.x = ND_coord_i(n).x + ND_rw_i(n);
02684 ND_bb(n).UR.y = ND_coord_i(n).y + ND_ht_i(n) / 2.;
02685
02686 for (e = agfstout(g, n); e; e = agnxtout(g, e))
02687 init_bb_edge(e);
02688
02689
02690
02691
02692
02693
02694
02695
02696 }
02697
02698 static void init_bb(graph_t *g)
02699 {
02700 node_t *n;
02701
02702 for (n = agfstnode(g); n; n = agnxtnode(g, n))
02703 init_bb_node(g, n);
02704 }
02705
02706 extern gvevent_key_binding_t gvevent_key_binding[];
02707 extern int gvevent_key_binding_size;
02708 extern gvdevice_callbacks_t gvdevice_callbacks;
02709
02710 int gvRenderJobs (GVC_t * gvc, graph_t * g)
02711 {
02712 static GVJ_t *prevjob;
02713 GVJ_t *job, *firstjob;
02714
02715 if (!GD_drawing(g)) {
02716 agerr (AGERR, "Layout was not done. Missing layout plugins? \n");
02717 return -1;
02718 }
02719
02720 init_bb(g);
02721 init_gvc(gvc, g);
02722 init_layering(gvc, g);
02723
02724 gvc->keybindings = gvevent_key_binding;
02725 gvc->numkeys = gvevent_key_binding_size;
02726 for (job = gvjobs_first(gvc); job; job = gvjobs_next(gvc)) {
02727 if (gvc->gvg) {
02728 job->input_filename = gvc->gvg->input_filename;
02729 job->graph_index = gvc->gvg->graph_index;
02730 }
02731 else {
02732 job->input_filename = NULL;
02733 job->graph_index = 0;
02734 }
02735 job->common = &(gvc->common);
02736 job->layout_type = gvc->layout.type;
02737 if (!GD_drawing(g)) {
02738 agerr (AGERR, "layout was not done\n");
02739 return -1;
02740 }
02741
02742 job->output_lang = gvrender_select(job, job->output_langname);
02743 if (job->output_lang == NO_SUPPORT) {
02744 agerr (AGERR, "renderer for %s is unavailable\n", job->output_langname);
02745 return -1;
02746 }
02747 #ifdef WITH_CODEGENS
02748 Output_lang = job->output_lang;
02749 #endif
02750
02751 switch (job->output_lang) {
02752 case VTX:
02753
02754 job->flags |= EMIT_SORTED;
02755 break;
02756 case DIA:
02757
02758 job->flags |= EMIT_PREORDER
02759 | GVDEVICE_BINARY_FORMAT;
02760 break;
02761 default:
02762 job->flags |= chkOrder(g);
02763 break;
02764 }
02765
02766
02767 firstjob = gvc->active_jobs;
02768 if (firstjob) {
02769 if (! (firstjob->flags & GVDEVICE_DOES_PAGES)
02770 || (strcmp(job->output_langname,firstjob->output_langname))) {
02771
02772 gvrender_end_job(firstjob);
02773
02774 gvc->active_jobs = NULL;
02775 gvc->common.viewNum = 0;
02776 prevjob = NULL;
02777 }
02778 }
02779 else {
02780 prevjob = NULL;
02781 }
02782
02783 if (prevjob) {
02784 prevjob->next_active = job;
02785 job->output_file = prevjob->output_file;
02786 }
02787 else {
02788 gvc->active_jobs = job;
02789 gvrender_begin_job(job);
02790 }
02791 job->next_active = NULL;
02792 job->callbacks = &gvdevice_callbacks;
02793
02794 init_job_pad(job);
02795 init_job_margin(job);
02796 init_job_dpi(job, g);
02797 init_job_viewport(job, g);
02798 init_job_pagination(job, g);
02799
02800 if (! (job->flags & GVDEVICE_EVENTS)) {
02801 #ifdef DEBUG
02802
02803
02804
02805 job->common->show_boxes = Show_boxes;
02806 #endif
02807 emit_graph(job, g);
02808 }
02809
02810
02811
02812
02813 prevjob = job;
02814 }
02815 return 0;
02816 }