00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "render.h"
00037 #include "htmltable.h"
00038 #include "agxbuf.h"
00039 #include "pointset.h"
00040 #include <assert.h>
00041
00042 #define DEFAULT_BORDER 1
00043 #define DEFAULT_CELLPADDING 2
00044 #define DEFAULT_CELLSPACING 2
00045
00046 typedef struct {
00047 point p;
00048 htmlfont_t finfo;
00049 void *obj;
00050 graph_t *g;
00051 char* imgscale;
00052 } htmlenv_t;
00053
00054 typedef struct {
00055 char *url;
00056 char *tooltip;
00057 char *target;
00058 boolean explicit_tooltip;
00059 point LL;
00060 point UR;
00061 } htmlmap_data_t;
00062
00063 #ifdef DEBUG
00064 static void printCell(htmlcell_t * cp, int ind);
00065 #endif
00066
00067
00068
00069
00070
00071
00072 static void
00073 pushFontInfo(htmlenv_t * env, htmlfont_t * fp, htmlfont_t * savp)
00074 {
00075 if (env->finfo.name) {
00076 if (fp->name) {
00077 savp->name = env->finfo.name;
00078 env->finfo.name = fp->name;
00079 } else
00080 savp->name = NULL;
00081 }
00082 if (env->finfo.color) {
00083 if (fp->color) {
00084 savp->color = env->finfo.color;
00085 env->finfo.color = fp->color;
00086 } else
00087 savp->color = NULL;
00088 }
00089 if (env->finfo.size >= 0) {
00090 if (fp->size >= 0) {
00091 savp->size = env->finfo.size;
00092 env->finfo.size = fp->size;
00093 } else
00094 savp->size = -1.0;
00095 }
00096 }
00097
00098
00099
00100
00101
00102 static void popFontInfo(htmlenv_t * env, htmlfont_t * savp)
00103 {
00104 if (savp->name)
00105 env->finfo.name = savp->name;
00106 if (savp->color)
00107 env->finfo.color = savp->color;
00108 if (savp->size >= 0.0)
00109 env->finfo.size = savp->size;
00110 }
00111
00112 static void
00113 emit_htextparas(GVJ_t* job, int nparas, htextpara_t* paras, pointf p,
00114 double halfwidth_x, char* fname, double fsize, char* fcolor, box b)
00115 {
00116 int i,j;
00117 double tmp, center_x, left_x, right_x, fsize_;
00118 double offset;
00119 char *fname_ , *fcolor_;
00120 textpara_t tl;
00121 pointf p_ = {0.0, 0.0};
00122 textitem_t* ti;
00123
00124 center_x = p.x;
00125 left_x = center_x - halfwidth_x;
00126 right_x = center_x + halfwidth_x;
00127
00128
00129
00130
00131 p_.y = p.y + (double)(b.UR.y-b.LL.y)/2.0;
00132 tmp = ROUND(p_.y);
00133 p_.y = (double)tmp;
00134
00135 gvrender_begin_context(job);
00136 for(i=0; i<nparas; i++) {
00137 switch (paras[i].just) {
00138 case 'l':
00139 p_.x = left_x;
00140 p.x = left_x;
00141 break;
00142 case 'r':
00143 p_.x = right_x;
00144 p.x = right_x;
00145 break;
00146 default:
00147 case 'n':
00148 p_.x = center_x;
00149 p.x = center_x;
00150 break;
00151 }
00152 p_.y -= paras[i].lfsize;
00153
00154 ti = paras[i].items;
00155 offset = 0.0;
00156 for(j=0; j<paras[i].nitems; j++) {
00157 if (ti->font && (ti->font->size > 0))
00158 fsize_ = ti->font->size;
00159 else
00160 fsize_ = fsize;
00161 if (ti->font && ti->font->name)
00162 fname_ = ti->font->name;
00163 else
00164 fname_ = fname;
00165 if (ti->font && ti->font->color)
00166 fcolor_ = ti->font->color;
00167 else
00168 fcolor_ = fcolor;
00169
00170 gvrender_set_pencolor(job, fcolor_);
00171 gvrender_set_font(job, fname_, fsize_);
00172
00173 tl.str = ti->str;
00174 tl.fontname = fname_;
00175 tl.fontsize = fsize_;
00176 tl.yoffset_layout = ti->yoffset_layout;
00177 tl.yoffset_centerline = ti->yoffset_centerline;
00178 tl.postscript_alias = ti->postscript_alias;
00179 tl.layout = ti->layout;
00180 tl.width = paras[i].size;
00181 tl.height = paras[i].lfsize;
00182 tl.just = paras[i].just;
00183
00184 gvrender_textpara(job, p_, &tl);
00185 offset += ti->size;
00186 p_.x = p.x + offset;
00187 ti++;
00188 }
00189 }
00190
00191 gvrender_end_context(job);
00192 }
00193
00194 static void
00195 emit_html_txt(GVJ_t* job, htmltxt_t* tp, htmlenv_t* env)
00196 {
00197 double halfwidth_x;
00198 pointf p;
00199 char *fname;
00200 char *fcolor;
00201 double fsize;
00202
00203
00204 if (tp->nparas < 1)
00205 return;
00206
00207 fsize = env->finfo.size;
00208 fname = env->finfo.name;
00209 fcolor = env->finfo.color;
00210
00211 halfwidth_x = ((double) (tp->box.UR.x - tp->box.LL.x)) / 2.0;
00212 p.x = env->p.x + ((double) (tp->box.UR.x + tp->box.LL.x)) / 2.0;
00213 p.y = env->p.y + ((double) (tp->box.UR.y + tp->box.LL.y)) / 2.0;
00214
00215 emit_htextparas(job, tp->nparas, tp->paras, p, halfwidth_x, fname,
00216 fsize, fcolor, tp->box);
00217 }
00218
00219 static void doSide(GVJ_t * job, pointf p, double wd, double ht)
00220 {
00221 boxf BF;
00222
00223 BF.LL = p;
00224 BF.UR.x = p.x + wd;
00225 BF.UR.y = p.y + ht;
00226 gvrender_box(job, BF, 1);
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 static void doBorder(GVJ_t * job, char *color, int border, box B)
00240 {
00241 pointf pt;
00242 boxf BF;
00243 double wd, ht;
00244
00245 gvrender_begin_context(job);
00246
00247 if (!color)
00248 color = "black";
00249 gvrender_set_fillcolor(job, color);
00250 gvrender_set_pencolor(job, color);
00251
00252 B2BF(B, BF);
00253 if (border == 1) {
00254 gvrender_box(job, BF, 0);
00255 } else {
00256 border--;
00257 ht = BF.UR.y - BF.LL.y;
00258 wd = BF.UR.x - BF.LL.x;
00259 doSide(job, BF.LL, border, ht);
00260 pt.x = BF.LL.x;
00261 pt.y = BF.UR.y;
00262 doSide(job, pt, wd, -border);
00263 doSide(job, BF.UR, -border, -ht);
00264 pt.x = BF.UR.x;
00265 pt.y = BF.LL.y;
00266 doSide(job, pt, -wd, border);
00267 }
00268
00269 gvrender_end_context(job);
00270 }
00271
00272 static void doFill(GVJ_t * job, char *color, box B)
00273 {
00274 boxf BF;
00275
00276 gvrender_set_fillcolor(job, color);
00277 gvrender_set_pencolor(job, color);
00278 B2BF(B, BF);
00279 gvrender_box(job, BF, 1);
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 static int
00294 initAnchor (GVJ_t* job, htmldata_t* data, box pts, htmlmap_data_t* save,
00295 int closePrev)
00296 {
00297 obj_state_t *obj = job->obj;
00298 int changed;
00299
00300 save->url = obj->url;
00301 save->tooltip = obj->tooltip;
00302 save->target = obj->target;
00303 save->explicit_tooltip = obj->explicit_tooltip;
00304 changed = initMapData (job, NULL, data->href, data->title, data->target, obj->u.g);
00305
00306 if (changed) {
00307 if (closePrev && (save->url || save->explicit_tooltip))
00308 gvrender_end_anchor(job);
00309 if (obj->url || obj->explicit_tooltip) {
00310 emit_map_rect(job, pts.LL, pts.UR);
00311 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
00312 }
00313 }
00314 return changed;
00315 }
00316
00317 #define RESET(fld) \
00318 if(obj->fld != save->fld) {free(obj->fld); obj->fld = save->fld;}
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 static void
00332 endAnchor (GVJ_t* job, htmlmap_data_t* save, int openPrev)
00333 {
00334 obj_state_t *obj = job->obj;
00335
00336 if (obj->url || obj->explicit_tooltip)
00337 gvrender_end_anchor(job);
00338 RESET(url);
00339 RESET(tooltip);
00340 RESET(target);
00341 obj->explicit_tooltip = save->explicit_tooltip;
00342 if (openPrev && (obj->url || obj->explicit_tooltip))
00343 gvrender_begin_anchor(job, obj->url, obj->tooltip, obj->target);
00344 }
00345
00346
00347 static void emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env);
00348
00349 static void
00350 emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
00351 {
00352 box pts = tbl->data.box;
00353 point p = env->p;
00354 htmlcell_t **cells = tbl->u.n.cells;
00355 htmlfont_t savef;
00356 htmlmap_data_t saved;
00357 int anchor;
00358 int doAnchor = (tbl->data.href || tbl->data.target);
00359
00360 if (tbl->font)
00361 pushFontInfo(env, tbl->font, &savef);
00362
00363 pts.LL.x += p.x;
00364 pts.UR.x += p.x;
00365 pts.LL.y += p.y;
00366 pts.UR.y += p.y;
00367
00368 if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
00369 anchor = initAnchor(job, &tbl->data, pts, &saved, 1);
00370 else
00371 anchor = 0;
00372
00373 if (tbl->data.bgcolor)
00374 doFill(job, tbl->data.bgcolor, pts);
00375
00376 if (tbl->data.border)
00377 doBorder(job, tbl->data.pencolor, tbl->data.border, pts);
00378
00379 while (*cells) {
00380 emit_html_cell(job, *cells, env);
00381 cells++;
00382 }
00383
00384 if (anchor)
00385 endAnchor (job, &saved, 1);
00386
00387 if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
00388 if (initAnchor(job, &tbl->data, pts, &saved, 0))
00389 endAnchor (job, &saved, 0);
00390 }
00391
00392 if (tbl->font)
00393 popFontInfo(env, &savef);
00394 }
00395
00396
00397
00398
00399
00400
00401 static void
00402 emit_html_img(GVJ_t * job, htmlimg_t * cp, htmlenv_t * env)
00403 {
00404 pointf A[4];
00405 box bb = cp->box;
00406 char* scale;
00407
00408 bb.LL.x += env->p.x;
00409 bb.LL.y += env->p.y;
00410 bb.UR.x += env->p.x;
00411 bb.UR.y += env->p.y;
00412
00413 P2PF(bb.UR, A[0]);
00414 P2PF(bb.LL, A[2]);
00415 A[1].x = A[2].x;
00416 A[1].y = A[0].y;
00417 A[3].x = A[0].x;
00418 A[3].y = A[2].y;
00419
00420 if (cp->scale)
00421 scale = cp->scale;
00422 else
00423 scale = env->imgscale;
00424 gvrender_usershape(job, cp->src, A, 4, TRUE, scale);
00425 }
00426
00427 static void
00428 emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
00429 {
00430 htmlmap_data_t saved;
00431 box pts = cp->data.box;
00432 point p = env->p;
00433 int inAnchor, doAnchor = (cp->data.href || cp->data.target);
00434
00435 pts.LL.x += p.x;
00436 pts.UR.x += p.x;
00437 pts.LL.y += p.y;
00438 pts.UR.y += p.y;
00439
00440 if (doAnchor && !(job->flags & EMIT_CLUSTERS_LAST))
00441 inAnchor = initAnchor(job, &cp->data, pts, &saved, 1);
00442 else
00443 inAnchor = 0;
00444
00445 if (cp->data.bgcolor) {
00446 doFill(job, cp->data.bgcolor, pts);
00447 }
00448
00449 if (cp->data.border)
00450 doBorder(job, cp->data.pencolor, cp->data.border, pts);
00451
00452 if (cp->child.kind == HTML_TBL)
00453 emit_html_tbl(job, cp->child.u.tbl, env);
00454 else if (cp->child.kind == HTML_IMAGE)
00455 emit_html_img(job, cp->child.u.img, env);
00456 else
00457 emit_html_txt(job, cp->child.u.txt, env);
00458
00459 if (inAnchor)
00460 endAnchor (job, &saved, 1);
00461
00462 if (doAnchor && (job->flags & EMIT_CLUSTERS_LAST)) {
00463 if (initAnchor(job, &cp->data, pts, &saved, 0))
00464 endAnchor (job, &saved, 0);
00465 }
00466 }
00467
00468
00469
00470
00471
00472
00473
00474 static void
00475 allocObj (GVJ_t * job)
00476 {
00477 obj_state_t *obj;
00478 obj_state_t *parent;
00479
00480 obj = push_obj_state(job);
00481 parent = obj->parent;
00482 obj->type = parent->type;
00483 obj->emit_state = parent->emit_state;
00484 switch (obj->type) {
00485 case NODE_OBJTYPE :
00486 obj->u.n = parent->u.n;
00487 #ifdef WITH_CODEGENS
00488 Obj = NODE;
00489 #endif
00490 break;
00491 case ROOTGRAPH_OBJTYPE :
00492 obj->u.g = parent->u.g;
00493 #ifdef WITH_CODEGENS
00494 Obj = NONE;
00495 #endif
00496 break;
00497 case CLUSTER_OBJTYPE :
00498 obj->u.sg = parent->u.sg;
00499 #ifdef WITH_CODEGENS
00500 Obj = CLST;
00501 #endif
00502 break;
00503 case EDGE_OBJTYPE :
00504 obj->u.e = parent->u.e;
00505 #ifdef WITH_CODEGENS
00506 Obj = EDGE;
00507 #endif
00508 break;
00509 }
00510 obj->url = parent->url;
00511 obj->tooltip = parent->tooltip;
00512 obj->target = parent->target;
00513 obj->explicit_tooltip = parent->explicit_tooltip;
00514 }
00515
00516 static void
00517 freeObj (GVJ_t * job)
00518 {
00519 obj_state_t *obj = job->obj;
00520
00521 obj->url = NULL;
00522 obj->tooltip = NULL;
00523 obj->target = NULL;
00524 pop_obj_state(job);
00525 }
00526
00527
00528
00529 void
00530 emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp)
00531 {
00532 htmlenv_t env;
00533
00534 allocObj (job);
00535 env.p = tp->p;
00536 env.finfo.color = tp->fontcolor;
00537 env.finfo.name = tp->fontname;
00538 env.finfo.size = tp->fontsize;
00539 env.finfo.size = tp->fontsize;
00540 env.imgscale = agget (job->obj->u.n, "imagescale");
00541 if ((env.imgscale == NULL) || (*env.imgscale == '\0'))
00542 env.imgscale = "false";
00543 if (lp->kind == HTML_TBL) {
00544 htmltbl_t *tbl = lp->u.tbl;
00545
00546
00547 gvrender_begin_context(job);
00548
00549 gvrender_set_style(job, job->gvc->defaultlinestyle);
00550 if (tbl->data.pencolor)
00551 gvrender_set_pencolor(job, tbl->data.pencolor);
00552 else
00553 gvrender_set_pencolor(job, DEFAULT_COLOR);
00554 emit_html_tbl(job, tbl, &env);
00555 gvrender_end_context(job);
00556 } else {
00557 emit_html_txt(job, lp->u.txt, &env);
00558 }
00559 freeObj (job);
00560 }
00561
00562 void free_html_font(htmlfont_t * fp)
00563 {
00564 fp->cnt--;
00565 if (fp->cnt == 0) {
00566 if (fp->name)
00567 free(fp->name);
00568 if (fp->color)
00569 free(fp->color);
00570 free(fp);
00571 }
00572 }
00573
00574 void free_html_data(htmldata_t * dp)
00575 {
00576 free(dp->href);
00577 free(dp->port);
00578 free(dp->target);
00579 free(dp->title);
00580 free(dp->bgcolor);
00581 }
00582
00583 void free_html_text(htmltxt_t* t)
00584 {
00585 htextpara_t *tl;
00586 textitem_t *ti;
00587 int i, j;
00588
00589 if (!t) return;
00590
00591 tl = t->paras;
00592 if (tl) {
00593 ti = tl->items;
00594 for (i = 0; i < t->nparas; i++) {
00595 for (j = 0; j < tl->nitems; j++) {
00596 if (ti->str) free (ti->str);
00597 if (ti->font) free_html_font(ti->font);
00598 if (ti->layout && ti->free_layout) ti->free_layout (ti->layout);
00599 ti++;
00600 }
00601 tl++;
00602 ti = tl->items;
00603 }
00604 if (ti != tl->items) free(tl->items);
00605 if (tl != t->paras) free(t->paras);
00606 }
00607 free(t);
00608 }
00609
00610 void free_html_img(htmlimg_t * ip)
00611 {
00612 free(ip->src);
00613 free(ip);
00614 }
00615
00616 static void free_html_cell(htmlcell_t * cp)
00617 {
00618 free_html_label(&cp->child, 0);
00619 free_html_data(&cp->data);
00620 free(cp);
00621 }
00622
00623
00624
00625
00626
00627
00628 static void free_html_tbl(htmltbl_t * tbl)
00629 {
00630 htmlcell_t **cells;
00631
00632 if (tbl->rc == -1) {
00633 dtclose(tbl->u.p.rows);
00634 } else {
00635 cells = tbl->u.n.cells;
00636
00637 free(tbl->heights);
00638 free(tbl->widths);
00639 while (*cells) {
00640 free_html_cell(*cells);
00641 cells++;
00642 }
00643 free(tbl->u.n.cells);
00644 }
00645 if (tbl->font)
00646 free_html_font(tbl->font);
00647 free_html_data(&tbl->data);
00648 free(tbl);
00649 }
00650
00651 void free_html_label(htmllabel_t * lp, int root)
00652 {
00653 if (lp->kind == HTML_TBL)
00654 free_html_tbl(lp->u.tbl);
00655 else if (lp->kind == HTML_IMAGE)
00656 free_html_img(lp->u.img);
00657 else
00658 free_html_text(lp->u.txt);
00659 if (root)
00660 free(lp);
00661 }
00662
00663 static htmldata_t* portToTbl(htmltbl_t *, char *);
00664
00665 static htmldata_t* portToCell(htmlcell_t * cp, char *id)
00666 {
00667 htmldata_t* rv;
00668
00669 if (cp->data.port && (strcasecmp(cp->data.port, id) == 0))
00670 rv = &cp->data;
00671 else if (cp->child.kind == HTML_TBL)
00672 rv = portToTbl(cp->child.u.tbl, id);
00673 else
00674 rv = NULL;
00675
00676 return rv;
00677 }
00678
00679
00680
00681
00682
00683 static htmldata_t*
00684 portToTbl(htmltbl_t* tp, char* id)
00685 {
00686 htmldata_t* rv;
00687 htmlcell_t** cells;
00688 htmlcell_t* cp;
00689
00690 if (tp->data.port && (strcasecmp(tp->data.port, id) == 0))
00691 rv = &tp->data;
00692 else {
00693 rv = NULL;
00694 cells = tp->u.n.cells;
00695 while ((cp = *cells++)) {
00696 if ((rv = portToCell(cp, id)))
00697 break;
00698 }
00699 }
00700
00701 return rv;
00702 }
00703
00704
00705
00706
00707
00708
00709
00710 box *html_port(node_t * n, char *pname, int* sides)
00711 {
00712 htmldata_t* tp;
00713 htmllabel_t* lbl = ND_label(n)->u.html;
00714 box* rv = NULL;
00715
00716 if (lbl->kind == HTML_TEXT)
00717 return NULL;
00718
00719 tp = portToTbl(lbl->u.tbl, pname);
00720 if (tp) {
00721 rv = &tp->box;
00722 *sides = tp->sides;
00723 }
00724 return rv;
00725
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 int html_path(node_t * n, port* p, int side, box * rv, int *k)
00742 {
00743 #ifdef UNIMPL
00744 point p;
00745 tbl_t *info;
00746 tbl_t *t;
00747 box b;
00748 int i;
00749
00750 info = (tbl_t *) ND_shape_info(n);
00751 assert(info->tbls);
00752 info = info->tbls[0];
00753 assert(IS_FLOW(info));
00754
00755 b = info->box;
00756 if (info->tbl) {
00757 info = info->tbl;
00758 if (pt == 1)
00759 p = ED_tail_port(e).p;
00760 else
00761 p = ED_head_port(e).p;
00762 p = flip_pt(p, GD_rankdir(n->graph));
00763 for (i = 0; (t = info->tbls[i]) != 0; i++)
00764 if (INSIDE(p, t->box)) {
00765 b = t->box;
00766 break;
00767 }
00768 }
00769
00770
00771 if (GD_flip(n->graph))
00772 b = flip_trans_box(b, ND_coord_i(n));
00773 else
00774 b = move_box(b, ND_coord_i(n));
00775
00776 *k = 1;
00777 *rv = b;
00778 if (pt == 1)
00779 return BOTTOM;
00780 else
00781 return TOP;
00782 #endif
00783 return 0;
00784 }
00785
00786 static int
00787 size_html_txt(graph_t *g, htmltxt_t* ftxt, htmlenv_t* env)
00788 {
00789 double xsize = 0.0;
00790 double ysize = 0.0;
00791 double fsize;
00792 double lsize;
00793 double mxfsize = 0.0;
00794 double curbline = 0.0;
00795 pointf sz;
00796 int i, j, w, width;
00797 char *fname;
00798 textpara_t lp;
00799
00800 for (i = 0; i < ftxt->nparas; i++) {
00801 width = w = 0;
00802 mxfsize = 0;
00803 for (j = 0; j < ftxt->paras[i].nitems; j++) {
00804 lp.str = strdup_and_subst_obj (ftxt->paras[i].items[j].str, env->obj);
00805 if (ftxt->paras[i].items[j].font) {
00806 if (ftxt->paras[i].items[j].font->size > 0)
00807 fsize = ftxt->paras[i].items[j].font->size;
00808 else
00809 fsize = env->finfo.size;
00810 if (ftxt->paras[i].items[j].font->name)
00811 fname = ftxt->paras[i].items[j].font->name;
00812 else
00813 fname = env->finfo.name;
00814 } else {
00815 fsize = env->finfo.size;
00816 fname = env->finfo.name;
00817 }
00818 sz = textsize(g, &lp, fname, fsize);
00819 free (ftxt->paras[i].items[j].str);
00820 ftxt->paras[i].items[j].str = lp.str;
00821 ftxt->paras[i].items[j].size = sz.x;
00822 ftxt->paras[i].items[j].yoffset_layout = lp.yoffset_layout;
00823 ftxt->paras[i].items[j].yoffset_centerline = lp.yoffset_centerline;
00824 ftxt->paras[i].items[j].postscript_alias = lp.postscript_alias;
00825 ftxt->paras[i].items[j].layout = lp.layout;
00826 ftxt->paras[i].items[j].free_layout = lp.free_layout;
00827 width += sz.x;
00828 mxfsize = MAX(fsize, mxfsize);
00829 }
00830 lsize = mxfsize * LINESPACING;
00831 ftxt->paras[i].size = (double) width;
00832
00833
00834
00835
00836
00837
00838 ftxt->paras[i].lfsize = 5*mxfsize/6 + ysize - curbline;
00839 curbline += ftxt->paras[i].lfsize;
00840 xsize = MAX(width, xsize);
00841 ysize += lsize;
00842 }
00843 ftxt->box.UR.x = xsize;
00844 if (ftxt->nparas == 1)
00845 ftxt->box.UR.y = (int) (mxfsize);
00846 else
00847 ftxt->box.UR.y = (int) (ysize);
00848 return 0;
00849 }
00850
00851
00852 static int size_html_tbl(graph_t *g, htmltbl_t * tbl, htmlcell_t * parent,
00853 htmlenv_t * env);
00854
00855
00856
00857 static int size_html_img(htmlimg_t * img, htmlenv_t * env)
00858 {
00859 box b;
00860 int rv;
00861
00862 b.LL.x = b.LL.y = 0;
00863 b.UR = gvusershape_size(env->g, img->src);
00864 if ((b.UR.x == -1) && (b.UR.y == -1)) {
00865 rv = 1;
00866 b.UR.x = b.UR.y = 0;
00867 agerr(AGERR, "No or improper image file=\"%s\"\n", img->src);
00868 } else {
00869 rv = 0;
00870 GD_has_images(env->g) = TRUE;
00871 }
00872
00873 img->box = b;
00874 return rv;
00875 }
00876
00877
00878
00879 static int
00880 size_html_cell(graph_t *g, htmlcell_t * cp, htmltbl_t * parent, htmlenv_t * env)
00881 {
00882 int rv;
00883 point sz, child_sz;
00884 int margin;
00885
00886 cp->parent = parent;
00887 if (!(cp->data.flags & PAD_SET)) {
00888 if (parent->data.flags & PAD_SET)
00889 cp->data.pad = parent->data.pad;
00890 else
00891 cp->data.pad = DEFAULT_CELLPADDING;
00892 }
00893 if (!(cp->data.flags & BORDER_SET)) {
00894 if (parent->cb >= 0)
00895 cp->data.border = parent->cb;
00896 else if (parent->data.flags & BORDER_SET)
00897 cp->data.border = parent->data.border;
00898 else
00899 cp->data.border = DEFAULT_BORDER;
00900 }
00901
00902 if (cp->child.kind == HTML_TBL) {
00903 rv = size_html_tbl(g, cp->child.u.tbl, cp, env);
00904 child_sz = cp->child.u.tbl->data.box.UR;
00905 } else if (cp->child.kind == HTML_IMAGE) {
00906 rv = size_html_img(cp->child.u.img, env);
00907 child_sz = cp->child.u.img->box.UR;
00908 } else {
00909 rv = size_html_txt(g, cp->child.u.txt, env);
00910 child_sz = cp->child.u.txt->box.UR;
00911 }
00912
00913 margin = 2 * (cp->data.pad + cp->data.border);
00914 sz.x = child_sz.x + margin;
00915 sz.y = child_sz.y + margin;
00916
00917 if (cp->data.flags & FIXED_FLAG) {
00918 if (cp->data.width && cp->data.height) {
00919 if ((cp->data.width < sz.x) || (cp->data.height < sz.y)) {
00920 agerr(AGWARN, "cell size too small for content\n");
00921 rv = 1;
00922 }
00923 sz.x = sz.y = 0;
00924
00925 } else {
00926 agerr(AGWARN,
00927 "fixed cell size with unspecified width or height\n");
00928 rv = 1;
00929 }
00930 }
00931 cp->data.box.UR.x = MAX(sz.x, cp->data.width);
00932 cp->data.box.UR.y = MAX(sz.y, cp->data.height);
00933 return rv;
00934 }
00935
00936 static int findCol(PointSet * ps, int row, int col, htmlcell_t * cellp)
00937 {
00938 int notFound = 1;
00939 int lastc;
00940 int i, j, c;
00941 int end = cellp->cspan - 1;
00942
00943 while (notFound) {
00944 lastc = col + end;
00945 for (c = lastc; c >= col; c--) {
00946 if (isInPS(ps, c, row))
00947 break;
00948 }
00949 if (c >= col)
00950 col = c + 1;
00951 else
00952 notFound = 0;
00953 }
00954 for (j = col; j < col + cellp->cspan; j++) {
00955 for (i = row; i < row + cellp->rspan; i++) {
00956 addPS(ps, j, i);
00957 }
00958 }
00959 return col;
00960 }
00961
00962
00963
00964
00965
00966
00967
00968 static int processTbl(graph_t *g, htmltbl_t * tbl, htmlenv_t * env)
00969 {
00970 pitem *rp;
00971 pitem *cp;
00972 Dt_t *cdict;
00973 int r, c, cnt;
00974 htmlcell_t *cellp;
00975 htmlcell_t **cells;
00976 Dt_t *rows = tbl->u.p.rows;
00977 int rv = 0;
00978 int n_rows = 0;
00979 int n_cols = 0;
00980 PointSet *ps = newPS();
00981
00982 rp = (pitem *) dtflatten(rows);
00983 cnt = 0;
00984 while (rp) {
00985 cdict = rp->u.rp;
00986 cp = (pitem *) dtflatten(cdict);
00987 while (cp) {
00988 cellp = cp->u.cp;
00989 cnt++;
00990 cp = (pitem *) dtlink(cdict, (Dtlink_t *) cp);
00991 }
00992 rp = (pitem *) dtlink(rows, (Dtlink_t *) rp);
00993 }
00994
00995 cells = tbl->u.n.cells = N_NEW(cnt + 1, htmlcell_t *);
00996 rp = (pitem *) dtflatten(rows);
00997 r = 0;
00998 while (rp) {
00999 cdict = rp->u.rp;
01000 cp = (pitem *) dtflatten(cdict);
01001 c = 0;
01002 while (cp) {
01003 cellp = cp->u.cp;
01004 *cells++ = cellp;
01005 rv |= size_html_cell(g, cellp, tbl, env);
01006 c = findCol(ps, r, c, cellp);
01007 cellp->row = r;
01008 cellp->col = c;
01009 c += cellp->cspan;
01010 n_cols = MAX(c, n_cols);
01011 n_rows = MAX(r + cellp->rspan, n_rows);
01012 cp = (pitem *) dtlink(cdict, (Dtlink_t *) cp);
01013 }
01014 rp = (pitem *) dtlink(rows, (Dtlink_t *) rp);
01015 r++;
01016 }
01017 tbl->rc = n_rows;
01018 tbl->cc = n_cols;
01019 dtclose(rows);
01020 freePS(ps);
01021 return rv;
01022 }
01023
01024
01025
01026
01027
01028 #define SPLIT(x,n,s) (((x) - ((s)-1)*((n)-1)) / (n))
01029
01030
01031
01032
01033
01034
01035
01036 void sizeLinearArray(htmltbl_t * tbl)
01037 {
01038 htmlcell_t *cp;
01039 htmlcell_t **cells;
01040 int wd, ht, i, x, y;
01041
01042 tbl->heights = N_NEW(tbl->rc + 1, int);
01043 tbl->widths = N_NEW(tbl->cc + 1, int);
01044
01045 for (cells = tbl->u.n.cells; *cells; cells++) {
01046 cp = *cells;
01047 if (cp->rspan == 1)
01048 ht = cp->data.box.UR.y;
01049 else {
01050 ht = SPLIT(cp->data.box.UR.y, cp->rspan, tbl->data.space);
01051 ht = MAX(ht, 1);
01052 }
01053 if (cp->cspan == 1)
01054 wd = cp->data.box.UR.x;
01055 else {
01056 wd = SPLIT(cp->data.box.UR.x, cp->cspan, tbl->data.space);
01057 wd = MAX(wd, 1);
01058 }
01059 for (i = cp->row; i < cp->row + cp->rspan; i++) {
01060 y = tbl->heights[i];
01061 tbl->heights[i] = MAX(y, ht);
01062 }
01063 for (i = cp->col; i < cp->col + cp->cspan; i++) {
01064 x = tbl->widths[i];
01065 tbl->widths[i] = MAX(x, wd);
01066 }
01067 }
01068 }
01069
01070 static char *nnames[] = {
01071 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
01072 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
01073 };
01074
01075
01076
01077
01078 char *nToName(int c)
01079 {
01080 static char name[100];
01081
01082 if (c < sizeof(nnames) / sizeof(char *))
01083 return nnames[c];
01084
01085 sprintf(name, "%d", c);
01086 return name;
01087 }
01088
01089
01090
01091
01092 static void closeGraphs(graph_t * rowg, graph_t * colg)
01093 {
01094 node_t *n;
01095 for (n = GD_nlist(colg); n; n = ND_next(n)) {
01096 free_list(ND_in(n));
01097 free_list(ND_out(n));
01098 }
01099
01100 agclose(rowg);
01101 agclose(colg);
01102 }
01103
01104 static void checkChain(graph_t * g)
01105 {
01106 node_t *t;
01107 node_t *h;
01108 edge_t *e;
01109 t = GD_nlist(g);
01110 for (h = ND_next(t); h; h = ND_next(h)) {
01111 if (!agfindedge(g, t, h)) {
01112 e = agedge(g, t, h);
01113 ED_minlen(e) = 0;
01114 elist_append(e, ND_out(t));
01115 elist_append(e, ND_in(h));
01116 }
01117 t = h;
01118 }
01119 }
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131 void makeGraphs(htmltbl_t * tbl, graph_t * rowg, graph_t * colg)
01132 {
01133 htmlcell_t *cp;
01134 htmlcell_t **cells;
01135 node_t *t;
01136 node_t *lastn;
01137 node_t *h;
01138 edge_t *e;
01139 int i;
01140 int* minc;
01141 int* minr;
01142
01143 lastn = NULL;
01144 for (i = 0; i <= tbl->cc; i++) {
01145 t = agnode(colg, nToName(i));
01146 alloc_elist(tbl->rc, ND_in(t));
01147 alloc_elist(tbl->rc, ND_out(t));
01148 if (lastn) {
01149 ND_next(lastn) = t;
01150 lastn = t;
01151 } else {
01152 lastn = GD_nlist(colg) = t;
01153 }
01154 }
01155 lastn = NULL;
01156 for (i = 0; i <= tbl->rc; i++) {
01157 t = agnode(rowg, nToName(i));
01158 alloc_elist(tbl->cc, ND_in(t));
01159 alloc_elist(tbl->cc, ND_out(t));
01160 if (lastn) {
01161 ND_next(lastn) = t;
01162 lastn = t;
01163 } else {
01164 lastn = GD_nlist(rowg) = t;
01165 }
01166 }
01167 minr = N_NEW(tbl->rc, int);
01168 minc = N_NEW(tbl->cc, int);
01169 for (cells = tbl->u.n.cells; *cells; cells++) {
01170 int x, y, c, r;
01171 cp = *cells;
01172 x = (cp->data.box.UR.x + (cp->cspan-1))/cp->cspan;
01173 for (c = 0; c < cp->cspan; c++)
01174 minc[cp->col + c] = MAX(minc[cp->col + c],x);
01175 y = (cp->data.box.UR.y + (cp->rspan-1))/cp->rspan;
01176 for (r = 0; r < cp->rspan; r++)
01177 minr[cp->row + r] = MAX(minr[cp->row + r],y);
01178 }
01179 for (cells = tbl->u.n.cells; *cells; cells++) {
01180 int x, y, c, r;
01181 cp = *cells;
01182 t = agfindnode(colg, nToName(cp->col));
01183 h = agfindnode(colg, nToName(cp->col + cp->cspan));
01184 e = agedge(colg, t, h);
01185 x = 0;
01186 for (c = 0; c < cp->cspan; c++)
01187 x += minc[cp->col + c];
01188 ED_minlen(e) = x;
01189
01190 #ifdef DEBUG
01191 fprintf(stderr, "col edge %s -> %s %d\n", t->name, h->name,
01192 ED_minlen(e));
01193 #endif
01194 elist_append(e, ND_out(t));
01195 elist_append(e, ND_in(h));
01196
01197 t = agfindnode(rowg, nToName(cp->row));
01198 h = agfindnode(rowg, nToName(cp->row + cp->rspan));
01199 e = agedge(rowg, t, h);
01200 y = 0;
01201 for (r = 0; r < cp->rspan; r++)
01202 y += minr[cp->row + r];
01203 ED_minlen(e) = y;
01204
01205 #ifdef DEBUG
01206 fprintf(stderr, "row edge %s -> %s %d\n", t->name, h->name,
01207 ED_minlen(e));
01208 #endif
01209 elist_append(e, ND_out(t));
01210 elist_append(e, ND_in(h));
01211 }
01212
01213
01214 checkChain(colg);
01215 checkChain(rowg);
01216
01217 free (minc);
01218 free (minr);
01219 }
01220
01221
01222
01223
01224
01225
01226 void setSizes(htmltbl_t * tbl, graph_t * rowg, graph_t * colg)
01227 {
01228 int i;
01229 node_t *n;
01230 int prev;
01231
01232 prev = 0;
01233 n = GD_nlist(rowg);
01234 for (i = 0, n = ND_next(n); n; i++, n = ND_next(n)) {
01235 tbl->heights[i] = ND_rank(n) - prev;
01236 prev = ND_rank(n);
01237 }
01238 prev = 0;
01239 n = GD_nlist(colg);
01240 for (i = 0, n = ND_next(n); n; i++, n = ND_next(n)) {
01241 tbl->widths[i] = ND_rank(n) - prev;
01242 prev = ND_rank(n);
01243 }
01244
01245 }
01246
01247
01248
01249
01250
01251
01252
01253
01254 void sizeArray(htmltbl_t * tbl)
01255 {
01256 graph_t *rowg;
01257 graph_t *colg;
01258
01259
01260 if ((tbl->rc == 1) || (tbl->cc == 1)) {
01261 sizeLinearArray(tbl);
01262 return;
01263 }
01264
01265 tbl->heights = N_NEW(tbl->rc + 1, int);
01266 tbl->widths = N_NEW(tbl->cc + 1, int);
01267
01268 rowg = agopen("rowg", AGDIGRAPH);
01269 colg = agopen("colg", AGDIGRAPH);
01270 makeGraphs(tbl, rowg, colg);
01271 rank(rowg, 2, INT_MAX);
01272 rank(colg, 2, INT_MAX);
01273 setSizes(tbl, rowg, colg);
01274 closeGraphs(rowg, colg);
01275 }
01276
01277 static void pos_html_tbl(htmltbl_t *, box, int);
01278
01279
01280
01281
01282
01283
01284 static void pos_html_img(htmlimg_t * cp, box pos)
01285 {
01286 cp->box = pos;
01287 }
01288
01289
01290
01291
01292 static void
01293 pos_html_txt(htmltxt_t* ftxt, char c)
01294 {
01295 int i;
01296
01297 for (i = 0; i < ftxt->nparas; i++) {
01298 if (ftxt->paras[i].just == UNSET_ALIGN)
01299 ftxt->paras[i].just = c;
01300 }
01301 }
01302
01303
01304
01305 static void pos_html_cell(htmlcell_t * cp, box pos, int sides)
01306 {
01307 int delx, dely;
01308 point oldsz;
01309 box cbox;
01310
01311 if (!cp->data.pencolor)
01312 cp->data.pencolor = cp->parent->data.pencolor;
01313
01314
01315 if (cp->data.flags & FIXED_FLAG) {
01316 oldsz = cp->data.box.UR;
01317 delx = (pos.UR.x - pos.LL.x) - oldsz.x;
01318 if (delx > 0) {
01319 switch (cp->data.flags & HALIGN_MASK) {
01320 case HALIGN_LEFT:
01321 pos.UR.x = pos.LL.x + oldsz.x;
01322 break;
01323 case HALIGN_RIGHT:
01324 pos.UR.x += delx;
01325 pos.LL.x += delx;
01326 break;
01327 default:
01328 pos.LL.x += delx / 2;
01329 pos.UR.x -= delx / 2;
01330 break;
01331 }
01332 }
01333 dely = (pos.UR.y - pos.LL.y) - oldsz.y;
01334 if (dely > 0) {
01335 switch (cp->data.flags & VALIGN_MASK) {
01336 case VALIGN_BOTTOM:
01337 pos.UR.y = pos.LL.y + oldsz.y;
01338 break;
01339 case VALIGN_TOP:
01340 pos.UR.y += dely;
01341 pos.LL.y += dely;
01342 break;
01343 default:
01344 pos.LL.y += dely / 2;
01345 pos.UR.y -= dely / 2;
01346 break;
01347 }
01348 }
01349 }
01350 cp->data.box = pos;
01351 cp->data.sides = sides;
01352
01353
01354 cbox.LL.x = pos.LL.x + cp->data.border + cp->data.pad;
01355 cbox.LL.y = pos.LL.y + cp->data.border + cp->data.pad;
01356 cbox.UR.x = pos.UR.x - cp->data.border - cp->data.pad;
01357 cbox.UR.y = pos.UR.y - cp->data.border - cp->data.pad;
01358
01359 if (cp->child.kind == HTML_TBL) {
01360 pos_html_tbl(cp->child.u.tbl, cbox, sides);
01361 } else if (cp->child.kind == HTML_IMAGE) {
01362 pos_html_img(cp->child.u.img, cbox);
01363 } else {
01364 char dfltalign;
01365 int af;
01366
01367 oldsz = cp->child.u.txt->box.UR;
01368 delx = (cbox.UR.x - cbox.LL.x) - oldsz.x;
01369
01370
01371
01372 if ((delx > 0)&&((af=(cp->data.flags & HALIGN_MASK)) != HALIGN_TEXT)) {
01373 switch (af) {
01374 case HALIGN_LEFT:
01375 cbox.UR.x -= delx;
01376 break;
01377 case HALIGN_RIGHT:
01378 cbox.LL.x += delx;
01379 break;
01380 default:
01381 cbox.LL.x += delx / 2;
01382 cbox.UR.x -= delx / 2;
01383 break;
01384 }
01385 }
01386
01387 dely = (cbox.UR.y - cbox.LL.y) - oldsz.y;
01388 if (dely > 0) {
01389 switch (cp->data.flags & VALIGN_MASK) {
01390 case VALIGN_BOTTOM:
01391 cbox.UR.y -= dely;
01392 break;
01393 case VALIGN_TOP:
01394 cbox.LL.y += dely;
01395 break;
01396 default:
01397 cbox.LL.y += dely / 2;
01398 cbox.UR.y -= dely / 2;
01399 break;
01400 }
01401 }
01402 cp->child.u.txt->box = cbox;
01403
01404
01405
01406 switch (cp->data.flags & BALIGN_MASK) {
01407 case BALIGN_LEFT:
01408 dfltalign = 'l';
01409 break;
01410 case BALIGN_RIGHT:
01411 dfltalign = 'r';
01412 break;
01413 default:
01414 dfltalign = 'n';
01415 break;
01416 }
01417 pos_html_txt (cp->child.u.txt, dfltalign);
01418 }
01419 }
01420
01421
01422
01423
01424
01425
01426
01427 static void pos_html_tbl(htmltbl_t * tbl, box pos, int sides)
01428 {
01429 int x, y, delx, dely;
01430 int i, plus, extra, oldsz;
01431 htmlcell_t **cells = tbl->u.n.cells;
01432 htmlcell_t *cp;
01433 box cbox;
01434
01435 if (tbl->u.n.parent && !tbl->data.pencolor)
01436 tbl->data.pencolor = tbl->u.n.parent->data.pencolor;
01437
01438 oldsz = tbl->data.box.UR.x;
01439 delx = (pos.UR.x - pos.LL.x) - oldsz;
01440 assert(delx >= 0);
01441 oldsz = tbl->data.box.UR.y;
01442 dely = (pos.UR.y - pos.LL.y) - oldsz;
01443 assert(dely >= 0);
01444
01445
01446 if (tbl->data.flags & FIXED_FLAG) {
01447 if (delx > 0) {
01448 switch (tbl->data.flags & HALIGN_MASK) {
01449 case HALIGN_LEFT:
01450 pos.UR.x = pos.LL.x + oldsz;
01451 break;
01452 case HALIGN_RIGHT:
01453 pos.UR.x += delx;
01454 pos.LL.x += delx;
01455 break;
01456 default:
01457 pos.LL.x += delx / 2;
01458 pos.UR.x -= delx / 2;
01459 break;
01460 }
01461 delx = 0;
01462 }
01463 if (dely > 0) {
01464 switch (tbl->data.flags & VALIGN_MASK) {
01465 case VALIGN_BOTTOM:
01466 pos.UR.y = pos.LL.y + oldsz;
01467 break;
01468 case VALIGN_TOP:
01469 pos.UR.y += dely;
01470 pos.LL.y += dely;
01471 break;
01472 default:
01473 pos.LL.y += dely / 2;
01474 pos.UR.y -= dely / 2;
01475 break;
01476 }
01477 dely = 0;
01478 }
01479 }
01480
01481
01482 x = pos.LL.x + tbl->data.border + tbl->data.space;
01483 extra = delx / (tbl->cc);
01484 plus = delx - extra * (tbl->cc);
01485 for (i = 0; i <= tbl->cc; i++) {
01486 delx = tbl->widths[i] + extra + (i < plus ? 1 : 0);
01487 tbl->widths[i] = x;
01488 x += delx + tbl->data.space;
01489 }
01490 y = pos.UR.y - tbl->data.border - tbl->data.space;
01491 extra = dely / (tbl->rc);
01492 plus = dely - extra * (tbl->rc);
01493 for (i = 0; i <= tbl->rc; i++) {
01494 dely = tbl->heights[i] + extra + (i < plus ? 1 : 0);
01495 tbl->heights[i] = y;
01496 y -= dely + tbl->data.space;
01497 }
01498
01499 while ((cp = *cells++)) {
01500 int mask = 0;
01501 if (sides) {
01502 if (cp->col == 0) mask |= LEFT;
01503 if (cp->row == 0) mask |= TOP;
01504 if (cp->col + cp->cspan == tbl->cc) mask |= RIGHT;
01505 if (cp->row + cp->rspan == tbl->rc) mask |= BOTTOM;
01506 }
01507 cbox.LL.x = tbl->widths[cp->col];
01508 cbox.UR.x = tbl->widths[cp->col + cp->cspan] - tbl->data.space;
01509 cbox.UR.y = tbl->heights[cp->row];
01510 cbox.LL.y = tbl->heights[cp->row + cp->rspan] + tbl->data.space;
01511 pos_html_cell(cp, cbox, sides & mask);
01512 }
01513
01514 tbl->data.sides = sides;
01515 tbl->data.box = pos;
01516 }
01517
01518
01519
01520
01521
01522 static int
01523 size_html_tbl(graph_t *g, htmltbl_t * tbl, htmlcell_t * parent, htmlenv_t * env)
01524 {
01525 int i, wd, ht;
01526 int rv = 0;
01527 htmlfont_t savef;
01528
01529 if (tbl->font)
01530 pushFontInfo(env, tbl->font, &savef);
01531 tbl->u.n.parent = parent;
01532 rv = processTbl(g, tbl, env);
01533
01534
01535 if (!(tbl->data.flags & SPACE_SET)) {
01536 tbl->data.space = DEFAULT_CELLSPACING;
01537 }
01538 if (!(tbl->data.flags & BORDER_SET)) {
01539 tbl->data.border = DEFAULT_BORDER;
01540 }
01541
01542 sizeArray(tbl);
01543
01544 wd = (tbl->cc + 1) * tbl->data.space + 2 * tbl->data.border;
01545 ht = (tbl->rc + 1) * tbl->data.space + 2 * tbl->data.border;
01546 for (i = 0; i < tbl->cc; i++)
01547 wd += tbl->widths[i];
01548 for (i = 0; i < tbl->rc; i++)
01549 ht += tbl->heights[i];
01550
01551 if (tbl->data.flags & FIXED_FLAG) {
01552 if (tbl->data.width && tbl->data.height) {
01553 if ((tbl->data.width < wd) || (tbl->data.height < ht)) {
01554 agerr(AGWARN, "table size too small for content\n");
01555 rv = 1;
01556 }
01557 wd = ht = 0;
01558 } else {
01559 agerr(AGWARN,
01560 "fixed table size with unspecified width or height\n");
01561 rv = 1;
01562 }
01563 }
01564 tbl->data.box.UR.x = MAX(wd, tbl->data.width);
01565 tbl->data.box.UR.y = MAX(ht, tbl->data.height);
01566
01567 if (tbl->font)
01568 popFontInfo(env, &savef);
01569 return rv;
01570 }
01571
01572 static char *nameOf(void *obj, agxbuf * xb)
01573 {
01574 Agedge_t *ep;
01575 switch (agobjkind(obj)) {
01576 case AGGRAPH:
01577 agxbput(xb, ((Agraph_t *) obj)->name);
01578 break;
01579 case AGNODE:
01580 agxbput(xb, ((Agnode_t *) obj)->name);
01581 break;
01582 case AGEDGE:
01583 ep = (Agedge_t *) obj;
01584 agxbput(xb, ep->tail->name);
01585 agxbput(xb, ep->head->name);
01586 if (AG_IS_DIRECTED(ep->tail->graph))
01587 agxbput(xb, "->");
01588 else
01589 agxbput(xb, "--");
01590 break;
01591 }
01592 return agxbuse(xb);
01593 }
01594
01595 #ifdef DEBUG
01596 void indent(int i)
01597 {
01598 while (i--)
01599 fprintf(stderr, " ");
01600 }
01601
01602 void printBox(box b)
01603 {
01604 fprintf(stderr, "(%d,%d)(%d,%d)", b.LL.x, b.LL.y, b.UR.x, b.UR.y);
01605 }
01606
01607 void printImage(htmlimg_t *ip, int ind)
01608 {
01609 indent(ind);
01610 fprintf(stderr, "img: %s\n", ip->src);
01611 }
01612
01613 void printTxt(htmltxt_t * txt, int ind)
01614 {
01615 int i, j;
01616
01617 indent(ind);
01618 fprintf (stderr, "txt paras = %d \n", txt->nparas);
01619 for (i = 0; i < txt->nparas; i++) {
01620 indent(ind+1);
01621 fprintf (stderr, "[%d] %d items\n", i, txt->paras[i].nitems);
01622 for (j = 0; j < txt->paras[i].nitems; j++) {
01623 indent(ind+2);
01624 fprintf (stderr, "[%d] (%f) \"%s\" ",
01625 j, txt->paras[i].items[j].size,
01626 txt->paras[i].items[j].str);
01627 if (txt->paras[i].items[j].font)
01628 fprintf (stderr, "font %s color %s size %f\n",
01629 txt->paras[i].items[j].font->name,
01630 txt->paras[i].items[j].font->color,
01631 txt->paras[i].items[j].font->size);
01632 else fprintf (stderr, "\n");
01633 }
01634 }
01635 }
01636
01637 void printData(htmldata_t * dp)
01638 {
01639 unsigned char flags = dp->flags;
01640 char c;
01641
01642 fprintf(stderr, "s%d(%d) ", dp->space, (flags & SPACE_SET ? 1 : 0));
01643 fprintf(stderr, "b%d(%d) ", dp->border, (flags & BORDER_SET ? 1 : 0));
01644 fprintf(stderr, "p%d(%d) ", dp->pad, (flags & PAD_SET ? 1 : 0));
01645 switch (flags & HALIGN_MASK) {
01646 case HALIGN_RIGHT:
01647 c = 'r';
01648 break;
01649 case HALIGN_LEFT:
01650 c = 'l';
01651 break;
01652 default:
01653 c = 'n';
01654 break;
01655 }
01656 fprintf(stderr, "%c", c);
01657 switch (flags & VALIGN_MASK) {
01658 case VALIGN_TOP:
01659 c = 't';
01660 break;
01661 case VALIGN_BOTTOM:
01662 c = 'b';
01663 break;
01664 default:
01665 c = 'c';
01666 break;
01667 }
01668 fprintf(stderr, "%c ", c);
01669 printBox(dp->box);
01670 }
01671
01672 void printTbl(htmltbl_t * tbl, int ind)
01673 {
01674 htmlcell_t **cells = tbl->u.n.cells;
01675 indent(ind);
01676 fprintf(stderr, "tbl %d %d ", tbl->cc, tbl->rc);
01677 printData(&tbl->data);
01678 fputs("\n", stderr);
01679 while (*cells)
01680 printCell(*cells++, ind + 1);
01681 }
01682
01683 static void printCell(htmlcell_t * cp, int ind)
01684 {
01685 indent(ind);
01686 fprintf(stderr, "cell %d %d %d %d ", cp->cspan, cp->rspan, cp->col,
01687 cp->row);
01688 printData(&cp->data);
01689 fputs("\n", stderr);
01690 switch (cp->child.kind) {
01691 case HTML_TBL:
01692 printTbl(cp->child.u.tbl, ind + 1);
01693 break;
01694 case HTML_TEXT:
01695 printTxt(cp->child.u.txt, ind + 1);
01696 break;
01697 case HTML_IMAGE:
01698 printImage(cp->child.u.img, ind + 1);
01699 break;
01700 default:
01701 break;
01702 }
01703 }
01704
01705 void printLbl(htmllabel_t * lbl)
01706 {
01707 if (lbl->kind == HTML_TBL)
01708 printTbl(lbl->u.tbl, 0);
01709 else
01710 printTxt(lbl->u.txt, 0);
01711 }
01712 #endif
01713
01714 static char *getPenColor(void *obj)
01715 {
01716 char *str;
01717
01718 if (((str = agget(obj, "pencolor")) != 0) && str[0])
01719 return str;
01720 else if (((str = agget(obj, "color")) != 0) && str[0])
01721 return str;
01722 else
01723 return NULL;
01724 }
01725
01726
01727
01728
01729 int make_html_label(graph_t *g, textlabel_t * lp, void *obj)
01730 {
01731 int rv;
01732 int wd2, ht2;
01733 box box;
01734 htmllabel_t *lbl;
01735 htmlenv_t env;
01736
01737 env.obj = obj;
01738 switch (agobjkind(obj)) {
01739 case AGGRAPH:
01740 env.g = ((Agraph_t *) obj)->root;
01741 break;
01742 case AGNODE:
01743 env.g = ((Agnode_t *) obj)->graph;
01744 break;
01745 case AGEDGE:
01746 env.g = ((Agedge_t *) obj)->head->graph;
01747 break;
01748 }
01749 env.finfo.size = lp->fontsize;
01750 env.finfo.name = lp->fontname;
01751 env.finfo.color = lp->fontcolor;
01752 lbl = parseHTML(lp->text, &rv, GD_charset(env.g));
01753 if (!lbl) {
01754
01755 agxbuf xb;
01756 unsigned char buf[SMALLBUF];
01757 agxbinit(&xb, SMALLBUF, buf);
01758 lp->html = FALSE;
01759 lp->text = strdup(nameOf(obj, &xb));
01760 size_label(env.g, lp);
01761 agxbfree(&xb);
01762 return rv;
01763 }
01764
01765 if (lbl->kind == HTML_TBL) {
01766 lbl->u.tbl->data.pencolor = getPenColor(obj);
01767 rv |= size_html_tbl(g, lbl->u.tbl, NULL, &env);
01768 wd2 = (lbl->u.tbl->data.box.UR.x + 1) / 2;
01769 ht2 = (lbl->u.tbl->data.box.UR.y + 1) / 2;
01770 box = boxof(-wd2, -ht2, wd2, ht2);
01771 pos_html_tbl(lbl->u.tbl, box, BOTTOM | RIGHT | TOP | LEFT);
01772 lp->dimen.x = box.UR.x - box.LL.x;
01773 lp->dimen.y = box.UR.y - box.LL.y;
01774 } else {
01775 rv |= size_html_txt(g, lbl->u.txt, &env);
01776 wd2 = (lbl->u.txt->box.UR.x + 1) / 2;
01777 ht2 = (lbl->u.txt->box.UR.y + 1) / 2;
01778 box = boxof(-wd2, -ht2, wd2, ht2);
01779 lbl->u.txt->box = box;
01780 lp->dimen.x = box.UR.x - box.LL.x;
01781 lp->dimen.y = box.UR.y - box.LL.y;
01782 }
01783
01784 lp->u.html = lbl;
01785
01786
01787
01788
01789 if (lbl->kind == HTML_TBL) {
01790 free (lp->text);
01791 lp->text = strdup ("<TABLE>");
01792 }
01793
01794 return rv;
01795 }
01796