#pragma prototyped
#include "render.h"
#include "htmltable.h"
#include "agxbuf.h"
#include "pointset.h"
#include "utils.h"
#include <assert.h>
#define DEFAULT_BORDER 1
#define DEFAULT_CELLPADDING 2
#define DEFAULT_CELLSPACING 2
typedef struct {
textlabel_t* lp;
void* obj;
} htmlenv_t;
static void
emit_html_txt (GVC_t *gvc, htmltxt_t* tp, htmlenv_t* env)
{
textlabel_t* lp = env->lp;
int i, linespacing, left_x, center_x, right_x;
point p;
if (tp->nlines < 1) return;
left_x = tp->box.LL.x + lp->p.x;
right_x = tp->box.UR.x + lp->p.x;
center_x = (left_x + right_x)/2;
linespacing = (int)(lp->fontsize * LINESPACING);
p.y = lp->p.y + (tp->box.UR.y + tp->box.LL.y)/2
+ (linespacing * (tp->nlines -1) / 2)
- lp->fontsize / 3.0 ;
gvrender_begin_context(gvc);
gvrender_set_pencolor(gvc, lp->fontcolor);
gvrender_set_font(gvc, lp->fontname, lp->fontsize*GD_drawing(gvc->g)->font_scale_adj);
for (i = 0; i < tp->nlines; i++) {
switch(tp->line[i].just) {
case 'l':
p.x = left_x;
break;
case 'r':
p.x = right_x;
break;
default:
case 'n':
p.x = center_x;
break;
}
gvrender_textline(gvc, p, &(tp->line[i]));
p.y -= linespacing;
}
gvrender_end_context(gvc);
}
static void
doSide (GVC_t *gvc, point p, int wd, int ht)
{
point A[4];
A[0] = p;
A[1].x = p.x;
A[1].y = p.y + ht;
A[2].y = A[1].y;
A[2].x = p.x + wd;
A[3].x = A[2].x;
A[3].y = p.y;
gvrender_polygon(gvc, A, 4, 1);
}
static void
doBorder (GVC_t *gvc, char* color, int border, box pts)
{
point pt;
int wd, ht;
gvrender_begin_context(gvc);
if (!color) color = "black";
gvrender_set_fillcolor(gvc, color);
gvrender_set_pencolor(gvc, color);
if (border == 1) {
point A[4];
A[0] = pts.LL;
A[2] = pts.UR;
A[1].x = A[0].x;
A[1].y = A[2].y;
A[3].x = A[2].x;
A[3].y = A[0].y;
gvrender_polygon(gvc, A, 4, 0);
}
else {
border--;
ht = pts.UR.y - pts.LL.y;
wd = pts.UR.x - pts.LL.x;
doSide (gvc, pts.LL, border, ht);
pt.x= pts.LL.x;
pt.y= pts.UR.y;
doSide (gvc, pt, wd, -border);
doSide (gvc, pts.UR, -border, -ht);
pt.x= pts.UR.x;
pt.y= pts.LL.y;
doSide (gvc, pt, -wd, border);
}
gvrender_end_context(gvc);
}
static void
doFill (GVC_t *gvc, char* color, box pts)
{
point A[4];
gvrender_set_fillcolor(gvc, color);
gvrender_set_pencolor(gvc, color);
A[0] = pts.LL;
A[1].x = pts.LL.x;
A[1].y = pts.UR.y;
A[2] = pts.UR;
A[3].x = pts.UR.x;
A[3].y = pts.LL.y;
gvrender_polygon(gvc, A, 4, 1);
}
static void emit_html_cell (GVC_t *gvc, htmlcell_t*, htmlenv_t*);
static void
emit_html_tbl (GVC_t *gvc, htmltbl_t* tbl, htmlenv_t* env)
{
box pts = tbl->data.box;
point p = env->lp->p;
htmlcell_t** cells = tbl->u.n.cells;
pts.LL.x += p.x;
pts.UR.x += p.x;
pts.LL.y += p.y;
pts.UR.y += p.y;
if (tbl->data.bgcolor)
doFill (gvc, tbl->data.bgcolor, pts);
while (*cells) {
emit_html_cell (gvc, *cells, env);
cells++;
}
if (tbl->data.border)
doBorder (gvc, NULL, tbl->data.border, pts);
}
static void
emit_html_cell (GVC_t *gvc, htmlcell_t* cp, htmlenv_t* env)
{
box pts = cp->data.box;
point p = env->lp->p;
pts.LL.x += p.x;
pts.UR.x += p.x;
pts.LL.y += p.y;
pts.UR.y += p.y;
if (cp->data.bgcolor)
doFill (gvc, cp->data.bgcolor, pts);
if (cp->child.kind == HTML_TBL)
emit_html_tbl (gvc, cp->child.u.tbl, env);
else
emit_html_txt (gvc, cp->child.u.txt, env);
if (cp->data.border)
doBorder (gvc, NULL, cp->data.border, pts);
}
void
emit_html_label(GVC_t *gvc, htmllabel_t* lp, textlabel_t* tp)
{
htmlenv_t env;
env.lp = tp;
if (lp->kind == HTML_TBL) {
htmltbl_t* tbl = lp->u.tbl;
gvrender_begin_context(gvc);
gvrender_set_style(gvc, BaseLineStyle);
if (tbl->data.pencolor)
gvrender_set_pencolor(gvc, tbl->data.pencolor);
else
gvrender_set_pencolor(gvc, DEFAULT_COLOR);
emit_html_tbl (gvc, tbl, &env);
gvrender_end_context(gvc);
}
else {
emit_html_txt (gvc, lp->u.txt, &env);
}
}
void
free_html_data (htmldata_t* dp)
{
free (dp->href);
free (dp->port);
free (dp->bgcolor);
}
void
free_html_text (htmltxt_t* tp)
{
textline_t* lp;
if (!tp) return;
lp = tp->line;
while (lp->str) {
free (lp->str);
lp++;
}
free(tp->line);
free(tp);
}
static void
free_html_cell (htmlcell_t* cp)
{
free_html_label (&cp->child, 0);
free_html_data (&cp->data);
free (cp);
}
static void
free_html_tbl (htmltbl_t* tbl)
{
htmlcell_t** cells;
if (tbl->rc == -1) {
dtclose (tbl->u.p.rows);
}
else {
cells = tbl->u.n.cells;
free (tbl->heights);
free (tbl->widths);
while (*cells) {
free_html_cell (*cells);
cells++;
}
free (tbl->u.n.cells);
}
free_html_data (&tbl->data);
free (tbl);
}
void
free_html_label (htmllabel_t* lp, int root)
{
if (lp->kind == HTML_TBL)
free_html_tbl (lp->u.tbl);
else
free_html_text (lp->u.txt);
if (root) free (lp);
}
static box* portToTbl (htmltbl_t*, char*);
static box*
portToCell (htmlcell_t* cp, char *id)
{
box* rv;
if (cp->data.port && (strcasecmp (cp->data.port, id) == 0))
rv = &cp->data.box;
else if (cp->child.kind == HTML_TBL)
rv = portToTbl (cp->child.u.tbl, id);
else
rv = NULL;
return rv;
}
static box*
portToTbl (htmltbl_t* tp, char *id)
{
box* rv;
htmlcell_t** cells;
htmlcell_t* cp;
if (tp->data.port && (strcasecmp (tp->data.port, id) == 0))
rv = &tp->data.box;
else {
rv = NULL;
cells = tp->u.n.cells;
while ((cp = *cells++)) {
if ((rv = portToCell (cp, id))) break;
}
}
return rv;
}
int
html_port (node_t* n, char* pname, port* pp)
{
box* bp;
box b;
port rv;
htmllabel_t* lbl = ND_label(n)->u.html;
if ((lbl->kind == HTML_TEXT) ||
((bp = portToTbl (lbl->u.tbl, pname)) == NULL)) {
return 0;
}
b = *bp;
rv.p = pointof ((b.LL.x + b.UR.x) / 2, (b.LL.y + b.UR.y) / 2);
if (GD_left_to_right(n->graph)) rv.p = invflip_pt(rv.p);
rv.order = (MC_SCALE * (ND_lw_i(n) + rv.p.x)) / (ND_lw_i(n) + ND_rw_i(n));
rv.bp = bp;
rv.constrained = FALSE;
rv.defined = TRUE;
*pp = rv;
return 1;
}
int
html_path (node_t* n, edge_t* e, int pt, box* rv, int* k)
{
#ifdef UNIMPL
point p;
tbl_t* info;
tbl_t* t;
box b;
int i;
info = (tbl_t*) ND_shape_info(n);
assert (info->tbls);
info = info->tbls[0];
assert (IS_FLOW(info));
b = info->box;
if (info->tbl) {
info = info->tbl;
if (pt == 1) p = ED_tail_port(e).p;
else p = ED_head_port(e).p;
if (GD_left_to_right(n->graph))
p = flip_pt (p);
for (i = 0; (t = info->tbls[i]) != 0; i++)
if (INSIDE(p,t->box)) {
b = t->box;
break;
}
}
if (GD_left_to_right(n->graph))
b = flip_trans_box(b,ND_coord_i(n));
else
b = move_box(b,ND_coord_i(n));
*k = 1;
*rv = b;
if (pt == 1) return BOTTOM;
else return TOP;
#endif
return 0;
}
int
size_html_txt (GVC_t *gvc, htmltxt_t* txt, htmlenv_t* env)
{
double xsize = 0.0;
double fsize = env->lp->fontsize;
char* fname = env->lp->fontname;
char* news = NULL;
int width;
textline_t* lp = txt->line;
while (lp->str) {
switch (agobjkind(env->obj)) {
case AGGRAPH:
news = strdup_and_subst_graph(lp->str, (Agraph_t*)(env->obj));
break;
case AGNODE:
news = strdup_and_subst_node(lp->str, (Agnode_t*)(env->obj));
break;
case AGEDGE:
news = strdup_and_subst_edge(lp->str, (Agedge_t*)(env->obj));
break;
}
free (lp->str);
lp->str = news;
width = textwidth (gvc, news, fname, fsize);
lp->width = width;
width += 2;
if (width > xsize) xsize = width;
lp++;
}
txt->box.UR.x = xsize;
txt->box.UR.y = txt->nlines*(int)(fsize*LINESPACING) + 2;
return 0;
}
static int size_html_tbl (GVC_t *gvc, htmltbl_t* tbl, htmlcell_t* parent, htmlenv_t* env);
static int
size_html_cell (GVC_t *gvc, htmlcell_t* cp, htmltbl_t* parent, htmlenv_t* env)
{
int rv;
point sz, child_sz;
int margin;
cp->parent = parent;
if (!(cp->data.flags & PAD_SET)) {
if (parent->data.flags & PAD_SET)
cp->data.pad = parent->data.pad;
else
cp->data.pad = DEFAULT_CELLPADDING;
}
if (!(cp->data.flags & BORDER_SET)) {
if (parent->cb >= 0)
cp->data.border = parent->cb;
else if (parent->data.flags & BORDER_SET)
cp->data.border = parent->data.border;
else
cp->data.border = DEFAULT_BORDER;
}
if (cp->child.kind == HTML_TBL) {
rv = size_html_tbl (gvc, cp->child.u.tbl, cp, env);
child_sz = cp->child.u.tbl->data.box.UR;
}
else {
rv = size_html_txt (gvc, cp->child.u.txt, env);
child_sz = cp->child.u.txt->box.UR;
}
margin = 2*(cp->data.pad + cp->data.border);
sz.x = child_sz.x + margin;
sz.y = child_sz.y + margin;
if (cp->data.flags & FIXED_FLAG) {
if (cp->data.width && cp->data.height) {
if ((cp->data.width < sz.x) || (cp->data.height < sz.y)) {
agerr(AGWARN, "cell size too small for content\n");
rv = 1;
}
sz.x = sz.y = 0;
}
else {
agerr(AGWARN, "fixed cell size with unspecified width or height\n");
rv = 1;
}
}
cp->data.box.UR.x = MAX(sz.x, cp->data.width);
cp->data.box.UR.y = MAX(sz.y, cp->data.height);
return rv;
}
static int
findCol (PointSet* ps, int row, int col, htmlcell_t* cellp)
{
int notFound = 1;
int lastc;
int i, j, c;
int end = cellp->cspan-1;
while (notFound) {
lastc = col+end;
for (c = lastc; c >= col; c--) {
if (isInPS(ps,c,row)) break;
}
if (c >= col)
col = c+1;
else
notFound = 0;
}
for (j = col; j < col+cellp->cspan; j++) {
for (i = row; i < row+cellp->rspan; i++) {
addPS (ps, j, i);
}
}
return col;
}
static int
processTbl (GVC_t *gvc, htmltbl_t* tbl, htmlenv_t* env)
{
pitem* rp;
pitem* cp;
Dt_t* cdict;
int r,c,cnt;
htmlcell_t* cellp;
htmlcell_t** cells;
Dt_t* rows = tbl->u.p.rows;
int rv = 0;
int n_rows = 0;
int n_cols = 0;
PointSet* ps = newPS();
rp = (pitem*)dtflatten(rows);
cnt = 0;
while (rp) {
cdict = rp->u.rp;
cp = (pitem*)dtflatten(cdict);
while (cp) {
cellp = cp->u.cp;
cnt++;
cp = (pitem*)dtlink(cdict,(Dtlink_t*)cp);
}
rp = (pitem*)dtlink(rows,(Dtlink_t*)rp);
}
cells = tbl->u.n.cells = N_NEW(cnt+1,htmlcell_t*);
rp = (pitem*)dtflatten(rows);
r = 0;
while (rp) {
cdict = rp->u.rp;
cp = (pitem*)dtflatten(cdict);
c = 0;
while (cp) {
cellp = cp->u.cp;
*cells++ = cellp;
rv |= size_html_cell (gvc, cellp, tbl, env);
c = findCol (ps, r, c, cellp);
cellp->row = r;
cellp->col = c;
c += cellp->cspan;
n_cols = MAX(c, n_cols);
n_rows = MAX(r+cellp->rspan, n_rows);
cp = (pitem*)dtlink(cdict,(Dtlink_t*)cp);
}
rp = (pitem*)dtlink(rows,(Dtlink_t*)rp);
r++;
}
tbl->rc = n_rows;
tbl->cc = n_cols;
dtclose (rows);
freePS(ps);
return rv;
}
#define SPLIT(x,n,s) (((x) - ((s)-1)*((n)-1)) / (n))
void
sizeArray (htmltbl_t* tbl)
{
htmlcell_t* cp;
htmlcell_t** cells;
int wd, ht, i, x, y;
tbl->heights = N_NEW (tbl->rc+1, int);
tbl->widths = N_NEW (tbl->cc+1, int);
for (cells = tbl->u.n.cells; *cells; cells++) {
cp = *cells;
if (cp->rspan == 1)
ht = cp->data.box.UR.y;
else {
ht = SPLIT(cp->data.box.UR.y,cp->rspan,tbl->data.space);
ht = MAX(ht,1);
}
if (cp->cspan == 1)
wd = cp->data.box.UR.x;
else {
wd = SPLIT(cp->data.box.UR.x,cp->cspan,tbl->data.space);
wd = MAX(wd,1);
}
for (i = cp->row; i < cp->row + cp->rspan; i++) {
y = tbl->heights[i];
tbl->heights[i] = MAX(y,ht);
}
for (i = cp->col; i < cp->col + cp->cspan; i++) {
x = tbl->widths[i];
tbl->widths[i] = MAX(x,wd);
}
}
}
static void pos_html_tbl (htmltbl_t*, box);
static void
pos_html_cell (htmlcell_t* cp, box pos)
{
int delx, dely;
point oldsz;
box cbox;
if (cp->data.flags & FIXED_FLAG) {
oldsz = cp->data.box.UR;
delx = (pos.UR.x - pos.LL.x) - oldsz.x;
if (delx > 0) {
switch (cp->data.flags & HALIGN_MASK) {
case HALIGN_LEFT :
pos.UR.x = pos.LL.x + oldsz.x;
break;
case HALIGN_RIGHT :
pos.UR.x += delx;
pos.LL.x += delx;
break;
default :
pos.LL.x += delx/2;
pos.UR.x -= delx/2;
break;
}
}
dely = (pos.UR.y - pos.LL.y) - oldsz.y;
if (dely > 0) {
switch (cp->data.flags & VALIGN_MASK) {
case VALIGN_BOTTOM :
pos.UR.y = pos.LL.y + oldsz.y;
break;
case VALIGN_TOP :
pos.UR.y += dely;
pos.LL.y += dely;
break;
default :
pos.LL.y += dely/2;
pos.UR.y -= dely/2;
break;
}
}
}
cp->data.box = pos;
cbox.LL.x = pos.LL.x + cp->data.border + cp->data.pad;
cbox.LL.y = pos.LL.y + cp->data.border + cp->data.pad;
cbox.UR.x = pos.UR.x - cp->data.border - cp->data.pad;
cbox.UR.y = pos.UR.y - cp->data.border - cp->data.pad;
if (cp->child.kind == HTML_TBL) {
pos_html_tbl (cp->child.u.tbl, cbox);
}
else {
oldsz = cp->child.u.txt->box.UR;
delx = (cbox.UR.x - cbox.LL.x) - oldsz.x;
if (delx > 0) {
switch (cp->data.flags & HALIGN_MASK) {
case HALIGN_LEFT :
cbox.UR.x -= delx;
break;
case HALIGN_RIGHT :
cbox.LL.x += delx;
break;
default :
cbox.LL.x += delx/2;
cbox.UR.x -= delx/2;
break;
}
}
dely = (cbox.UR.y - cbox.LL.y) - oldsz.y;
if (dely > 0) {
switch (cp->data.flags & VALIGN_MASK) {
case VALIGN_BOTTOM :
cbox.UR.y -= dely;
break;
case VALIGN_TOP :
cbox.LL.y += dely;
break;
default :
cbox.LL.y += dely/2;
cbox.UR.y -= dely/2;
break;
}
}
cp->child.u.txt->box = cbox;
}
}
static void
pos_html_tbl (htmltbl_t* tbl, box pos)
{
int x, y, delx, dely;
int i, plus, extra, oldsz;
htmlcell_t** cells = tbl->u.n.cells;
htmlcell_t* cp;
box cbox;
oldsz = tbl->data.box.UR.x;
delx = (pos.UR.x - pos.LL.x) - oldsz;
assert (delx >= 0);
oldsz = tbl->data.box.UR.y;
dely = (pos.UR.y - pos.LL.y) - oldsz;
assert (dely >= 0);
if (tbl->data.flags & FIXED_FLAG) {
if (delx > 0) {
switch (tbl->data.flags & HALIGN_MASK) {
case HALIGN_LEFT :
pos.UR.x = pos.LL.x + oldsz;
break;
case HALIGN_RIGHT :
pos.UR.x += delx;
pos.LL.x += delx;
break;
default :
pos.LL.x += delx/2;
pos.UR.x -= delx/2;
break;
}
delx = 0;
}
if (dely > 0) {
switch (tbl->data.flags & VALIGN_MASK) {
case VALIGN_BOTTOM :
pos.UR.y = pos.LL.y + oldsz;
break;
case VALIGN_TOP :
pos.UR.y += dely;
pos.LL.y += dely;
break;
default :
pos.LL.y += dely/2;
pos.UR.y -= dely/2;
break;
}
dely = 0;
}
}
x = pos.LL.x + tbl->data.border + tbl->data.space;
extra = delx/(tbl->cc);
plus = delx - extra*(tbl->cc);
for (i = 0; i <= tbl->cc; i++) {
delx = tbl->widths[i] + extra + (i<plus?1:0);
tbl->widths[i] = x;
x += delx + tbl->data.space;
}
y = pos.UR.y - tbl->data.border - tbl->data.space;
extra = dely/(tbl->rc);
plus = dely - extra*(tbl->rc);
for (i = 0; i <= tbl->rc; i++) {
dely = tbl->heights[i] + extra + (i<plus?1:0);
tbl->heights[i] = y;
y -= dely + tbl->data.space;
}
while ((cp = *cells++)) {
cbox.LL.x = tbl->widths[cp->col];
cbox.UR.x = tbl->widths[cp->col+cp->cspan] - tbl->data.space;
cbox.UR.y = tbl->heights[cp->row];
cbox.LL.y = tbl->heights[cp->row+cp->rspan] + tbl->data.space;
pos_html_cell (cp, cbox);
}
tbl->data.box = pos;
}
static int
size_html_tbl (GVC_t *gvc, htmltbl_t* tbl, htmlcell_t* parent, htmlenv_t* env)
{
int i, wd, ht;
int rv = 0;
tbl->u.n.parent = parent;
rv = processTbl (gvc, tbl, env);
if (!(tbl->data.flags & SPACE_SET)) {
tbl->data.space = DEFAULT_CELLSPACING;
}
if (!(tbl->data.flags & BORDER_SET)) {
tbl->data.border = DEFAULT_BORDER;
}
sizeArray (tbl);
wd = (tbl->cc + 1)*tbl->data.space + 2*tbl->data.border;
ht = (tbl->rc + 1)*tbl->data.space + 2*tbl->data.border;
for (i = 0; i < tbl->cc; i++)
wd += tbl->widths[i];
for (i = 0; i < tbl->rc; i++)
ht += tbl->heights[i];
if (tbl->data.flags & FIXED_FLAG) {
if (tbl->data.width && tbl->data.height) {
if ((tbl->data.width < wd) || (tbl->data.height < ht)) {
agerr(AGWARN, "table size too small for content\n");
rv = 1;
}
wd = ht = 0;
}
else {
agerr(AGWARN, "fixed table size with unspecified width or height\n");
rv = 1;
}
}
tbl->data.box.UR.x = MAX(wd, tbl->data.width);
tbl->data.box.UR.y = MAX(ht, tbl->data.height);
return rv;
}
static char*
nameOf (void* obj, agxbuf* xb)
{
Agedge_t* ep;
switch (agobjkind(obj)) {
case AGGRAPH: agxbput (xb, ((Agraph_t*)obj)->name); break;
case AGNODE: agxbput (xb, ((Agnode_t*)obj)->name); break;
case AGEDGE:
ep = (Agedge_t*)obj;
agxbput(xb, ep->tail->name);
agxbput(xb, ep->head->name);
if (AG_IS_DIRECTED(ep->tail->graph)) agxbput (xb, "->");
else agxbput (xb, "--");
break;
}
return agxbuse(xb);
}
#ifdef DEBUG
void
indent (int i)
{
while (i--)
fprintf (stderr, " ");
}
void
printBox (box b)
{
fprintf (stderr, "(%d,%d)(%d,%d)", b.LL.x, b.LL.y, b.UR.x, b.UR.y);
}
void
printTxt (htmltxt_t* tp, int ind)
{
int i;
indent (ind);
fprintf (stderr, "txt ");
printBox (tp->box);
fputs ("\n", stderr);
for (i = 0; i < tp->nlines; i++) {
indent (ind+1);
fprintf (stderr, "(%c) \"%s\"\n", tp->line[i].just, tp->line[i].str);
}
}
void
printData (htmldata_t* dp)
{
unsigned char flags = dp->flags;
char c;
fprintf (stderr, "s%d(%d) ", dp->space, (flags & SPACE_SET ? 1 : 0));
fprintf (stderr, "b%d(%d) ", dp->border, (flags & BORDER_SET ? 1 : 0));
fprintf (stderr, "p%d(%d) ", dp->pad, (flags & PAD_SET ? 1 : 0));
switch (flags & HALIGN_MASK) {
case HALIGN_RIGHT :
c = 'r';
break;
case HALIGN_LEFT :
c = 'l';
break;
default :
c = 'c';
break;
}
fprintf (stderr, "%c", c);
switch (flags & VALIGN_MASK) {
case VALIGN_TOP :
c = 't';
break;
case VALIGN_BOTTOM :
c = 'b';
break;
default :
c = 'c';
break;
}
fprintf (stderr, "%c ", c);
printBox (dp->box);
}
void printCell (htmlcell_t* cp, int ind);
void
printTbl (htmltbl_t* tbl, int ind)
{
htmlcell_t** cells = tbl->u.n.cells;
indent (ind);
fprintf(stderr, "tbl %d %d ", tbl->cc, tbl->rc);
printData (&tbl->data);
fputs ("\n", stderr);
while (*cells)
printCell (*cells++, ind+1);
}
void
printCell (htmlcell_t* cp, int ind)
{
indent (ind);
fprintf(stderr, "cell %d %d %d %d ", cp->cspan, cp->rspan, cp->col, cp->row);
printData (&cp->data);
fputs ("\n", stderr);
if (cp->child.kind == HTML_TBL)
printTbl (cp->child.u.tbl, ind+1);
else
printTxt (cp->child.u.txt, ind+1);
}
void
printLbl (htmllabel_t* lbl)
{
if (lbl->kind == HTML_TBL)
printTbl (lbl->u.tbl, 0);
else
printTxt (lbl->u.txt, 0);
}
#endif
static char*
getPenColor (void* obj)
{
char* str;
if (((str = agget(obj,"pencolor")) != 0) && str[0])
return str;
else if (((str = agget(obj,"color")) != 0) && str[0])
return str;
else
return NULL;
}
int
make_html_label(GVC_t *gvc, textlabel_t *lp, void* obj)
{
int rv;
int wd2, ht2;
box box;
htmllabel_t* lbl = parseHTML (lp->text, &rv);
htmlenv_t env;
if (!lbl) {
agxbuf xb;
unsigned char buf[SMALLBUF];
agxbinit (&xb, SMALLBUF, buf);
lbl = parseHTML (nameOf (obj, &xb),&rv);
assert (lbl);
rv = 1;
agxbfree (&xb);
}
env.lp = lp;
env.obj = obj;
if (lbl->kind == HTML_TBL) {
lbl->u.tbl->data.pencolor = getPenColor (obj);
rv |= size_html_tbl (gvc, lbl->u.tbl, NULL, &env);
wd2 = (lbl->u.tbl->data.box.UR.x +1)/2;
ht2 = (lbl->u.tbl->data.box.UR.y +1)/2;
box = boxof (-wd2, -ht2, wd2, ht2);
pos_html_tbl (lbl->u.tbl, box);
lp->dimen.x = PS2INCH (box.UR.x - box.LL.x);
lp->dimen.y = PS2INCH (box.UR.y - box.LL.y);
}
else {
rv |= size_html_txt (gvc, lbl->u.txt, &env);
wd2 = (lbl->u.txt->box.UR.x +1)/2;
ht2 = (lbl->u.txt->box.UR.y +1)/2;
box = boxof (-wd2, -ht2, wd2, ht2);
lbl->u.txt->box = box;
lp->dimen.x = PS2INCH (box.UR.x - box.LL.x);
lp->dimen.y = PS2INCH (box.UR.y - box.LL.y);
}
lp->u.html = lbl;
return rv;
}