From: erg Date: Fri, 3 Mar 2006 03:22:43 +0000 (+0000) Subject: New HTML code to support font changes in running text, plus attribute X-Git-Tag: LAST_LIBGRAPH~32^2~6767 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3c94e1c45817054fe4fd1a58280ae76c815a6c4d;p=graphviz New HTML code to support font changes in running text, plus attribute extensions to make it easier to specify text alignment using the entire cell width. --- diff --git a/lib/common/htmllex.c b/lib/common/htmllex.c index 5d5b77c58..a43d6dd71 100644 --- a/lib/common/htmllex.c +++ b/lib/common/htmllex.c @@ -251,6 +251,38 @@ static int halignfn(htmldata_t * p, char *v) return rv; } +static int cell_halignfn(htmldata_t * p, char *v) +{ + int rv = 0; + char c = toupper(*v); + if ((c == 'L') && !strcasecmp(v + 1, "EFT")) + p->flags |= HALIGN_LEFT; + else if ((c == 'R') && !strcasecmp(v + 1, "IGHT")) + p->flags |= HALIGN_RIGHT; + else if ((c == 'T') && !strcasecmp(v + 1, "EXT")) + p->flags |= HALIGN_TEXT; + else if ((c != 'C') || strcasecmp(v + 1, "ENTER")) + rv = 1; + if (rv) + agerr(AGWARN, "Illegal value %s for ALIGN in TD - ignored\n", v); + return rv; +} + +static int balignfn(htmldata_t * p, char *v) +{ + int rv = 0; + char c = toupper(*v); + if ((c == 'L') && !strcasecmp(v + 1, "EFT")) + p->flags |= BALIGN_LEFT; + else if ((c == 'R') && !strcasecmp(v + 1, "IGHT")) + p->flags |= BALIGN_RIGHT; + else if ((c != 'C') || strcasecmp(v + 1, "ENTER")) + rv = 1; + if (rv) + agerr(AGWARN, "Illegal value %s for BALIGN in TD - ignored\n", v); + return rv; +} + static int heightfn(htmldata_t * p, char *v) { long u; @@ -335,7 +367,9 @@ static int alignfn(int *p, char *v) *p = 'r'; else if ((c == 'L') || !strcasecmp(v + 1, "EFT")) *p = 'l'; - else if ((c != 'C') && strcasecmp(v + 1, "ENTER")) { + else if ((c == 'C') || strcasecmp(v + 1, "ENTER")) + *p = 'n'; + else { agerr(AGWARN, "Illegal value %s for ALIGN - ignored\n", v); rv = 1; } @@ -362,7 +396,8 @@ static attr_item tbl_items[] = { }; static attr_item cell_items[] = { - {"align", (attrFn) halignfn}, + {"align", (attrFn) cell_halignfn}, + {"balign", (attrFn) balignfn}, {"bgcolor", (attrFn) bgcolorfn}, {"border", (attrFn) borderfn}, {"cellpadding", (attrFn) cellpaddingfn}, @@ -426,7 +461,7 @@ doAttrs(void *tp, attr_item * items, int nel, char **atts, char *s) static void mkBR(char **atts) { - htmllval.i = 'n'; + htmllval.i = UNSET_ALIGN; doAttrs(&htmllval.i, br_items, sizeof(br_items) / ISIZE, atts, "
"); } @@ -541,16 +576,18 @@ static void endElement(void *user, const char *name) static void characterData(void *user, const char *s, int length) { int i; + int cnt = 0; unsigned char c; if (state.inCell) { for (i = length; i; i--) { c = *s++; if (c >= ' ') { + cnt++; agxbputc(state.xb, c); } } - state.tok = T_string; + if (cnt) state.tok = T_string; } } #endif diff --git a/lib/common/htmlparse.y b/lib/common/htmlparse.y index c2e65a742..de2025706 100644 --- a/lib/common/htmlparse.y +++ b/lib/common/htmlparse.y @@ -22,11 +22,21 @@ extern int yyparse(void); +typedef struct sfont_t { + htmlfont_t *cfont; + struct sfont_t *pfont; +} sfont_t; + static struct { htmllabel_t* lbl; /* Generated label */ htmltbl_t* tblstack; /* Stack of tables maintained during parsing */ +#ifdef OLD Dt_t* lines; /* Dictionary for lines of text */ +#endif + Dt_t* fitemList; /* Dictionary for font text items */ + Dt_t* flineList; agxbuf* str; /* Buffer for text */ + sfont_t* fontstack; } HTMLstate; /* free_ritem: @@ -40,12 +50,12 @@ free_ritem(Dt_t* d, pitem* p,Dtdisc_t* ds) free (p); } -/* free_ritem: - * Free cell item after cell has been copies into final table. - * Only the pitem is freed. +/* free_item: + * Generic Dt free. Only frees container, assuming contents + * have been copied elsewhere. */ static void -free_item(Dt_t* d, pitem* p,Dtdisc_t* ds) +free_item(Dt_t* d, void* p,Dtdisc_t* ds) { free (p); } @@ -106,18 +116,61 @@ static Dtdisc_t cellDisc = { NIL(Dtevent_f) }; +#ifdef OLD typedef struct { Dtlink_t link; const char* s; /* line of text */ char c; /* alignment of text */ } sitem; +#endif + +typedef struct { + Dtlink_t link; + textitem_t ti; +} fitem; + +typedef struct { + Dtlink_t link; + htextline_t lp; +} fline; +#ifdef OLD static void -free_sitem(Dt_t* d,sitem* p,Dtdisc_t* ds) +free_sitem(Dt_t* d, sitem* p,Dtdisc_t* ds) { free (p); } +#endif + +static void +free_fitem(Dt_t* d, fitem* p, Dtdisc_t* ds) +{ + if (p->ti.str) + free (p->ti.str); + if (p->ti.font) + free_html_font (p->ti.font); + free (p); +} + +static void +free_fline(Dt_t* d, fline* p, Dtdisc_t* ds) +{ + textitem_t* ti; + + if (p->lp.nitems) { + int i; + ti = p->lp.items; + for (i = 0; i < p->lp.nitems; i++) { + if (ti->str) free (ti->str); + if (ti->font) free_html_font (ti->font); + ti++; + } + free (p->lp.items); + } + free (p); +} +#ifdef OLD static Dtdisc_t strDisc = { offsetof(sitem,s), sizeof(char*), @@ -129,7 +182,34 @@ static Dtdisc_t strDisc = { NIL(Dtmemory_f), NIL(Dtevent_f) }; +#endif + +static Dtdisc_t fstrDisc = { + 0, + 0, + offsetof(fitem,link), + NIL(Dtmake_f), + (Dtfree_f)free_item, + NIL(Dtcompar_f), + NIL(Dthash_f), + NIL(Dtmemory_f), + NIL(Dtevent_f) +}; + +static Dtdisc_t flineDisc = { + 0, + 0, + offsetof(fline,link), + NIL(Dtmake_f), + (Dtfree_f)free_item, + NIL(Dtcompar_f), + NIL(Dthash_f), + NIL(Dtmemory_f), + NIL(Dtevent_f) +}; + +#ifdef OLD static void appendStrList(const char* p,int v) { @@ -138,7 +218,60 @@ appendStrList(const char* p,int v) sp->c = v; dtinsert (HTMLstate.lines, sp); } +#endif +/* dupFont: + */ +static htmlfont_t * +dupFont (htmlfont_t *f) +{ + if (f) f->cnt++; + return f; +} + +/* appendFItemList: + * Append a new fitem to the list. + */ +static void +appendFItemList (agxbuf *ag) +{ + fitem *fi = NEW(fitem); + + fi->ti.str = strdup(agxbuse(ag)); + fi->ti.font = dupFont (HTMLstate.fontstack->cfont); + dtinsert(HTMLstate.fitemList, fi); +} + +/* appendFLineList: + */ +static void +appendFLineList (int v) +{ + int cnt; + fline *ln = NEW(fline); + fitem *fi; + Dt_t *ilist = HTMLstate.fitemList; + + cnt = dtsize(ilist); + ln->lp.nitems = cnt; + ln->lp.just = v; + if (cnt) { + int i = 0; + ln->lp.items = N_NEW(cnt, textitem_t); + + fi = (fitem*)dtflatten(ilist); + for (; fi; fi = (fitem*)dtlink(fitemList,(Dtlink_t*)fi)) { + ln->lp.items[i] = fi->ti; + i++; + } + } + + dtclear(ilist); + + dtinsert(HTMLstate.flineList, ln); +} + +#ifdef OLD /* mkText: * Construct htmltxt_t from list of lines in HTMLstate.lines. * lastl is a last, odd line with no
, so we use n by default. @@ -173,13 +306,42 @@ mkText (const char* lastl) } if (lastl) { lp->str = strdup(lastl); - lp->just = 'n'; + lp->just = '\0'; } if (lines) dtclear (lines); return tp; } +#endif + +static htmltxt_t* +mkText() +{ + int cnt; + Dt_t * iline = HTMLstate.flineList; + fline *fl ; + htmltxt_t *hft = NEW(htmltxt_t); + + if (dtsize (HTMLstate.fitemList)) + appendFLineList (UNSET_ALIGN); + + cnt = dtsize(iline); + hft->nlines = cnt; + + if (cnt) { + int i = 0; + hft->lines = N_NEW(cnt,htextline_t); + for(fl=(fline *)dtfirst(iline); fl; fl=(fline *)dtnext(iline,fl)) { + hft->lines[i] = fl->lp; + i++; + } + } + + dtclear(iline); + + return hft; +} /* addRow: * Add new cell row to current table. @@ -189,7 +351,6 @@ static void addRow (void) Dt_t* dp = dtopen(&cellDisc, Dtqueue); htmltbl_t* tbl = HTMLstate.tblstack; pitem* sp = NEW(pitem); - sp->u.rp = dp; dtinsert (tbl->u.p.rows, sp); } @@ -203,18 +364,19 @@ static void setCell (htmlcell_t* cp, void* obj, int kind) htmltbl_t* tbl = HTMLstate.tblstack; pitem* rp = (pitem*)dtlast (tbl->u.p.rows); Dt_t* row = rp->u.rp; - sp->u.cp = cp; dtinsert (row, sp); cp->child.kind = kind; - if (kind == HTML_TEXT) - cp->child.u.txt = (htmltxt_t*)obj; + + if(kind == HTML_TEXT) + cp->child.u.txt = (htmltxt_t*)obj; else if (kind == HTML_IMAGE) cp->child.u.img = (htmlimg_t*)obj; else cp->child.u.tbl = (htmltbl_t*)obj; } +#ifdef OLD /* setFont: * Copy in font attributes. fp has the new attributes. * curf corresponds to the current font info of the object. @@ -237,7 +399,6 @@ static htmlfont_t* setFont (htmlfont_t* fp, htmlfont_t* curf) return fp; } - /* fontText: * Attach font information to text. */ @@ -253,6 +414,7 @@ static void fontTable (htmlfont_t* fp, htmltbl_t* cp) { cp->font = setFont (fp, cp->font); } +#endif /* mkLabel: * Create label, given body and type. @@ -266,10 +428,25 @@ static htmllabel_t* mkLabel (void* obj, int kind) lp->u.txt = (htmltxt_t*)obj; else lp->u.tbl = (htmltbl_t*)obj; - return lp; } +/* freeFontstack: + * Free all stack items but the last, which is + * put on artificially during in parseHTML. + */ +static void +freeFontstack() +{ + sfont_t* s; + sfont_t* next; + + for (s = HTMLstate.fontstack; (next = s->pfont); s = next) { + free_html_font (s->cfont); + free(s); + } +} + /* cleanup: * Called on error. Frees resources allocated during parsing. * This includes a label, plus a walk down the stack of @@ -292,6 +469,16 @@ static void cleanup (void) tp = next; } cellDisc.freef = (Dtfree_f)free_item; + + fstrDisc.freef = (Dtfree_f)free_fitem; + dtclear (HTMLstate.fitemList); + fstrDisc.freef = (Dtfree_f)free_item; + + flineDisc.freef = (Dtfree_f)free_fline; + dtclear (HTMLstate.flineList); + flineDisc.freef = (Dtfree_f)free_item; + + freeFontstack(); } /* nonSpace: @@ -307,6 +494,42 @@ static int nonSpace (char* s) return 0; } +/* pushFont: + * Fonts are allocated in the lexer. + */ +static void +pushFont (htmlfont_t *f) +{ + sfont_t *ft = NEW(sfont_t); + htmlfont_t* curfont = HTMLstate.fontstack->cfont; + + if (curfont) { + if (!f->color && curfont->color) + f->color = strdup(curfont->color); + if ((f->size < 0.0) && (curfont->size >= 0.0)) + f->size = curfont->size; + if (!f->name && curfont->name) + f->name = strdup(curfont->name); + } + + ft->cfont = dupFont (f); + ft->pfont = HTMLstate.fontstack; + HTMLstate.fontstack = ft; +} + +/* popFont: + */ +static void +popFont () +{ + sfont_t* curfont = HTMLstate.fontstack; + sfont_t* prevfont = curfont->pfont; + + free_html_font (curfont->cfont); + free (curfont); + HTMLstate.fontstack = prevfont; +} + %} %union { @@ -326,38 +549,36 @@ static int nonSpace (char* s) %token T_cell %token T_font -%type text fonttext +%type fonttext %type br %type table fonttable %type image %start html - + %% -html : T_html fonttext { HTMLstate.lbl = mkLabel($2,HTML_TEXT); } T_end_html - | T_html fonttable { HTMLstate.lbl = mkLabel($2,HTML_TBL); } T_end_html +html : T_html fonttext T_end_html { HTMLstate.lbl = mkLabel($2,HTML_TEXT); } + | T_html fonttable T_end_html { HTMLstate.lbl = mkLabel($2,HTML_TBL); } | error { cleanup(); YYABORT; } ; -fonttext : text { $$ = $1; } - | T_font text T_end_font { fontText($1,$2); $$ = $2; } - ; +fonttext : text { $$ = mkText(); } + ; -text : lines - { $$ = mkText (NULL); } - | lines string - { $$ = mkText (agxbuse(HTMLstate.str)); } - | string - { $$ = mkText (agxbuse(HTMLstate.str)); } - | /* empty */ - { $$ = mkText (NULL); } +text : text textitem + | textitem ; -lines : string br - { appendStrList (agxbuse(HTMLstate.str),$2); } - | lines string br - { appendStrList (agxbuse(HTMLstate.str), $3); } +textitem : string { appendFItemList(HTMLstate.str);} + | br {appendFLineList($1);} + | sfont text nfont + ; + +sfont : T_font { pushFont ($1); } + ; + +nfont : T_end_font { popFont (); } ; br : T_br T_end_br { $$ = $1; } @@ -376,6 +597,7 @@ table : opt_space T_table { $2->u.p.prev = HTMLstate.tblstack; $2->u.p.rows = dtopen(&rowDisc, Dtqueue); HTMLstate.tblstack = $2; + $2->font = dupFont (HTMLstate.fontstack->cfont); $$ = $2; } rows T_end_table opt_space { @@ -389,7 +611,7 @@ table : opt_space T_table { ; fonttable : table { $$ = $1; } - | T_font table T_end_font { fontTable($1,$2); $$ = $2; } + | sfont table nfont { $$=$2; } ; opt_space : string @@ -416,9 +638,9 @@ image : T_img T_end_img { $$ = $1; } | T_IMG { $$ = $1; } ; - %% +#ifdef OLD htmllabel_t* simpleHTML (char* txt) { @@ -426,6 +648,7 @@ simpleHTML (char* txt) htmllabel_t* l = mkLabel(tobj,HTML_TEXT); return l; } +#endif /* parseHTML: * Return parsed label or NULL if failure. @@ -437,10 +660,16 @@ parseHTML (char* txt, int* warn, int charset) unsigned char buf[SMALLBUF]; agxbuf str; htmllabel_t* l; + sfont_t dfltf; + dfltf.cfont = NULL; + dfltf.pfont = NULL; + HTMLstate.fontstack = &dfltf; HTMLstate.tblstack = 0; HTMLstate.lbl = 0; - HTMLstate.lines = dtopen(&strDisc, Dtqueue); + HTMLstate.fitemList = dtopen(&fstrDisc, Dtqueue); + HTMLstate.flineList = dtopen(&flineDisc, Dtqueue); + agxbinit (&str, SMALLBUF, buf); HTMLstate.str = &str; @@ -454,8 +683,13 @@ parseHTML (char* txt, int* warn, int charset) l = HTMLstate.lbl; } - dtclose (HTMLstate.lines); - HTMLstate.lines = NULL; + dtclose (HTMLstate.fitemList); + dtclose (HTMLstate.flineList); + + HTMLstate.fitemList = NULL; + HTMLstate.flineList = NULL; + HTMLstate.fontstack = NULL; + agxbfree (&str); return l; diff --git a/lib/common/htmltable.c b/lib/common/htmltable.c index 9dbb9edd5..f88826684 100644 --- a/lib/common/htmltable.c +++ b/lib/common/htmltable.c @@ -99,6 +99,7 @@ static void popFontInfo(htmlenv_t * env, htmlfont_t * savp) env->finfo.size = savp->size; } +#ifdef OLD static void emit_html_txt(GVJ_t * job, htmltxt_t * tp, htmlenv_t * env, void *obj) { @@ -110,34 +111,136 @@ emit_html_txt(GVJ_t * job, htmltxt_t * tp, htmlenv_t * env, void *obj) /* make sure that there is something to do */ if (tp->nlines < 1) - return; + return; + + /* set font attributes */ + if (tp->font) { + if (tp->font->size > 0.0) + fsize = tp->font->size; + else + fsize = env->finfo.size; + if (tp->font->name) + fname = tp->font->name; + else + fname = env->finfo.name; + if (tp->font->color) + fcolor = tp->font->color; + else + fcolor = env->finfo.color; + } else { + fsize = env->finfo.size; + fname = env->finfo.name; + fcolor = env->finfo.color; + } + halfwidth_x = ((double)(tp->box.UR.x - tp->box.LL.x))/2.0; + p.x = env->p.x + ((double)(tp->box.UR.x + tp->box.LL.x))/2.0; + p.y = env->p.y + ((double)(tp->box.UR.y + tp->box.LL.y))/2.0; + + emit_textlines(job, tp->nlines, tp->line, p, + halfwidth_x, fname, fsize, fcolor); + } +#endif - /* set font attributes */ - if (tp->font) { - if (tp->font->size > 0.0) - fsize = tp->font->size; - else - fsize = env->finfo.size; - if (tp->font->name) - fname = tp->font->name; - else - fname = env->finfo.name; - if (tp->font->color) - fcolor = tp->font->color; - else - fcolor = env->finfo.color; - } else { - fsize = env->finfo.size; - fname = env->finfo.name; - fcolor = env->finfo.color; +static void +emit_htextlines(GVJ_t* job, int nlines, htextline_t* lines, pointf p, + double halfwidth_x, char* fname, double fsize, char* fcolor, box b) +{ + int i,j; + double tmp, center_x, left_x, right_x, fsize_; + double offset=0.0; + char *fname_ , *fcolor_; + textline_t tl; + pointf p_; + textitem_t* ti; + + center_x = p.x; + left_x = center_x - halfwidth_x; + right_x = center_x + halfwidth_x; + + gvrender_begin_context(job); + for(i=0; ifont && (ti->font->size > 0)) + fsize_ = ti->font->size; + else + fsize_ = fsize; + if (ti->font && ti->font->name) + fname_ = ti->font->name; + else + fname_ = fname; + if (ti->font && ti->font->color) + fcolor_ = ti->font->color; + else + fcolor_ = fcolor; + + gvrender_set_pencolor(job, fcolor_); + gvrender_set_font(job, fname_, fsize_); + + tl.str = ti->str; + tl.xshow = ti->xshow; + tl.width = lines[i].size; + tl.just = lines[i].just; + + gvrender_textline(job, p_, &tl); + offset += ti->size; + p_.x = p.x + offset; + ti++; + } + /* position for next line */ + if(i != nlines-1) + p_.y -= lines[i+1].lfsize * LINESPACING; + offset = 0.0; } - halfwidth_x = ((double)(tp->box.UR.x - tp->box.LL.x))/2.0; - p.x = env->p.x + ((double)(tp->box.UR.x + tp->box.LL.x))/2.0; - p.y = env->p.y + ((double)(tp->box.UR.y + tp->box.LL.y))/2.0; + gvrender_end_context(job); +} - emit_textlines(job, tp->nlines, tp->line, p, - halfwidth_x, fname, fsize, fcolor); +static void +emit_html_txt(GVJ_t* job, htmltxt_t* tp, htmlenv_t* env, void* obj) +{ + double halfwidth_x; + pointf p; + char *fname; + char *fcolor; + double fsize; + + /* make sure that there is something to do */ + if (tp->nlines < 1) + return; + + fsize = env->finfo.size; + fname = env->finfo.name; + fcolor = env->finfo.color; + + halfwidth_x = ((double) (tp->box.UR.x - tp->box.LL.x)) / 2.0; + p.x = env->p.x + ((double) (tp->box.UR.x + tp->box.LL.x)) / 2.0; + p.y = env->p.y + ((double) (tp->box.UR.y + tp->box.LL.y)) / 2.0; + + emit_htextlines(job, tp->nlines, tp->lines, p, halfwidth_x, fname, + fsize, fcolor, tp->box); } static void doSide(GVJ_t * job, point p, int wd, int ht) @@ -357,13 +460,16 @@ emit_html_label(GVJ_t * job, htmllabel_t * lp, textlabel_t * tp, void *obj) } } -static void free_html_font(htmlfont_t * fp) +void free_html_font(htmlfont_t * fp) { - if (fp->name) - free(fp->name); - if (fp->color) - free(fp->color); - free(fp); + fp->cnt--; + if (fp->cnt == 0) { + if (fp->name) + free(fp->name); + if (fp->color) + free(fp->color); + free(fp); + } } void free_html_data(htmldata_t * dp) @@ -375,6 +481,7 @@ void free_html_data(htmldata_t * dp) free(dp->bgcolor); } +#ifdef OLD void free_html_text(htmltxt_t * tp) { textline_t *lp; @@ -391,6 +498,31 @@ void free_html_text(htmltxt_t * tp) free_html_font(tp->font); free(tp); } +#endif + +void free_html_text(htmltxt_t* t) +{ + htextline_t *tl; + textitem_t *ti; + int i, j; + + if (!t) return; + + tl = t->lines; + for (i = 0; i < t->nlines; i++) { + ti = tl->items; + for (j = 0; j < tl->nitems; j++) { + if (ti->str) free (ti->str); + if (ti->xshow) free (ti->xshow); + if (ti->font) free_html_font(ti->font); + ti++; + } + tl++; + } + free(tl->items); + free(t->lines); + free(t); +} void free_html_img(htmlimg_t * ip) { @@ -568,6 +700,7 @@ int html_path(node_t * n, port* p, int side, box * rv, int *k) return 0; } +#ifdef OLD static int size_html_txt(htmltxt_t * txt, htmlenv_t * env) { @@ -621,6 +754,85 @@ size_html_txt(htmltxt_t * txt, htmlenv_t * env) txt->box.UR.y = txt->nlines * (int) (fsize * LINESPACING); return 0; } +#endif + +static char* +substrGFn (char* s, htmlenv_t* env) +{ + return strdup_and_subst_graph(s, (Agraph_t *) (env->obj)); +} + +static char* +substrNFn (char* s, htmlenv_t* env) +{ + return strdup_and_subst_node(s, (Agnode_t *) (env->obj)); +} + +static char* +substrEFn (char* s, htmlenv_t* env) +{ + return strdup_and_subst_edge(s, (Agedge_t *) (env->obj)); +} + +static int +size_html_txt(htmltxt_t* ftxt, htmlenv_t* env) +{ + double xsize = 0.0, ysize = 0.0; + double fsize, lsize = 0.0; + int i, j, w = 0, width = 0; + char *fname; + textline_t lp; + char* (*substrFn) (char*, htmlenv_t* env); + + switch (agobjkind(env->obj)) { + case AGGRAPH: + substrFn = substrGFn; + break; + case AGNODE: + substrFn = substrNFn; + break; + case AGEDGE: + substrFn = substrEFn; + break; + } + + for (i = 0; i < ftxt->nlines; i++) { + for (j = 0; j < ftxt->lines[i].nitems; j++) { + lp.str = substrFn (ftxt->lines[i].items[j].str, env); + if (ftxt->lines[i].items[j].font) { + if (ftxt->lines[i].items[j].font->size > 0) + fsize = ftxt->lines[i].items[j].font->size; + else + fsize = env->finfo.size; + if (ftxt->lines[i].items[j].font->name) + fname = ftxt->lines[i].items[j].font->name; + else + fname = env->finfo.name; + } else { + fsize = env->finfo.size; + fname = env->finfo.name; + } + w = textwidth(&lp, fname, fsize); + free (ftxt->lines[i].items[j].str); + ftxt->lines[i].items[j].str = lp.str; + ftxt->lines[i].items[j].size = (double) w; + ftxt->lines[i].items[j].xshow = lp.xshow; + width += w; + ftxt->lines[i].size = (double) width; + if (fsize > lsize) + lsize = fsize; + } + ftxt->lines[i].lfsize = lsize; + if (width > xsize) + xsize = width; + ysize += lsize * LINESPACING; + width = w = 0; + lsize = 0; + } + ftxt->box.UR.x = xsize; + ftxt->box.UR.y = (int) (ysize); + return 0; +} /* forward declarion for recursive usage */ static int size_html_tbl(htmltbl_t * tbl, htmlcell_t * parent, @@ -683,6 +895,7 @@ size_html_cell(htmlcell_t * cp, htmltbl_t * parent, htmlenv_t * env) rv = size_html_txt(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; @@ -1024,6 +1237,22 @@ static void pos_html_img(htmlimg_t * cp, box pos) cp->box = pos; } +/* pos_html_txt: + * Set default alignment. + */ +static void +pos_html_txt(htmltxt_t* ftxt, char c) +{ + int i; + + for (i = 0; i < ftxt->nlines; i++) { + if (ftxt->lines[i].just == UNSET_ALIGN) /* unset */ + ftxt->lines[i].just = c; + } +} + +/* pos_html_cell: + */ static void pos_html_cell(htmlcell_t * cp, box pos, int sides) { int delx, dely; @@ -1083,10 +1312,16 @@ static void pos_html_cell(htmlcell_t * cp, box pos, int sides) } else if (cp->child.kind == HTML_IMAGE) { pos_html_img(cp->child.u.img, cbox); } else { + char dfltalign; + int af; + 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) { + /* If the cell is larger than the text block and alignment is + * done at textblock level, the text box is shrunk accordingly. + */ + if ((delx > 0)&&((af=(cp->data.flags & HALIGN_MASK)) != HALIGN_TEXT)) { + switch (af) { case HALIGN_LEFT: cbox.UR.x -= delx; break; @@ -1099,6 +1334,7 @@ static void pos_html_cell(htmlcell_t * cp, box pos, int sides) break; } } + dely = (cbox.UR.y - cbox.LL.y) - oldsz.y; if (dely > 0) { switch (cp->data.flags & VALIGN_MASK) { @@ -1115,6 +1351,21 @@ static void pos_html_cell(htmlcell_t * cp, box pos, int sides) } } cp->child.u.txt->box = cbox; + + /* Set default text alignment + */ + switch (cp->data.flags & BALIGN_MASK) { + case BALIGN_LEFT: + dfltalign = 'l'; + break; + case BALIGN_RIGHT: + dfltalign = 'r'; + break; + default: + dfltalign = 'c'; + break; + } + pos_html_txt (cp->child.u.txt, dfltalign); } } @@ -1310,6 +1561,7 @@ void printImage(htmlimg_t *ip, int ind) fprintf(stderr, "img: %s\n", ip->src); } +#ifdef OLD void printTxt(htmltxt_t * tp, int ind) { int i; @@ -1323,6 +1575,31 @@ void printTxt(htmltxt_t * tp, int ind) tp->line[i].str); } } +#endif + +void printTxt(htmltxt_t * txt, int ind) +{ + int i, j; + + indent(ind); + fprintf (stderr, "txt lines = %d \n", txt->nlines); + for (i = 0; i < txt->nlines; i++) { + indent(ind+1); + fprintf (stderr, "[%d] %d items\n", i, txt->lines[i].nitems); + for (j = 0; j < txt->lines[i].nitems; j++) { + indent(ind+2); + fprintf (stderr, "[%d] (%f) \"%s\" ", + j, txt->lines[i].items[j].size, + txt->lines[i].items[j].str); + if (txt->lines[i].items[j].font) + fprintf (stderr, "font %s color %s size %f\n", + txt->lines[i].items[j].font->name, + txt->lines[i].items[j].font->color, + txt->lines[i].items[j].font->size); + else fprintf (stderr, "\n"); + } + } +} void printData(htmldata_t * dp) { @@ -1438,15 +1715,18 @@ int make_html_label(textlabel_t * lp, void *obj) } env.finfo.size = lp->fontsize; env.finfo.name = lp->fontname; - env.finfo.color = NULL; + env.finfo.color = lp->fontcolor; lbl = parseHTML(lp->text, &rv, GD_charset(env.g)); if (!lbl) { + /* Parse of label failed; revert to simple text label */ agxbuf xb; unsigned char buf[SMALLBUF]; agxbinit(&xb, SMALLBUF, buf); - lbl = simpleHTML(nameOf(obj, &xb)); + lp->html = FALSE; + size_label(env.g, nameOf(obj, &xb), lp); agxbfree(&xb); + return rv; } if (lbl->kind == HTML_TBL) { @@ -1467,6 +1747,7 @@ int make_html_label(textlabel_t * lp, void *obj) lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } + lp->u.html = lbl; /* If the label is a table, replace label text because this may diff --git a/lib/common/htmltable.h b/lib/common/htmltable.h index 9187e79d6..1b29609cc 100644 --- a/lib/common/htmltable.h +++ b/lib/common/htmltable.h @@ -25,33 +25,63 @@ extern "C" { #define HALIGN_RIGHT (1 << 1) #define HALIGN_LEFT (1 << 2) #define HALIGN_MASK (HALIGN_RIGHT | HALIGN_LEFT) +#define HALIGN_TEXT HALIGN_MASK #define VALIGN_TOP (1 << 3) #define VALIGN_BOTTOM (1 << 4) #define VALIGN_MASK (VALIGN_TOP | VALIGN_BOTTOM) #define BORDER_SET (1 << 5) #define PAD_SET (1 << 6) #define SPACE_SET (1 << 7) +#define BALIGN_RIGHT (1 << 8) +#define BALIGN_LEFT (1 << 9) +#define BALIGN_MASK (BALIGN_RIGHT | BALIGN_LEFT) + +#define UNSET_ALIGN 0 /* font information * If name or color is NULL, or size < 0, that attribute * is unspecified. */ typedef struct { - char *name; - char *color; + char* name; + char* color; double size; + int cnt; /* reference count */ } htmlfont_t; /* lines of text within a cell * NOTE: As required, the str field in line is utf-8. * This translation is done when libexpat scans the input. */ +#ifdef OLD typedef struct { textline_t *line; short nlines; box box; htmlfont_t *font; /* font info */ } htmltxt_t; +#endif + + typedef struct { + char *str; + char *xshow; + htmlfont_t *font; + double size; /* size of text item according to font */ + } textitem_t; + + typedef struct { + textitem_t *items; + short nitems; + char just; + double size; /* size of line */ + double lfsize; /* size of largest font in line */ + } htextline_t; + + typedef struct { + htextline_t *lines; + short nlines; + box box; + } htmltxt_t; typedef struct { box box; @@ -68,11 +98,11 @@ extern "C" { signed char space; unsigned char border; unsigned char pad; - unsigned char flags; + unsigned char sides; /* set of sides exposed to field */ + unsigned short flags; unsigned short width; unsigned short height; box box; /* its geometric placement in points */ - unsigned char sides; /* set of sides exposed to field */ } htmldata_t; #define HTML_UNSET 0 @@ -82,7 +112,7 @@ extern "C" { typedef struct htmlcell_t htmlcell_t; typedef struct htmltbl_t htmltbl_t; - + struct htmltbl_t { htmldata_t data; union { @@ -134,9 +164,8 @@ extern "C" { htmlcell_t *cp; } u; } pitem; - + extern htmllabel_t *parseHTML(char *, int *, int); - extern htmllabel_t *simpleHTML(char *); extern int make_html_label(textlabel_t * lp, void *obj); extern void emit_html_label(GVJ_t * job, htmllabel_t * lp, @@ -145,6 +174,7 @@ extern "C" { extern void free_html_label(htmllabel_t *, int); extern void free_html_data(htmldata_t *); extern void free_html_text(htmltxt_t *); + extern void free_html_font(htmlfont_t*); extern box *html_port(node_t * n, char *pname, int* sides); extern int html_path(node_t * n, port* p, int side, box * rv, int *k); diff --git a/lib/common/labels.c b/lib/common/labels.c index 90b678654..f8d689e2e 100644 --- a/lib/common/labels.c +++ b/lib/common/labels.c @@ -114,6 +114,21 @@ static pointf label_size(char *str, textlabel_t * lp, graph_t * g) return lp->dimen; } +/* size_label: + * Process label text for size and line breaks. + */ +void +size_label (graph_t* g, char* str, textlabel_t* rv) +{ + if (GD_charset(g) == CHAR_LATIN1) { + char* lstr = latin1ToUTF8(str); + label_size(lstr, rv, g); + free(lstr); + } + else + label_size(str, rv, g); +} + /* make_label: * Assume str is freshly allocated for this instance, so it * can be freed in free_label. @@ -129,13 +144,8 @@ textlabel_t *make_label(int html, char *str, double fontsize, rv->fontsize = fontsize; if (html) rv->html = TRUE; - else if (GD_charset(g) == CHAR_LATIN1) { - char* lstr = latin1ToUTF8(str); - label_size(lstr, rv, g); - free(lstr); - } else - label_size(str, rv, g); + size_label(g, str, rv); return rv; } diff --git a/lib/common/render.h b/lib/common/render.h index 839169ccd..ec6f2af94 100644 --- a/lib/common/render.h +++ b/lib/common/render.h @@ -157,6 +157,7 @@ extern "C" { extern void setup_graph(GVC_t * gvc, graph_t * g); extern shape_kind shapeOf(node_t *); extern void shape_clip(node_t * n, point curve[4]); + extern void size_label (graph_t* g, char* str, textlabel_t* rv); extern void start_timer(void); extern double textwidth(textline_t * textline, char *fontname, double fontsz);