]> granicus.if.org Git - graphviz/commitdiff
New HTML code to support font changes in running text, plus attribute
authorerg <devnull@localhost>
Fri, 3 Mar 2006 03:22:43 +0000 (03:22 +0000)
committererg <devnull@localhost>
Fri, 3 Mar 2006 03:22:43 +0000 (03:22 +0000)
extensions to make it easier to specify text alignment using the
entire cell width.

lib/common/htmllex.c
lib/common/htmlparse.y
lib/common/htmltable.c
lib/common/htmltable.h
lib/common/labels.c
lib/common/render.h

index 5d5b77c58dc0f5c4566f5d54f2ecc586ed942f4a..a43d6dd71d1595415a30d9da58c2dcf2689edf7c 100644 (file)
@@ -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, "<BR>");
 }
 
@@ -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
index c2e65a742262b36fc1fc69296a0f4a5d30e6da9f..de2025706d8ad3f87bb7e8526e52e348e8ff6c7f 100644 (file)
 
 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 <BR>, 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 <cell> T_cell
 %token <font> T_font
 
-%type <txt> text fonttext
+%type <txt> fonttext
 %type <i> br
 %type <tbl> table fonttable
 %type <img> 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;
index 9dbb9edd5bbd306d233cd80afc5834e5617668dc..f88826684e05f0e9ceea38159fb64c4b3c1cda85 100644 (file)
@@ -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; i<nlines; i++) {
+       switch (lines[i].just) {
+       case 'l':
+           p_.x = left_x;
+           p.x = left_x;
+           break;
+       case 'r':
+           p_.x = right_x;
+           p.x = right_x;              
+           break;
+       default:
+       case 'n':
+           p_.x = center_x;
+           p.x = center_x;
+           break;
+       }
+
+       if (i == 0) {
+           p_.y = p.y + (double)(b.UR.y-b.LL.y)/2 - lines[i].lfsize;
+           tmp = ROUND(p_.y);  /* align with interger points */
+           p_.y = (double)tmp;
+       }
+
+       ti = lines[i].items;
+       for(j=0; j<lines[i].nitems; j++) {
+           if (ti->font && (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
index 9187e79d6d2138e21104f48aa5beeac50e0f0f1d..1b29609cca7a328e8720e550ba473c1574081cf2 100644 (file)
@@ -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);
index 90b67865465a7f50d569980c63f2e58efbd34978..f8d689e2e8ae86682f5b145ee77721552df88d38 100644 (file)
@@ -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;
 }
 
index 839169ccde71b37d6bda749f5145227aba7812af..ec6f2af9491c12047b4a4a927ca250bc0e17ec5a 100644 (file)
@@ -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);