1/* Hello, Emacs, this is -*-C-*- */
2
3/* GNUPLOT - estimate.trm */
4
5/*
6 * This file is included by ../src/term.c via term.h.
7 *
8 * This terminal driver supports:
9 *   On return from ENHest_put_text()
10 *	(*term)->xmax = estimated string width
11 *	(*term)->ymax = estimated string height (in tenths of a character height)
12 *	ENHest_plaintext = non-enhanced text approximation of original string
13 *
14 * AUTHORS
15 *
16 *   Ethan A Merritt - Dec 2004
17 *
18 */
19#include "driver.h"
20
21#ifdef TERM_PROTO
22TERM_PUBLIC void ENHest_put_text(unsigned int x, unsigned int y, const char str[]);
23TERM_PUBLIC void ENHest_OPEN(char * fontname, double fontsize, double base,
24				TBOOLEAN widthflag, TBOOLEAN showflag, int overprint);
25TERM_PUBLIC void ENHest_FLUSH(void);
26#endif /* TERM_PROTO */
27
28#ifdef TERM_BODY
29
30static double ENHest_x, ENHest_y;
31static double ENHest_xsave, ENHest_ysave;
32static double ENHest_fragment_width;
33static double ENHest_fontsize;
34static double ENHest_min_height, ENHest_max_height;
35static double ENHest_total_width;
36static char *ENHest_plaintext = NULL;
37static int ENHest_plaintext_buflen = 0;
38static int ENHest_plaintext_pos = 0;
39
40static TBOOLEAN ENHest_opened_string;
41static TBOOLEAN ENHest_show = TRUE;
42static int ENHest_overprint = 0;
43static TBOOLEAN ENHest_widthflag = TRUE;
44#define ENHest_font ""
45static double ENHest_base;
46
47/* Internal routines for UTF-8 support */
48static size_t strwidth_utf8(const char *s);
49
50TERM_PUBLIC void
51ENHest_OPEN(
52    char *fontname,
53    double fontsize, double base,
54    TBOOLEAN widthflag, TBOOLEAN showflag,
55    int overprint)
56{
57    /* There are two special cases:
58     * overprint = 3 means save current position
59     * overprint = 4 means restore saved position
60     */
61    if (overprint == 3) {
62	ENHest_xsave = ENHest_x;
63	ENHest_ysave = ENHest_y;
64	return;
65    } else if (overprint == 4) {
66	ENHest_x = ENHest_xsave;
67	ENHest_y = ENHest_ysave;
68	return;
69    }
70
71    if (!ENHest_opened_string) {
72	ENHest_opened_string = TRUE;
73	/* Start new text fragment */
74	    ENHest_fragment_width = 0;
75	/* font size will be used to estimate width of each character */
76	    ENHest_fontsize = fontsize > 2.0 ? 1.0 : fontsize;
77	/* Scale fractional font height */
78	    ENHest_base = base * 1.0;
79	    if (ENHest_max_height < ENHest_base+1.0*fontsize)
80		ENHest_max_height = ENHest_base+1.0*fontsize;
81	    if (ENHest_min_height > ENHest_base)
82		ENHest_min_height = ENHest_base;
83	    FPRINTF((stderr,"ENHest_OPEN: base %g fontsize %g  min %g max %g\n",
84	    	    base,fontsize,ENHest_min_height,ENHest_max_height));
85	/* Keep track of whether we are supposed to show this string */
86	    ENHest_show = showflag;
87	/* 0/1/2  no overprint / 1st pass / 2nd pass */
88	    ENHest_overprint = overprint;
89	/* widthflag FALSE means do not update text position after printing */
90	    ENHest_widthflag = widthflag;
91    }
92}
93
94TERM_PUBLIC void
95ENHest_FLUSH()
96{
97    double len = ENHest_fragment_width;
98
99    if (ENHest_opened_string) {
100	ENHest_fragment_width = 0;
101
102	if (!ENHest_widthflag)
103	    /* don't update position */
104	    ;
105	else if (ENHest_overprint == 1)
106	    /* First pass of overprint, leave position in center of fragment */
107	    ENHest_x += len / 2;
108	else
109	    /* Normal case is to update position to end of fragment */
110	    ENHest_x += len;
111
112	ENHest_total_width = GPMAX(ENHest_total_width, ENHest_x);
113	ENHest_opened_string = FALSE;
114    }
115}
116
117TERM_PUBLIC void
118ENHest_put_text(unsigned int x, unsigned int y, const char *str)
119{
120    /* Set up global variables needed by enhanced_recursion() */
121    ENHest_fontsize  = 1.0;
122    ENHest_opened_string = FALSE;
123    ENHest_max_height = 1.0;
124    ENHest_min_height = 0.0;
125    ENHest_total_width = 0.0;
126    strncpy(enhanced_escape_format,".",sizeof(enhanced_escape_format));
127
128    /* buffer in which we will return plaintext version of enhanced text string */
129    while (ENHest_plaintext_buflen <= strlen(str)) {
130	ENHest_plaintext_buflen += MAX_ID_LEN;
131	ENHest_plaintext = gp_realloc(ENHest_plaintext, ENHest_plaintext_buflen+1, "ENHest_plaintext");
132    }
133    ENHest_plaintext[0] = '\0';
134    ENHest_plaintext_pos = 0;
135
136    /* If no enhanced text processing is needed, strlen() is sufficient */
137    if (ignore_enhanced_text || (!strpbrk(str, "{}^_@&~\n") && !contains_unicode(str))) {
138	if (encoding == S_ENC_UTF8)
139	    term->xmax = strwidth_utf8(str);
140	else
141	    term->xmax = strlen(str);
142	term->ymax = 10;
143	strcpy(ENHest_plaintext, str);
144	return;
145    }
146
147    ENHest_x = x;
148    ENHest_y = y;
149
150    while (*(str = enhanced_recursion((char *)str, TRUE,
151    			ENHest_font, ENHest_fontsize,
152			0.0, TRUE, TRUE, 0))) {
153	(term->enhanced_flush)();
154
155	enh_err_check(str);
156	if (!*++str)
157	    break; /* end of string */
158    }
159
160    ENHest_plaintext[ENHest_plaintext_pos] = '\0';
161    if (ENHest_x > 0.0 && ENHest_x < 1.0)
162	ENHest_x = 1;
163    term->xmax = ENHest_total_width;
164    term->ymax = 10. * (ENHest_max_height - ENHest_min_height) + 0.5;
165}
166
167TERM_PUBLIC void
168ENHest_writec(int c)
169{
170    if (c == '\n') {
171	ENHest_FLUSH();
172	ENHest_opened_string = TRUE;
173	ENHest_min_height -= 1.0 * ENHest_fontsize;
174	ENHest_base -= 1.0 * ENHest_fontsize;
175	ENHest_x = 0;
176    }
177
178    if (encoding == S_ENC_UTF8) {
179	/* Skip all but the first byte of UTF-8 multi-byte characters. */
180	if ((c & 0xc0) != 0x80) {
181	    ENHest_fragment_width += ENHest_fontsize;
182	    /* [most] characters above 0x3000 are square CJK glyphs, */
183	    /* which are wider than western characters.              */
184	    if ((unsigned char)c >= 0xec)
185		ENHest_fragment_width += ENHest_fontsize;
186	}
187    } else
188	ENHest_fragment_width += ENHest_fontsize;
189
190    ENHest_plaintext[ENHest_plaintext_pos++] = c;
191}
192
193/*
194 * This routine accounts for multi-byte characters in UTF-8.
195 * NB:  It does not return the _number_ of characters in the string, but
196 * rather their approximate _width_ in units of typical character width.
197 * As with the ENHest_writec() routine, it approximates the width of characters
198 * above unicode 0x3000 as being twice that of western alphabetic characters.
199 */
200size_t strwidth_utf8(const char *s) {
201    int i = 0, j = 0;
202    while (s[i]) {
203       if ((s[i] & 0xc0) != 0x80) {
204           j++;
205	   if ((unsigned char)(s[i]) >= 0xe3)
206		j++;
207       }
208       i++;
209    }
210    return j;
211}
212
213
214static struct termentry ENHest = {
215    "estimate", NULL,
216    1, 1, 1, 1, 1, 1,
217    NULL, NULL, NULL,
218    NULL, NULL, NULL, NULL, NULL,
219    NULL, ENHest_put_text, NULL,
220    NULL, NULL, NULL, NULL,
221    0, 0,			/* pointsize, flags */
222    NULL, NULL, NULL, NULL
223#ifdef USE_MOUSE
224    , NULL, NULL, NULL, NULL, NULL
225#endif
226    , NULL, NULL, NULL, NULL
227    , NULL
228    , ENHest_OPEN, ENHest_FLUSH, ENHest_writec
229};
230
231#endif /* TERM_BODY */
232