From 4c1676f8f2e0b7baff0f5b4ca019ce38aefbfd51 Mon Sep 17 00:00:00 2001
From: "Emden R. Gansner" <erg@alum.mit.edu>
Date: Sun, 9 Mar 2014 16:16:06 -0400
Subject: [PATCH] Support text overlining.

---
 doc/info/output.html            |  4 +++-
 doc/infosrc/outputs             |  4 +++-
 lib/common/htmllex.c            | 11 +++++++++++
 lib/common/htmlparse.y          | 12 ++++++++++--
 lib/common/textspan.h           | 17 ++++++++++-------
 lib/xdot/xdot.c                 | 14 +++++++++++++-
 lib/xdot/xdot.h                 |  2 +-
 plugin/core/gvrender_core_dot.c |  8 +++++---
 plugin/core/gvrender_core_svg.c |  8 ++++++--
 plugin/pango/gvrender_pango.c   | 10 ++++++++++
 10 files changed, 72 insertions(+), 18 deletions(-)

diff --git a/doc/info/output.html b/doc/info/output.html
index 00248da36..2f49b8c09 100644
--- a/doc/info/output.html
+++ b/doc/info/output.html
@@ -215,7 +215,8 @@ n bytes following '-'. The text should be left-aligned (centered,
 right-aligned) on the point if j is -1 (0, 1), respectively. The value
 w gives the width of the text as computed by the library.
 <TR><TD>t f
-<TD>Set font characteristics. The integer f is the OR of BOLD=1, ITALIC=2, UNDERLINE=4, SUPERSCRIPT=8, SUBSCRIPT=16, and STRIKE-THROUGH=32. (1.5)
+<TD>Set font characteristics. The integer f is the OR of BOLD=1, ITALIC=2, UNDERLINE=4, SUPERSCRIPT=8, SUBSCRIPT=16, (1.5) STRIKE-THROUGH=32 (1.6),
+and OVERLINE=64 (1.7).
 <TR><TD>C n -<I>b<sub>1</sub>b<sub>2</sub>...b<sub>n</sub></I>
 <TD>Set fill color. The color value consists of the
 n bytes following '-'. (1.1)
@@ -297,6 +298,7 @@ Version info:
 <TR><TD>1.4</TD><TD>2.32</TD><TD>Add gradient colors</TD</TR>
 <TR><TD>1.5</TD><TD>2.34</TD><TD>Fix text layout problem; fix inverted vector in gradient; support version-specific output; new <B>t</B> op for text characteristics</TD</TR>
 <TR><TD>1.6</TD><TD>2.35</TD><TD>Add STRIKE-THROUGH bit for <tt>t</tt></TD</TR>
+<TR><TD>1.7</TD><TD>2.37</TD><TD>Add OVERLINE for <tt>t</tt></TD</TR>
 </TABLE>
 
 <DT><A NAME=d:cgimage HREF=#a:cgimage><STRONG>cgimage</STRONG></A>
diff --git a/doc/infosrc/outputs b/doc/infosrc/outputs
index 73fe19ce2..1917c89d1 100644
--- a/doc/infosrc/outputs
+++ b/doc/infosrc/outputs
@@ -259,7 +259,8 @@ n bytes following '-'. The text should be left-aligned (centered,
 right-aligned) on the point if j is -1 (0, 1), respectively. The value
 w gives the width of the text as computed by the library.
 <TR><TD>t f
-<TD>Set font characteristics. The integer f is the OR of BOLD=1, ITALIC=2, UNDERLINE=4, SUPERSCRIPT=8, SUBSCRIPT=16, and STRIKE-THROUGH=32. (1.5)
+<TD>Set font characteristics. The integer f is the OR of BOLD=1, ITALIC=2, UNDERLINE=4, SUPERSCRIPT=8, SUBSCRIPT=16, (1.5) STRIKE-THROUGH=32 (1.6),
+and OVERLINE=64 (1.7).
 <TR><TD>C n -<I>b<sub>1</sub>b<sub>2</sub>...b<sub>n</sub></I>
 <TD>Set fill color. The color value consists of the
 n bytes following '-'. (1.1)
@@ -341,6 +342,7 @@ Version info:
 <TR><TD>1.4</TD><TD>2.32</TD><TD>Add gradient colors</TD</TR>
 <TR><TD>1.5</TD><TD>2.34</TD><TD>Fix text layout problem; fix inverted vector in gradient; support version-specific output; new <B>t</B> op for text characteristics</TD</TR>
 <TR><TD>1.6</TD><TD>2.35</TD><TD>Add STRIKE-THROUGH bit for <tt>t</tt></TD</TR>
+<TR><TD>1.7</TD><TD>2.37</TD><TD>Add OVERLINE for <tt>t</tt></TD</TR>
 </TABLE>
 :plain/plain-ext:Simple text format
 The plain and plain-ext formats produce output using
diff --git a/lib/common/htmllex.c b/lib/common/htmllex.c
index 067efa6c1..c4a1dd99b 100644
--- a/lib/common/htmllex.c
+++ b/lib/common/htmllex.c
@@ -657,6 +657,9 @@ static void startElement(void *user, const char *name, char **atts)
     } else if (strcasecmp(name, "U") == 0) {
 	htmllval.font = mkFont(gvc, 0, HTML_UL, 1);
 	state.tok = T_underline;
+    } else if (strcasecmp(name, "O") == 0) {
+	htmllval.font = mkFont(gvc, 0, HTML_OL, 1);
+	state.tok = T_overline;
     } else if (strcasecmp(name, "I") == 0) {
 	htmllval.font = mkFont(gvc, 0, HTML_IF, 0);
 	state.tok = T_italic;
@@ -702,6 +705,8 @@ static void endElement(void *user, const char *name)
 	state.tok = T_n_bold;
     } else if (strcasecmp(name, "U") == 0) {
 	state.tok = T_n_underline;
+    } else if (strcasecmp(name, "O") == 0) {
+	state.tok = T_n_overline;
     } else if (strcasecmp(name, "I") == 0) {
 	state.tok = T_n_italic;
     } else if (strcasecmp(name, "SUP") == 0) {
@@ -956,6 +961,12 @@ static void printTok(int tok)
     case T_n_underline:
 	s = "T_n_underline";
 	break;
+    case T_overline:
+	s = "T_overline";
+	break;
+    case T_n_overline:
+	s = "T_n_overline";
+	break;
     case T_italic:
 	s = "T_italic";
 	break;
diff --git a/lib/common/htmlparse.y b/lib/common/htmlparse.y
index 7a7dfb0c5..4d1656533 100644
--- a/lib/common/htmlparse.y
+++ b/lib/common/htmlparse.y
@@ -424,14 +424,14 @@ popFont (void)
 
 %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 T_n_s
+%token T_n_italic T_n_bold T_n_underline  T_n_overline T_n_sup T_n_sub T_n_s
 %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 <cell> T_cell
-%token <font> T_font T_italic T_bold T_underline T_sup T_sub T_s
+%token <font> T_font T_italic T_bold T_underline T_overline T_sup T_sub T_s
 
 %type <txt> fonttext
 %type <cell> cell cells
@@ -461,6 +461,7 @@ textitem : string { appendFItemList(HTMLstate.str);}
          | font text n_font
          | italic text n_italic
          | underline text n_underline
+         | overline text n_overline
          | bold text n_bold
          | sup text n_sup
          | sub text n_sub
@@ -497,6 +498,12 @@ underline : T_underline {pushFont($1);}
 n_underline : T_n_underline {popFont();}
             ;
 
+overline : T_overline {pushFont($1);}
+          ;
+
+n_overline : T_n_overline {popFont();}
+            ;
+
 sup : T_sup {pushFont($1);}
           ;
 
@@ -542,6 +549,7 @@ fonttable : table { $$ = $1; }
           | font table n_font { $$=$2; }
           | italic table n_italic { $$=$2; }
           | underline table n_underline { $$=$2; }
+          | overline table n_overline { $$=$2; }
           | bold table n_bold { $$=$2; }
           ;
 
diff --git a/lib/common/textspan.h b/lib/common/textspan.h
index 4682e20c4..64ba97fc5 100644
--- a/lib/common/textspan.h
+++ b/lib/common/textspan.h
@@ -19,12 +19,15 @@ extern "C" {
 #endif
 
 /* Bold, Italic, Underline, Sup, Sub, Strike */
-#define HTML_BF 1
-#define HTML_IF 2
-#define HTML_UL 4
-#define HTML_SUP 8
-#define HTML_SUB 16
-#define HTML_S   32
+/* Stored in textfont_t.flags, which is 7 bits, so full */
+/* Probably should be moved to textspan_t */
+#define HTML_BF   (1 << 0)
+#define HTML_IF   (1 << 1)
+#define HTML_UL   (1 << 2)
+#define HTML_SUP  (1 << 3)
+#define HTML_SUB  (1 << 4)
+#define HTML_S    (1 << 5)
+#define HTML_OL   (1 << 6)
 
     typedef struct _PostscriptAlias {
         char* name;
@@ -47,7 +50,7 @@ extern "C" {
 	char*  color;
 	PostscriptAlias *postscript_alias;
 	double size;
-	int    flags:7;  /* HTML_UL, HTML_IF, HTML_BF, etc. */
+	unsigned int flags:7;  /* HTML_UL, HTML_IF, HTML_BF, etc. */
 	unsigned int cnt:(sizeof(unsigned int) * 8 - 7);   /* reference count */
     } textfont_t;
 
diff --git a/lib/xdot/xdot.c b/lib/xdot/xdot.c
index 14227684f..562f3636c 100755
--- a/lib/xdot/xdot.c
+++ b/lib/xdot/xdot.c
@@ -101,6 +101,7 @@ static char *parseReal(char *s, double *fp)
     return (p);
 }
 
+
 static char *parseInt(char *s, int *ip)
 {
     char* endp;
@@ -118,6 +119,17 @@ static char *parseInt(char *s, int *ip)
 	return endp;
 }
 
+static char *parseUInt(char *s, unsigned int *ip)
+{
+    char* endp;
+
+    *ip = (unsigned int)strtoul (s, &endp, 10);
+    if (s == endp)
+	return 0;
+    else
+	return endp;
+}
+
 #ifdef UNUSED
 static char *parsePoint(char *s, xdot_point * pp)
 {
@@ -393,7 +405,7 @@ static char *parseOp(xdot_op * op, char *s, drawfunc_t ops[], int* error)
 
     case 't':
 	op->kind = xd_fontchar;
-	s = parseInt(s, &op->u.fontchar);
+	s = parseUInt(s, &op->u.fontchar);
 	CHK(s);
 	if (ops)
 	    op->drawfunc = ops[xop_fontchar];
diff --git a/lib/xdot/xdot.h b/lib/xdot/xdot.h
index 3323b6b41..94f34accf 100755
--- a/lib/xdot/xdot.h
+++ b/lib/xdot/xdot.h
@@ -128,7 +128,7 @@ struct _xdot_op {
       xdot_color grad_color;   /* xd_grad_fill_color, xd_grad_pen_color */
       xdot_font font;          /* xd_font */
       char* style;             /* xd_style */
-      int fontchar;            /* xd_fontchar */
+      unsigned int fontchar;   /* xd_fontchar */
     } u;
     drawfunc_t drawfunc;
 };
diff --git a/plugin/core/gvrender_core_dot.c b/plugin/core/gvrender_core_dot.c
index bdc8d8e00..d3c3b8f8f 100644
--- a/plugin/core/gvrender_core_dot.c
+++ b/plugin/core/gvrender_core_dot.c
@@ -54,7 +54,7 @@ typedef enum {
 //    #pragma comment( lib, "ingraphs.lib" )
 #endif
 
-#define XDOTVERSION "1.6"
+#define XDOTVERSION "1.7"
 
 #define NUMXBUFS (EMIT_HLABEL+1)
 /* There are as many xbufs as there are values of emit_state_t.
@@ -535,6 +535,8 @@ static void dot_end_graph(GVJ_t *job)
     g->clos->disc.io = io_save;
 }
 
+static unsigned int flag_masks[] = { 0x1F, 0x3F, 0x7F };
+
 static void xdot_textspan(GVJ_t * job, pointf p, textspan_t * span)
 {
     emit_state_t emit_state = job->obj->emit_state;
@@ -565,10 +567,10 @@ static void xdot_textspan(GVJ_t * job, pointf p, textspan_t * span)
     else
 	flags = 0;
     if (xd->version >= 15) {
-	unsigned int mask = (xd->version >= 16?0x3F:0x1F);
+	unsigned int mask = flag_masks[xd->version-15];
 	unsigned int bits = flags & mask;
 	if (textflags[emit_state] != bits) {
-	    sprintf (buf, "t %d ", bits);
+	    sprintf (buf, "t %u ", bits);
 	    agxbput(xbufs[emit_state], buf);
 	    textflags[emit_state] = bits;
 	}
diff --git a/plugin/core/gvrender_core_svg.c b/plugin/core/gvrender_core_svg.c
index 03a3e850d..59327ca9f 100644
--- a/plugin/core/gvrender_core_svg.c
+++ b/plugin/core/gvrender_core_svg.c
@@ -348,7 +348,7 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
     obj_state_t *obj = job->obj;
     PostscriptAlias *pA;
     char *family = NULL, *weight = NULL, *stretch = NULL, *style = NULL;
-    int flags;
+    unsigned int flags;
 
     gvputs(job, "<text");
     switch (span->just) {
@@ -404,13 +404,17 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
 	    gvprintf(job, " font-weight=\"bold\"");
 	if ((flags & HTML_IF) && !style)
 	    gvprintf(job, " font-style=\"italic\"");
-	if ((flags & (HTML_UL|HTML_S))) {
+	if ((flags & (HTML_UL|HTML_S|HTML_OL))) {
 	    int comma = 0;
 	    gvprintf(job, " text-decoration=\"");
 	    if ((flags & HTML_UL)) {
 		gvprintf(job, "underline");
 		comma = 1;
 	    }
+	    if ((flags & HTML_OL)) {
+		gvprintf(job, "%soverline", (comma?",":""));
+		comma = 1;
+	    }
 	    if ((flags & HTML_S))
 		gvprintf(job, "%sline-through", (comma?",":""));
 	    gvprintf(job, "\"");
diff --git a/plugin/pango/gvrender_pango.c b/plugin/pango/gvrender_pango.c
index 6be3a25bd..394be35cc 100644
--- a/plugin/pango/gvrender_pango.c
+++ b/plugin/pango/gvrender_pango.c
@@ -62,6 +62,8 @@ static int dotted_len = ARRAY_SIZE(dotted);
 #include <cairo-svg.h>
 #endif
 
+static void cairogen_polyline(GVJ_t * job, pointf * A, int n);
+
 static void cairogen_set_color(cairo_t * cr, gvcolor_t * color)
 {
     cairo_set_source_rgba(cr, color->u.RGBA[0], color->u.RGBA[1],
@@ -223,6 +225,7 @@ static void cairogen_textspan(GVJ_t * job, pointf p, textspan_t * span)
 {
     obj_state_t *obj = job->obj;
     cairo_t *cr = (cairo_t *) job->context;
+    pointf A[2];
 
     cairo_set_dash (cr, dashed, 0, 0.0);  /* clear any dashing */
     cairogen_set_color(cr, &(obj->pencolor));
@@ -246,6 +249,13 @@ static void cairogen_textspan(GVJ_t * job, pointf p, textspan_t * span)
     cairo_scale(cr, POINTS_PER_INCH / FONT_DPI, POINTS_PER_INCH / FONT_DPI);
     pango_cairo_show_layout(cr, (PangoLayout*)(span->layout));
     cairo_restore(cr);
+
+    if ((span->font) && (span->font->flags & HTML_OL)) {
+	A[0].x = p.x;
+	A[1].x = p.x + span->size.x;
+	A[1].y = A[0].y = p.y;
+	cairogen_polyline(job, A, 2);
+    }
 }
 
 static void cairogen_set_penstyle(GVJ_t *job, cairo_t *cr)
-- 
2.40.0