From 7006a00dd484cfe2cfe7b58eb5e4391fdb1fd1d4 Mon Sep 17 00:00:00 2001 From: oetiker Date: Tue, 7 Jun 2005 22:10:01 +0000 Subject: [PATCH] make pdf/eps/svg formats utf8 aware too -- Peter Speck git-svn-id: svn://svn.oetiker.ch/rrdtool/branches/1.2/program@612 a5681a0c-68f1-0310-ab6d-d61299d08faa --- src/rrd_afm.c | 44 +++++++++++---- src/rrd_afm.h | 17 ++++-- src/rrd_gfx.c | 151 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 161 insertions(+), 51 deletions(-) diff --git a/src/rrd_afm.c b/src/rrd_afm.c index 2a2ec6c..f9acc16 100644 --- a/src/rrd_afm.c +++ b/src/rrd_afm.c @@ -13,7 +13,6 @@ #include "rrd_afm.h" #include "rrd_afm_data.h" -#include #include #ifdef HAVE_STRING_H @@ -187,24 +186,49 @@ static long afm_find_kern(const afm_fontinfo *fontinfo, } /* measure width of a text string */ -double afm_get_text_width ( double UNUSED(start), const char* font, double size, - double UNUSED(tabwidth), const char* text) +double afm_get_text_width( double start, const char* font, double size, + double tabwidth, const char* text) +{ +#ifdef HAVE_MBSTOWCS + size_t clen = strlen(text) + 1; + wchar_t *cstr = malloc(sizeof(wchar_t) * clen); /* yes we are allocating probably too much here, I know */ + int text_count = mbstowcs(cstr, text, clen); + double w; + if (text_count == -1) + text_count = mbstowcs(cstr, "Enc-Err", 6); +#ifdef __APPLE__ + while (text_count > 0) { + text_count--; + cstr[text_count] = afm_fix_osx_charset(cstr[text_count]); /* unsafe macro */ + } +#endif + w = afm_get_text_width_wide(start, font, size, tabwidth, cstr); + free(cstr); + return w; +#else + return afm_get_text_width_wide(start, font, size, tabwidth, text); +#endif +} + +double afm_get_text_width_wide( double UNUSED(start), const char* font, double size, + double UNUSED(tabwidth), const afm_char* text) { const afm_fontinfo *fontinfo = afm_findfont(font); long width = 0; double widthf; - const unsigned char *up = (const unsigned char*)text; + const afm_char *up = text; DLOG((stderr, "================= %s\n", text)); - if (fontinfo == NULL) - return size * strlen(text); + if (fontinfo == NULL) { + while (*up) + up++; + return size * (up - text); + } while (1) { afm_unicode ch1, ch2; int idx1, kern_idx; if ((ch1 = *up) == 0) - break; - ch1 = afm_host2unicode(ch1); /* unsafe macro */ + break; ch2 = *++up; - ch2 = afm_host2unicode(ch2); /* unsafe macro */ DLOG((stderr, "------------- Loop: %d + %d (%c%c) at %d\n", ch1, ch2, ch1, ch2 ? ch2 : ' ', (up - (const unsigned char*)text) - 1)); @@ -217,7 +241,7 @@ double afm_get_text_width ( double UNUSED(start), const char* font, double size, if (ch1_new) { ch1 = ch1_new; idx1 = afm_find_char_index(fontinfo, ch1); - ch2 = afm_host2unicode(*++up); + ch2 = *++up; DLOG((stderr, " -> idx1 = %d, ch2 = %d (%c)\n", idx1, ch2, ch2 ? ch2 : ' ')); } diff --git a/src/rrd_afm.h b/src/rrd_afm.h index cedc994..9d12e49 100644 --- a/src/rrd_afm.h +++ b/src/rrd_afm.h @@ -7,6 +7,13 @@ #ifndef RRD_AFM_H #define RRD_AFM_H +#include + +#ifdef HAVE_MBSTOWCS +#define afm_char wchar_t +#else +#define afm_char unsigned char +#endif /* If the font specified by the name parameter in the routes below is not found @@ -21,8 +28,10 @@ /* measure width of a text string */ /* fontname can be full name or postscript name */ -double afm_get_text_width ( double start, const char* font, double size, +double afm_get_text_width( double start, const char* font, double size, double tabwidth, const char* text); +double afm_get_text_width_wide( double start, const char* font, double size, + double tabwidth, const afm_char* text); double afm_get_ascender(const char* font, double size); double afm_get_descender(const char* font, double size); @@ -35,11 +44,11 @@ const char *afm_get_font_name(const char* font); #ifdef __APPLE__ /* need charset conversion from macintosh to unicode. */ extern const unsigned char afm_mac2iso[128]; -#define afm_host2unicode(c) \ - ( (c) >= 128 ? afm_mac2iso[(c) - 128] : (c)) +#define afm_fix_osx_charset(c) \ + ( (c) >= 128 && (c) <= 255 ? afm_mac2iso[(c) - 128] : (c)) #else /* UNSAFE macro */ -#define afm_host2unicode(a_unsigned_char) ((unsigned int)(a_unsigned_char)) +#define afm_fix_osx_charset(x) (x) #endif #endif diff --git a/src/rrd_gfx.c b/src/rrd_gfx.c index d01b904..a241fc2 100644 --- a/src/rrd_gfx.c +++ b/src/rrd_gfx.c @@ -415,6 +415,7 @@ gfx_string gfx_string_create(gfx_canvas_t *canvas, FT_Face face,const char *text have a witespace glyph inserted, but set its width such that the distance of the new right edge is x times tabwidth from 0,0 where x is an integer. */ unsigned int letter = cstr[n]; + letter = afm_fix_osx_charset(letter); /* unsafe macro */ gottab = 0; if (letter == '\\' && n+1 < string->count && cstr[n+1] == 't'){ @@ -1038,37 +1039,46 @@ static void svg_close_tag_empty_node(FILE *fp) static void svg_write_text(FILE *fp, const char *text) { - const unsigned char *p, *start, *last; - unsigned int ch; - p = (const unsigned char*)text; - if (!p) - return; - /* trim leading spaces */ - while (*p == ' ') - p++; - start = p; - /* trim trailing spaces */ - last = p - 1; - while ((ch = *p) != 0) { - if (ch != ' ') - last = p; - p++; - } - /* encode trimmed text */ - p = start; - while (p <= last) { +#ifdef HAVE_MBSTOWCS + size_t clen; + wchar_t *p, *cstr, ch; + int text_count; + if (!text) + return; + clen = strlen(text) + 1; + cstr = malloc(sizeof(wchar_t) * clen); + text_count = mbstowcs(cstr, text, clen); + if (text_count == -1) + text_count = mbstowcs(cstr, "Enc-Err", 6); + p = cstr; +#else + const unsigned char *p = text, ch; + if (!p) + return; +#endif + while (1) { ch = *p++; - ch = afm_host2unicode(ch); /* unsafe macro */ + ch = afm_fix_osx_charset(ch); /* unsafe macro */ switch (ch) { + case 0: +#ifdef HAVE_MBSTOWCS + free(cstr); +#endif + return; case '&': fputs("&", fp); break; case '<': fputs("<", fp); break; case '>': fputs(">", fp); break; case '"': fputs(""", fp); break; default: - if (ch >= 127) - fprintf(fp, "&#%d;", ch); + if (ch == 32) { + if (p <= cstr + 1 || !*p || *p == 32) + fputs(" ", fp); /* non-breaking space in unicode */ + else + fputc(32, fp); + } else if (ch < 32 || ch >= 127) + fprintf(fp, "&#%d;", (int)ch); else - putc(ch, fp); + putc((char)ch, fp); } } } @@ -1707,10 +1717,26 @@ static void eps_write_linearea(eps_state *state, gfx_node_t *node) static void eps_write_text(eps_state *state, gfx_node_t *node) { FILE *fp = state->fp; - const char *p; const char *ps_font = afm_get_font_postscript_name(node->filename); int lineLen = 0; pdf_coords g; +#ifdef HAVE_MBSTOWCS + size_t clen; + wchar_t *p, *cstr, ch; + int text_count; + if (!node->text) + return; + clen = strlen(node->text) + 1; + cstr = malloc(sizeof(wchar_t) * clen); + text_count = mbstowcs(cstr, node->text, clen); + if (text_count == -1) + text_count = mbstowcs(cstr, "Enc-Err", 6); + p = cstr; +#else + const unsigned char *p = node->text, ch; + if (!p) + return; +#endif pdf_calc(state->page_height, node, &g); eps_set_color(state, node->color); if (strcmp(ps_font, state->font) || node->size != state->font_size) { @@ -1723,11 +1749,11 @@ static void eps_write_text(eps_state *state, gfx_node_t *node) fputs("T1 ", fp); fputs("(", fp); lineLen = 20; - p = node->text; while (1) { - unsigned char ch = *(unsigned char*)p; + ch = *p; if (!ch) break; + ch = afm_fix_osx_charset(ch); /* unsafe macro */ if (++lineLen > 70) { fputs("\\\n", fp); /* backslash and \n */ lineLen = 0; @@ -1750,7 +1776,9 @@ static void eps_write_text(eps_state *state, gfx_node_t *node) fputs("\\t", fp); break; default: - if (ch >= 126 || ch < 32) { + if (ch > 255) { + fputc('?', fp); + } else if (ch >= 126 || ch < 32) { fprintf(fp, "\\%03o", ch); lineLen += 3; } else { @@ -1759,6 +1787,9 @@ static void eps_write_text(eps_state *state, gfx_node_t *node) } p++; } +#ifdef HAVE_MBSTOWCS + free(cstr); +#endif if (node->angle) { /* can't use svg_write_number as 2 decimals is far from enough to avoid skewed text */ @@ -1918,6 +1949,17 @@ static void pdf_put(pdf_buffer *buf, const char *text, int len) buf->current_size += len; } +static void pdf_put_char(pdf_buffer *buf, char c) +{ + if (buf->alloc_size >= buf->current_size + 1) { + buf->data[buf->current_size++] = c; + } else { + char tmp[1]; + tmp[0] = (char)c; + pdf_put(buf, tmp, 1); + } +} + static void pdf_puts(pdf_buffer *buf, const char *text) { pdf_put(buf, text, strlen(text)); @@ -1948,18 +1990,23 @@ static void pdf_putnumber(pdf_buffer *buf, double d) pdf_puts(buf, tmp); } -static void pdf_put_string_contents(pdf_buffer *buf, const char *text) +static void pdf_put_string_contents_wide(pdf_buffer *buf, const afm_char *text) { - const char *p = text; + const afm_char *p = text; while (1) { - unsigned char ch = *(unsigned char*)p; + afm_char ch = *p; + ch = afm_fix_osx_charset(ch); /* unsafe macro */ switch (ch) { - case 0: return; + case 0: + return; case '(': + pdf_puts(buf, "\\("); + break; case ')': + pdf_puts(buf, "\\)"); + break; case '\\': - pdf_puts(buf, "\\"); - pdf_put(buf, p, 1); + pdf_puts(buf, "\\\\"); break; case '\n': pdf_puts(buf, "\\n"); @@ -1971,18 +2018,48 @@ static void pdf_put_string_contents(pdf_buffer *buf, const char *text) pdf_puts(buf, "\\t"); break; default: - if (ch >= 126 || ch < 32) { + if (ch > 255) { + pdf_put_char(buf, '?'); + } else if (ch >= 126 || ch < 32) { + pdf_put_char(buf, ch); + } else if (ch >= 0 && ch <= 255) { char tmp[10]; - snprintf(tmp, sizeof(tmp), "\\%03o", ch); + snprintf(tmp, sizeof(tmp), "\\%03o", (int)ch); pdf_puts(buf, tmp); - } else { - pdf_put(buf, p, 1); } } p++; } } +static void pdf_put_string_contents(pdf_buffer *buf, const char *text) +{ +#ifdef HAVE_MBSTOWCS + size_t clen = strlen(text) + 1; + wchar_t *cstr = malloc(sizeof(wchar_t) * clen); + int text_count = mbstowcs(cstr, text, clen); + if (text_count == -1) + text_count = mbstowcs(cstr, "Enc-Err", 6); + pdf_put_string_contents_wide(buf, cstr); +#if 0 + if (*text == 'W') { + fprintf(stderr, "Decoding utf8 for '%s'\n", text); + wchar_t *p = cstr; + char *pp = text; + fprintf(stderr, "sz wc = %d\n", sizeof(wchar_t)); + while (*p) { + fprintf(stderr, " %d = %c versus %d = %c\n", *p, (char)*p, 255 & (int)*pp, *pp); + p++; + pp++; + } + } +#endif + free(cstr); +#else + pdf_put_string_contents_wide(buf, text); +#endif +} + static void pdf_init_object(pdf_state *state, pdf_buffer *buf) { pdf_init_buffer(state, buf); -- 2.30.2