00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "render.h"
00019 #include "htmltable.h"
00020 #include <limits.h>
00021
00022 static void storeline(graph_t *g, textlabel_t *lp, char *line, char terminator)
00023 {
00024 pointf size;
00025 textpara_t *para;
00026 int oldsz = lp->u.txt.nparas + 1;
00027
00028 lp->u.txt.para = ZALLOC(oldsz + 1, lp->u.txt.para, textpara_t, oldsz);
00029 para = &(lp->u.txt.para[lp->u.txt.nparas]);
00030 para->str = line;
00031 para->just = terminator;
00032 if (line && line[0])
00033 size = textsize(g, para, lp->fontname, lp->fontsize);
00034 else {
00035 size.x = 0.0;
00036 para->height = size.y = (int)(lp->fontsize * LINESPACING);
00037 }
00038
00039 lp->u.txt.nparas++;
00040
00041 lp->dimen.x = MAX(lp->dimen.x, size.x);
00042
00043 lp->dimen.y += size.y;
00044 }
00045
00046
00047 static pointf label_size(graph_t * g, textlabel_t * lp)
00048 {
00049 char c, *p, *line, *lineptr, *str = lp->text;
00050 unsigned char byte = 0x00;
00051 int charset = GD_charset(g);
00052
00053 lp->dimen.x = lp->dimen.y = 0.0;
00054 if (*str == '\0')
00055 return lp->dimen;
00056
00057 line = lineptr = NULL;
00058 p = str;
00059 line = lineptr = N_GNEW(strlen(p) + 1, char);
00060 *line = 0;
00061 while ((c = *p++)) {
00062 byte = (unsigned int) c;
00063
00064
00065
00066
00067
00068 if ((charset == CHAR_BIG5) && 0xA1 <= byte && byte <= 0xFE) {
00069 *lineptr++ = c;
00070 c = *p++;
00071 *lineptr++ = c;
00072 if (!c)
00073 break;
00074 } else {
00075 if (c == '\\') {
00076 switch (*p) {
00077 case 'n':
00078 case 'l':
00079 case 'r':
00080 *lineptr++ = '\0';
00081 storeline(g, lp, line, *p);
00082 line = lineptr;
00083 break;
00084 default:
00085 *lineptr++ = *p;
00086 }
00087 if (*p)
00088 p++;
00089
00090 } else if (c == '\n') {
00091 *lineptr++ = '\0';
00092 storeline(g, lp, line, 'n');
00093 line = lineptr;
00094 } else {
00095 *lineptr++ = c;
00096 }
00097 }
00098 }
00099
00100 if (line != lineptr) {
00101 *lineptr++ = '\0';
00102 storeline(g, lp, line, 'n');
00103 }
00104
00105 return lp->dimen;
00106 }
00107
00108
00109
00110
00111 void
00112 size_label (graph_t* g, textlabel_t* rv)
00113 {
00114 char *s;
00115
00116 switch (GD_charset(g->root)) {
00117 case CHAR_LATIN1:
00118 s = latin1ToUTF8(rv->text);
00119 break;
00120 default:
00121 s = htmlEntityUTF8(rv->text);
00122 break;
00123 }
00124 free(rv->text);
00125 rv->text = s;
00126 label_size(g, rv);
00127 }
00128
00129
00130
00131
00132
00133 textlabel_t *make_label(graph_t *g, int kind, char *str, double fontsize,
00134 char *fontname, char *fontcolor)
00135 {
00136 textlabel_t *rv = NEW(textlabel_t);
00137
00138 rv->text = str;
00139 rv->fontname = fontname;
00140 rv->fontcolor = fontcolor;
00141 rv->fontsize = fontsize;
00142 if (kind & LT_HTML)
00143 rv->html = TRUE;
00144 if (kind == LT_NONE)
00145 size_label(g, rv);
00146 return rv;
00147 }
00148
00149 static void free_textpara(textpara_t * tl)
00150 {
00151 if (tl) {
00152 if (tl->str)
00153 free(tl->str);
00154 if (tl->layout && tl->free_layout)
00155 tl->free_layout (tl->layout);
00156 free(tl);
00157 }
00158 }
00159
00160 void free_label(textlabel_t * p)
00161 {
00162 if (p) {
00163 free(p->text);
00164 if (p->html) {
00165 free_html_label(p->u.html, 1);
00166 } else {
00167 free_textpara(p->u.txt.para);
00168 }
00169 free(p);
00170 }
00171 }
00172
00173 void emit_label(GVJ_t * job, emit_state_t emit_state, textlabel_t * lp)
00174 {
00175 obj_state_t *obj = job->obj;
00176 double halfwidth_x, center_x, left_x, right_x;
00177 int i;
00178 pointf p;
00179 emit_state_t old_emit_state;
00180
00181 old_emit_state = obj->emit_state;
00182 obj->emit_state = emit_state;
00183
00184 if (lp->html) {
00185 emit_html_label(job, lp->u.html, lp);
00186 return;
00187 }
00188
00189
00190 if (lp->u.txt.nparas < 1)
00191 return;
00192
00193 p.x = lp->p.x;
00194 p.y = lp->p.y;
00195
00196
00197 halfwidth_x = (lp->dimen.x + lp->d.x) / 2.0;
00198
00199 center_x = p.x;
00200 left_x = center_x - halfwidth_x;
00201 right_x = center_x + halfwidth_x;
00202
00203
00204 p.y += (lp->dimen.y + lp->d.y) / 2.0 - lp->fontsize;
00205
00206 gvrender_begin_context(job);
00207 gvrender_set_pencolor(job, lp->fontcolor);
00208 gvrender_set_font(job, lp->fontname, lp->fontsize);
00209
00210 for (i = 0; i < lp->u.txt.nparas; i++) {
00211 switch (lp->u.txt.para[i].just) {
00212 case 'l':
00213 p.x = left_x;
00214 break;
00215 case 'r':
00216 p.x = right_x;
00217 break;
00218 default:
00219 case 'n':
00220 p.x = center_x;
00221 break;
00222 }
00223 gvrender_textpara(job, p, &(lp->u.txt.para[i]));
00224
00225
00226 p.y -= lp->u.txt.para[i].height;
00227 }
00228
00229 gvrender_end_context(job);
00230 obj->emit_state = old_emit_state;
00231 }
00232
00233 char *strdup_and_subst_obj(char *str, void *obj)
00234 {
00235 char c, *s, *p, *t, *newstr;
00236 char *g_str = "\\G", *n_str = "\\N", *e_str = "\\E", *h_str = "\\H", *t_str = "\\T";
00237 int g_len = 2, n_len = 2, e_len = 2, h_len = 2, t_len = 2, newlen = 0;
00238
00239
00240 switch (agobjkind(obj)) {
00241 case AGGRAPH:
00242 g_str = ((graph_t *)obj)->name;
00243 g_len = strlen(g_str);
00244 break;
00245 case AGNODE:
00246 g_str = ((node_t *)obj)->graph->name;
00247 g_len = strlen(g_str);
00248 n_str = ((node_t *)obj)->name;
00249 n_len = strlen(n_str);
00250 break;
00251 case AGEDGE:
00252 g_str = ((edge_t *)obj)->tail->graph->root->name;
00253 g_len = strlen(g_str);
00254 t_str = ((edge_t *)obj)->tail->name;
00255 t_len = strlen(t_str);
00256 h_str = ((edge_t *)obj)->head->name;
00257 h_len = strlen(h_str);
00258 if (((edge_t *)obj)->tail->graph->root->kind & AGFLAG_DIRECTED)
00259 e_str = "->";
00260 else
00261 e_str = "--";
00262 e_len = t_len + 2 + h_len;
00263 break;
00264 }
00265
00266
00267
00268
00269
00270
00271 for (s = str; (c = *s++);) {
00272 if (c == '\\') {
00273 switch (c = *s++) {
00274 case 'G':
00275 newlen += g_len;
00276 break;
00277 case 'N':
00278 newlen += n_len;
00279 break;
00280 case 'E':
00281 newlen += e_len;
00282 break;
00283 case 'H':
00284 newlen += h_len;
00285 break;
00286 case 'T':
00287 newlen += t_len;
00288 break;
00289 default:
00290 newlen += 2;
00291 }
00292 } else {
00293 newlen++;
00294 }
00295 }
00296
00297 newstr = gmalloc(newlen + 1);
00298
00299
00300 for (s = str, p = newstr; (c = *s++);) {
00301 if (c == '\\') {
00302 switch (c = *s++) {
00303 case 'G':
00304 for (t = g_str; (*p = *t++); p++);
00305 break;
00306 case 'N':
00307 for (t = n_str; (*p = *t++); p++);
00308 break;
00309 case 'E':
00310 for (t = t_str; (*p = *t++); p++);
00311 for (t = e_str; (*p = *t++); p++);
00312 for (t = h_str; (*p = *t++); p++);
00313 break;
00314 case 'T':
00315 for (t = t_str; (*p = *t++); p++);
00316 break;
00317 case 'H':
00318 for (t = h_str; (*p = *t++); p++);
00319 break;
00320 default:
00321 *p++ = '\\';
00322 *p++ = c;
00323 break;
00324 }
00325 } else {
00326 *p++ = c;
00327 }
00328 }
00329 *p++ = '\0';
00330 return newstr;
00331 }
00332
00333
00334
00335
00336
00337 static int xml_isentity(char *s)
00338 {
00339 s++;
00340 if (*s == '#') {
00341 s++;
00342 if (*s == 'x' || *s == 'X') {
00343 s++;
00344 while ((*s >= '0' && *s <= '9')
00345 || (*s >= 'a' && *s <= 'f')
00346 || (*s >= 'A' && *s <= 'F'))
00347 s++;
00348 } else {
00349 while (*s >= '0' && *s <= '9')
00350 s++;
00351 }
00352 } else {
00353 while ((*s >= 'a' && *s <= 'z')
00354 || (*s >= 'A' && *s <= 'Z'))
00355 s++;
00356 }
00357 if (*s == ';')
00358 return 1;
00359 return 0;
00360 }
00361
00362
00363 char *xml_string(char *s)
00364 {
00365 static char *buf = NULL;
00366 static int bufsize = 0;
00367 char *p, *sub, *prev = NULL;
00368 int len, pos = 0;
00369
00370 if (!buf) {
00371 bufsize = 64;
00372 buf = gmalloc(bufsize);
00373 }
00374
00375 p = buf;
00376 while (s && *s) {
00377 if (pos > (bufsize - 8)) {
00378 bufsize *= 2;
00379 buf = grealloc(buf, bufsize);
00380 p = buf + pos;
00381 }
00382
00383
00384 if (*s == '<') {
00385 sub = "<";
00386 len = 4;
00387 } else if (*s == '>') {
00388 sub = ">";
00389 len = 4;
00390 } else if (*s == '"') {
00391 sub = """;
00392 len = 6;
00393 } else if (*s == '-') {
00394 sub = "-";
00395 len = 5;
00396 } else if (*s == '\'') {
00397 sub = "'";
00398 len = 5;
00399 } else if (*s == ' ' && prev && *prev == ' ') {
00400
00401 sub = " ";
00402 len = 6;
00403 }
00404
00405 else if (*s == '&' && !(xml_isentity(s))) {
00406 sub = "&";
00407 len = 5;
00408 } else {
00409 sub = s;
00410 len = 1;
00411 }
00412 while (len--) {
00413 *p++ = *sub++;
00414 pos++;
00415 }
00416 prev = s;
00417 s++;
00418 }
00419 *p = '\0';
00420 return buf;
00421 }