Note that at present the width of the rules is only 1.
We also allow formatting information about rules to be supplied by
the columns and rows attributes of TABLE. This is limited now to just
specifying all or nothing. These could be extended to accept more
general specifications as used in tabular environment in LaTeX.
pkginclude_HEADERS = arith.h geom.h color.h types.h textpara.h usershape.h
noinst_HEADERS = render.h utils.h memory.h \
geomprocs.h colorprocs.h colortbl.h entities.h globals.h \
- logic.h const.h macros.h htmllex.h htmltable.h pointset.h
+ logic.h const.h macros.h htmllex.h htmltable.h pointset.h intset.h
noinst_LTLIBRARIES = libcommon_C.la
libcommon_C_la_SOURCES = arrows.c colxlate.c fontmetrics.c \
args.c memory.c globals.c htmllex.c htmlparse.y htmltable.c input.c \
- pointset.c postproc.c routespl.c splines.c psusershape.c \
+ pointset.c intset.c postproc.c routespl.c splines.c psusershape.c \
timing.c labels.c ns.c shapes.c utils.c geom.c \
output.c emit.c ps_font_equiv.txt ps_fontmap.txt fontmap.cfg \
color_names
return 0;
}
+static int columnsfn(htmltbl_t * p, char *v)
+{
+ if (*v != '*') {
+ agerr(AGWARN, "Unknown value %s for COLUMNS - ignored\n", v);
+ return 1;
+ }
+ p->flags |= HTML_VRULE;
+ return 0;
+}
+
+static int rowsfn(htmltbl_t * p, char *v)
+{
+ if (*v != '*') {
+ agerr(AGWARN, "Unknown value %s for ROWS - ignored\n", v);
+ return 1;
+ }
+ p->flags |= HTML_HRULE;
+ return 0;
+}
+
static int fixedsizefn(htmldata_t * p, char *v)
{
int rv = 0;
{"cellpadding", (attrFn) cellpaddingfn},
{"cellspacing", (attrFn) cellspacingfn},
{"color", (attrFn) pencolorfn},
+ {"columns", (attrFn) columnsfn},
{"fixedsize", (attrFn) fixedsizefn},
{"height", (attrFn) heightfn},
{"href", (attrFn) hreffn},
{"id", (attrFn) idfn},
{"port", (attrFn) portfn},
+ {"rows", (attrFn) rowsfn},
{"style", (attrFn) stylefn},
{"target", (attrFn) targetfn},
{"title", (attrFn) titlefn},
} else if (strcasecmp(name, "BR") == 0) {
mkBR(atts);
state.tok = T_br;
+ } else if (strcasecmp(name, "HR") == 0) {
+ state.tok = T_hr;
+ } else if (strcasecmp(name, "VR") == 0) {
+ state.tok = T_vr;
} else if (strcasecmp(name, "IMG") == 0) {
htmllval.img = mkImg(atts);
state.tok = T_img;
state.tok = T_BR;
else
state.tok = T_end_br;
+ } else if (strcasecmp(name, "HR") == 0) {
+ if (state.tok == T_hr)
+ state.tok = T_HR;
+ else
+ state.tok = T_end_hr;
+ } else if (strcasecmp(name, "VR") == 0) {
+ if (state.tok == T_vr)
+ state.tok = T_VR;
+ else
+ state.tok = T_end_vr;
} else if (strcasecmp(name, "IMG") == 0) {
if (state.tok == T_img)
state.tok = T_IMG;
char *s;
switch (tok) {
+ case T_VR:
+ s = "T_VR";
+ break;
+ case T_vr:
+ s = "T_vr";
+ break;
+ case T_end_vr:
+ s = "T_end_vr";
+ break;
+ case T_HR:
+ s = "T_HR";
+ break;
+ case T_hr:
+ s = "T_hr";
+ break;
+ case T_end_hr:
+ s = "T_end_hr";
+ break;
case T_BR:
s = "T_BR";
break;
if (endp)
state.ptr = endp;
} while (state.tok == 0);
+ /* printTok (state.tok); */
return state.tok;
#else
return EOF;
#endif
}
+
return hft;
}
+static pitem* lastRow (void)
+{
+ htmltbl_t* tbl = HTMLstate.tblstack;
+ pitem* sp = dtlast (tbl->u.p.rows);
+ return sp;
+}
+
/* addRow:
* Add new cell row to current table.
*/
-static void addRow (void)
+static pitem* addRow (void)
{
Dt_t* dp = dtopen(&cellDisc, Dtqueue);
htmltbl_t* tbl = HTMLstate.tblstack;
pitem* sp = NEW(pitem);
sp->u.rp = dp;
+ if (tbl->flags & HTML_HRULE)
+ sp->ruled = 1;
dtinsert (tbl->u.p.rows, sp);
+ return sp;
}
/* setCell:
sp->u.cp = cp;
dtinsert (row, sp);
cp->child.kind = kind;
+ if (tbl->flags & HTML_VRULE)
+ cp->ruled = HTML_VRULE;
if(kind == HTML_TEXT)
cp->child.u.txt = (htmltxt_t*)obj;
htmltbl_t* tbl;
htmlfont_t* font;
htmlimg_t* img;
+ pitem* p;
}
%token T_end_br T_end_img T_row T_end_row T_html T_end_html
%token T_end_table T_end_cell T_end_font T_string T_error
%token T_n_italic T_n_bold T_n_underline T_n_sup T_n_sub
+%token T_HR T_hr T_end_hr
+%token T_VR T_vr T_end_vr
%token <i> T_BR T_br
%token <img> T_IMG T_img
%token <tbl> T_table
%token <font> T_font T_italic T_bold T_underline T_sup T_sub
%type <txt> fonttext
+%type <cell> cell cells
%type <i> br
%type <tbl> table fonttable
%type <img> image
+%type <p> row rows
%start html
| /* empty*/
;
-rows : row
- | rows row
+rows : row { $$ = $1; }
+ | rows row { $$ = $2; }
+ | rows HR row { $1->ruled = 1; $$ = $3; }
;
-row : T_row { addRow (); } cells T_end_row
+row : T_row { addRow (); } cells T_end_row { $$ = lastRow(); }
;
-cells : cell
- | cells cell
+cells : cell { $$ = $1; }
+ | cells cell { $$ = $2; }
+ | cells VR cell { $1->ruled |= HTML_VRULE; $$ = $3; }
;
-cell : T_cell fonttable { setCell($1,$2,HTML_TBL); } T_end_cell
- | T_cell fonttext { setCell($1,$2,HTML_TEXT); } T_end_cell
- | T_cell image { setCell($1,$2,HTML_IMAGE); } T_end_cell
- | T_cell { setCell($1,mkText(),HTML_TEXT); } T_end_cell
+cell : T_cell fonttable { setCell($1,$2,HTML_TBL); } T_end_cell { $$ = $1; }
+ | T_cell fonttext { setCell($1,$2,HTML_TEXT); } T_end_cell { $$ = $1; }
+ | T_cell image { setCell($1,$2,HTML_IMAGE); } T_end_cell { $$ = $1; }
+ | T_cell { setCell($1,mkText(),HTML_TEXT); } T_end_cell { $$ = $1; }
;
image : T_img T_end_img { $$ = $1; }
| T_IMG { $$ = $1; }
;
+HR : T_hr T_end_hr
+ | T_HR
+ ;
+
+VR : T_vr T_end_vr
+ | T_VR
+ ;
+
+
%%
/* parseHTML:
#include "htmltable.h"
#include "agxbuf.h"
#include "pointset.h"
+#include "intset.h"
#define DEFAULT_BORDER 1
#define DEFAULT_CELLPADDING 2
/* forward declaration */
static void emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env);
-static void emit_html_rules(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env, char *fillc);
+
+/* emit_html_rules:
+ * place vertical and horizontal lines between adjacent cells and
+ * extend the lines to intersect the rounded table boundary
+ */
+static void
+emit_html_rules(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env, char *color)
+{
+ pointf rule_pt;
+ double rule_length;
+ unsigned char base;
+ boxf pts = cp->data.box;
+ pointf pos = env->pos;
+
+ if (!color)
+ color = DEFAULT_COLOR;
+ gvrender_set_fillcolor(job, color);
+ gvrender_set_pencolor(job, color);
+
+ pts = cp->data.box;
+ pts.LL.x += pos.x;
+ pts.UR.x += pos.x;
+ pts.LL.y += pos.y;
+ pts.UR.y += pos.y;
+
+ //Determine vertical line coordinate and length
+ if ((cp->ruled & HTML_VRULE) && (cp->col + cp->cspan < cp->parent->cc)) {
+ if(cp->row == 0) { // first row
+ // extend to table border and add half cell spacing
+ base = cp->parent->data.border + cp->parent->data.space/2;
+ rule_pt.y = pts.LL.y - cp->parent->data.space/2;
+ }
+ else if(cp->row + cp->rspan == cp->parent->rc){ // bottom row
+ // extend to table border and add half cell spacing
+ base = cp->parent->data.border + cp->parent->data.space/2;
+ rule_pt.y = pts.LL.y - cp->parent->data.space/2 - base;
+ }
+ else {
+ base = 0;
+ rule_pt.y = pts.LL.y - cp->parent->data.space/2;
+ }
+ rule_pt.x = pts.UR.x + cp->parent->data.space/2;
+ rule_length = base + pts.UR.y - pts.LL.y + cp->parent->data.space;
+ doSide(job,rule_pt,0,rule_length);
+ }
+
+ //Determine the horizontal coordinate and length
+ if ((cp->ruled & HTML_HRULE) && (cp->row + cp->rspan < cp->parent->rc)) {
+ if(cp->col == 0) { // first column
+ // extend to table border and add half cell spacing
+ base = cp->parent->data.border + cp->parent->data.space/2;
+ rule_pt.x = pts.LL.x - base - cp->parent->data.space/2;
+ }
+ else if(cp->col + cp->cspan == cp->parent->cc){ // last column
+ // extend to table border and add half cell spacing
+ base = cp->parent->data.border + cp->parent->data.space/2;
+ rule_pt.x = pts.LL.x - cp->parent->data.space/2;
+ }
+ else {
+ base = 0;
+ rule_pt.x = pts.LL.x - cp->parent->data.space/2;
+ }
+ rule_pt.y = pts.LL.y - cp->parent->data.space/2;
+ rule_length = base + pts.UR.x - pts.LL.x + cp->parent->data.space;
+ doSide(job,rule_pt,rule_length,0);
+ }
+}
static void
emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
boxf pts = tbl->data.box;
pointf pos = env->pos;
htmlcell_t **cells = tbl->u.n.cells;
+ htmlcell_t *cp;
static htmlfont_t savef;
htmlmap_data_t saved;
int anchor; /* if true, we need to undo anchor settings. */
doBorder(job, tbl->data.pencolor, tbl->data.border, pts);
}
//render table rules
-#if 0
- while (*cells){
- emit_html_rules(job, *cells, env, tbl->data.bgcolor);
- cells++;
+ while ((cp = *cells++)){
+ if (cp->ruled) emit_html_rules(job, cp, env, tbl->data.bgcolor);
}
-#endif
cells = tbl->u.n.cells;
while (*cells) {
}
}
-/* emit_html_rules:
- * place vertical and horizontal lines between adjacent cells and
- * extend the lines to intersect the rounded table boundary
- */
-static void
-emit_html_rules(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env, char *color)
-{
- pointf rule_pt;
- double rule_length;
- unsigned char base;
- boxf pts = cp->data.box;
- pointf pos = env->pos;
-
- if (!color)
- color = DEFAULT_COLOR;
- gvrender_set_fillcolor(job, color);
- gvrender_set_pencolor(job, color);
-
- pts = cp->data.box;
- pts.LL.x += pos.x;
- pts.UR.x += pos.x;
- pts.LL.y += pos.y;
- pts.UR.y += pos.y;
-
- //Determine vertical line coordinate and length
- if (cp->col + cp->cspan < cp->parent->cc){
- if(cp->row == 0) { // first row
- // extend to table border and add half cell spacing
- base = cp->parent->data.border + cp->parent->data.space/2;
- rule_pt.y = pts.LL.y - cp->parent->data.space/2;
- }
- else if(cp->row + cp->rspan == cp->parent->rc){ // bottom row
- // extend to table border and add half cell spacing
- base = cp->parent->data.border + cp->parent->data.space/2;
- rule_pt.y = pts.LL.y - cp->parent->data.space/2 - base;
- }
- else {
- base = 0;
- rule_pt.y = pts.LL.y - cp->parent->data.space/2;
- }
- rule_pt.x = pts.UR.x + cp->parent->data.space/2;
- rule_length = base + pts.UR.y - pts.LL.y + cp->parent->data.space;
- doSide(job,rule_pt,0,rule_length);
- }
- //Determine the horizontal coordinate and length
- if(cp->row + cp->rspan < cp->parent->rc){
- if(cp->col == 0) { // first column
- // extend to table border and add half cell spacing
- base = cp->parent->data.border + cp->parent->data.space/2;
- rule_pt.x = pts.LL.x - base - cp->parent->data.space/2;
- }
- else if(cp->col + cp->cspan == cp->parent->cc){ // last column
- // extend to table border and add half cell spacing
- base = cp->parent->data.border + cp->parent->data.space/2;
- rule_pt.x = pts.LL.x - cp->parent->data.space/2;
- }
- else {
- base = 0;
- rule_pt.x = pts.LL.x - cp->parent->data.space/2;
- }
- rule_pt.y = pts.LL.y - cp->parent->data.space/2;
- rule_length = base + pts.UR.x - pts.LL.x + cp->parent->data.space;
- doSide(job,rule_pt,rule_length,0);
- }
-
-}
-
/* allocObj:
* Push new obj on stack to be used in common by all
* html elements with anchors.
/* free_html_tbl:
* If tbl->n_rows is negative, table is in initial state from
- * HTML parse, with data stored in u.p. Once run through processTable,
+ * HTML parse, with data stored in u.p. Once run through processTbl,
* data is stored in u.n and tbl->n_rows is > 0.
*/
static void free_html_tbl(htmltbl_t * tbl)
int n_rows = 0;
int n_cols = 0;
PointSet *ps = newPS();
+ Dt_t* is = openIntSet();
rp = (pitem *) dtflatten(rows);
cnt = 0;
+ r = 0;
while (rp) {
cdict = rp->u.rp;
cp = (pitem *) dtflatten(cdict);
cnt++;
cp = (pitem *) dtlink(cdict, (Dtlink_t *) cp);
}
+ if (rp->ruled) {
+ addIntSet (is, r+1);
+ }
rp = (pitem *) dtlink(rows, (Dtlink_t *) rp);
+ r++;
}
cells = tbl->u.n.cells = N_NEW(cnt + 1, htmlcell_t *);
c += cellp->cspan;
n_cols = MAX(c, n_cols);
n_rows = MAX(r + cellp->rspan, n_rows);
+ if (inIntSet (is, r+cellp->rspan)) cellp->ruled |= HTML_HRULE;
cp = (pitem *) dtlink(cdict, (Dtlink_t *) cp);
}
rp = (pitem *) dtlink(rows, (Dtlink_t *) rp);
tbl->rc = n_rows;
tbl->cc = n_cols;
dtclose(rows);
+ dtclose(is);
freePS(ps);
return rv;
}
#define HTML_TEXT 2
#define HTML_IMAGE 3
+#define HTML_VRULE 1
+#define HTML_HRULE 2
+
typedef struct htmlcell_t htmlcell_t;
typedef struct htmltbl_t htmltbl_t;
int cc; /* number of columns */
htmlfont_t *font; /* font info */
unsigned char style;
+ unsigned char flags;
};
struct htmllabel_t {
unsigned short row;
htmllabel_t child;
htmltbl_t *parent;
+ unsigned char ruled;
};
/* During parsing, table contents are stored as rows of cells.
Dt_t *rp;
htmlcell_t *cp;
} u;
+ unsigned char ruled;
} pitem;
extern htmllabel_t *parseHTML(char *, int *, int);
--- /dev/null
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stddef.h>
+#include <intset.h>
+#include <memory.h>
+
+static Void_t*
+mkIntItem(Dt_t* d,intitem* obj,Dtdisc_t* disc)
+{
+ intitem* np = NEW(intitem);
+ np->id = obj->id;
+ return (Void_t*)np;
+}
+
+static void
+freeIntItem(Dt_t* d,intitem* obj,Dtdisc_t* disc)
+{
+ free (obj);
+}
+
+static int
+cmpid(Dt_t* d, int* key1, int* key2, Dtdisc_t* disc)
+{
+ if (*key1 > *key2) return 1;
+ else if (*key1 < *key2) return -1;
+ else return 0;
+}
+
+static Dtdisc_t intSetDisc = {
+ offsetof(intitem,id),
+ sizeof(int),
+ offsetof(intitem,link),
+ (Dtmake_f)mkIntItem,
+ (Dtfree_f)freeIntItem,
+ (Dtcompar_f)cmpid,
+ 0,
+ 0,
+ 0
+};
+
+Dt_t*
+openIntSet (void)
+{
+ return dtopen(&intSetDisc,Dtoset);
+}
+
+void
+addIntSet (Dt_t* is, int v)
+{
+ intitem obj;
+
+ obj.id = v;
+ dtinsert(is, &obj);
+}
+
+int
+inIntSet (Dt_t* is, int v)
+{
+ return (dtmatch (is, &v) != 0);
+}
+
--- /dev/null
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/*************************************************************************
+ * Copyright (c) 2011 AT&T Intellectual Property
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
+ *************************************************************************/
+
+#ifndef INTSET_H
+#define INTSET_H
+
+#include <cdt.h>
+
+typedef struct {
+ int id;
+ Dtlink_t link;
+} intitem;
+
+extern Dt_t* openIntSet (void);
+extern void addIntSet (Dt_t*, int);
+extern int inIntSet (Dt_t*, int);
+#endif