1 /****************************************************************************
2 * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007
3 ****************************************************************************
4 * rrd_afm.h Parsing afm tables to find width of strings.
5 ****************************************************************************
9 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(HAVE_CONFIG_H)
10 #include "../win32/config.h"
13 #include "../rrd_config.h"
18 #include "rrd_afm_data.h"
30 # define DLOG(x) fprintf x
36 /* Adobe SVG View and Batik 1.1.1 can't handle ligatures.
37 So disable it as we just waste speed.
38 Besides, it doesn't matter much in normal text.
40 #define ENABLE_LIGATURES 0
42 static const afm_fontinfo *afm_last_used_font = NULL;
43 static const char *last_unknown_font = NULL;
45 #define is_font(p, name) \
46 (!strcmp(p->postscript_name, name) || !strcmp(p->fullname, name))
48 static const afm_fontinfo *afm_searchfont(
52 const afm_fontinfo *p = afm_last_used_font;
54 if (p && is_font(p, name))
57 for (i = 0; i < afm_fontinfo_count; i++, p++) {
58 if (is_font(p, name)) {
59 afm_last_used_font = p;
67 /* returns always a font, never NULL.
68 The rest of the code depends on the result never being NULL.
70 static const afm_fontinfo *afm_findfont(
73 const afm_fontinfo *p = afm_searchfont(name);
77 if (!last_unknown_font || strcmp(name, last_unknown_font)) {
78 fprintf(stderr, "Can't find font '%s'\n", name);
79 last_unknown_font = name;
81 p = afm_searchfont(RRD_AFM_DEFAULT_FONT);
84 return afm_fontinfolist; /* anything, just anything. */
87 const char *afm_get_font_postscript_name(
90 const afm_fontinfo *p = afm_findfont(font);
92 return p->postscript_name;
95 const char *afm_get_font_name(
98 const afm_fontinfo *p = afm_findfont(font);
103 double afm_get_ascender(
107 const afm_fontinfo *p = afm_findfont(font);
109 return size * p->ascender / 1000.0;
112 double afm_get_descender(
116 const afm_fontinfo *p = afm_findfont(font);
118 return size * p->descender / 1000.0;
121 static int afm_find_char_index(
122 const afm_fontinfo *fontinfo,
127 int numIndexChars, i;
133 indexP = fontinfo->highchars_index;
136 numIndexChars = fontinfo->highchars_count;
137 DLOG((stderr, " find highbit, num = %d\n", numIndexChars));
138 if (ch1 >= 161 && ch1 <= 255) {
140 DLOG((stderr, " 161, idx = %d -> %d\n", idx, indexP[idx]));
141 if (idx < numIndexChars && indexP[idx] == ch1) {
143 DLOG((stderr, " 161-guessed ok to %d\n", idx));
147 for (i = 0; i < numIndexChars; i++) {
148 DLOG((stderr, " compares to %d -> %d\n", indexP[i], i));
149 if (indexP[i] == ch1)
152 DLOG((stderr, "Did not find %d in highchars_index ??\n", ch1));
157 static afm_cunicode afm_find_combined_ligature(
158 const afm_fontinfo *fontinfo,
162 afm_cunicode *p = fontinfo->ligatures;
163 int num = fontinfo->ligatures_count;
168 DLOG((stderr, " find-lig, num = %d\n", num));
169 for (i = 0; i < num; i++, p += 3) {
170 DLOG((stderr, " lig: %d + %d -> %d (%c %c %c)\n",
171 p[0], p[1], p[2], p[0], p[1], p[2]));
172 if (ch1 == *p && ch2 == p[1]) {
173 DLOG((stderr, " matches.\n"));
181 #define READ_ESCAPED(p, val) \
182 if ((val = *p++) == 0) { \
184 } else if (!--val) { \
190 static long afm_find_kern(
191 const afm_fontinfo *fontinfo,
195 afm_cuint8 *p8 = fontinfo->kerning_data + kern_idx;
198 READ_ESCAPED(p8, num);
199 DLOG((stderr, " find kern, num pairs = %d\n", num));
203 READ_ESCAPED(p8, ch);
204 DLOG((stderr, " pair-char = %d\n", ch));
206 DLOG((stderr, " got kern = %d\n", *(afm_csint8 *) p8));
207 return *(afm_csint8 *) p8;
215 /* measure width of a text string */
216 double afm_get_text_width(
224 size_t clen = strlen(text) + 1;
225 wchar_t *cstr = malloc(sizeof(wchar_t) * clen); /* yes we are allocating probably too much here, I know */
226 int text_count = mbstowcs(cstr, text, clen);
229 if (text_count == -1)
230 text_count = mbstowcs(cstr, "Enc-Err", 6);
232 while (text_count > 0) {
234 cstr[text_count] = afm_fix_osx_charset(cstr[text_count]); /* unsafe macro */
237 w = afm_get_text_width_wide(start, font, size, tabwidth, cstr);
241 return afm_get_text_width_wide(start, font, size, tabwidth, text);
245 double afm_get_text_width_wide(
246 double UNUSED(start),
249 double UNUSED(tabwidth),
250 const afm_char * text)
252 const afm_fontinfo *fontinfo = afm_findfont(font);
255 const afm_char *up = text;
257 DLOG((stderr, "================= %s\n", text));
258 if (fontinfo == NULL) {
261 return size * (up - text);
264 afm_unicode ch1, ch2;
267 if ((ch1 = *up) == 0)
270 DLOG((stderr, "------------- Loop: %d + %d (%c%c) at %d\n",
271 ch1, ch2, ch1, ch2 ? ch2 : ' ',
272 (up - (const unsigned char *) text) - 1));
273 idx1 = afm_find_char_index(fontinfo, ch1);
274 DLOG((stderr, " idx1 = %d\n", idx1));
278 afm_find_combined_ligature(fontinfo, ch1, ch2);
280 DLOG((stderr, " lig-ch = %d\n", ch1_new));
283 idx1 = afm_find_char_index(fontinfo, ch1);
285 DLOG((stderr, " -> idx1 = %d, ch2 = %d (%c)\n",
286 idx1, ch2, ch2 ? ch2 : ' '));
290 width += fontinfo->widths[idx1];
291 DLOG((stderr, "Plain width of %d = %d\n", ch1,
292 fontinfo->widths[idx1]));
293 if (fontinfo->kerning_index && ch2) {
294 kern_idx = fontinfo->kerning_index[idx1];
295 DLOG((stderr, " kern_idx = %d\n", kern_idx));
297 width += afm_find_kern(fontinfo, kern_idx, ch2);
300 widthf = (width * 6 / 1000.0) * size;
301 DLOG((stderr, "Returns %ld (%ld) -> %f\n", width, width * 6, widthf));
306 const unsigned char afm_mac2iso[128] = {
307 '\xC4', '\xC5', '\xC7', '\xC9', '\xD1', '\xD6', '\xDC', '\xE1', /* 80 */
308 '\xE0', '\xE2', '\xE4', '\xE3', '\xE5', '\xE7', '\xE9', '\xE8', /* 88 */
309 '\xEA', '\xEB', '\xED', '\xEC', '\xEE', '\xEF', '\xF1', '\xF3', /* 90 */
310 '\xF2', '\xF4', '\xF6', '\xF5', '\xFA', '\xF9', '\xFB', '\xFC', /* 98 */
311 '\xDD', '\xB0', '\xA2', '\xA3', '\xA7', ' ', '\xB6', '\xDF', /* A0 */
312 '\xAE', '\xA9', ' ', '\xB4', '\xA8', ' ', '\xC6', '\xD8', /* A8 */
313 ' ', '\xB1', '\xBE', ' ', '\xA5', '\xB5', ' ', ' ', /* B0 */
314 '\xBD', '\xBC', ' ', '\xAA', '\xBA', ' ', '\xE6', '\xF8', /* B8 */
315 '\xBF', '\xA1', '\xAC', ' ', ' ', ' ', ' ', '\xAB', /* C0 */
316 '\xBB', ' ', '\xA0', '\xC0', '\xC3', '\xD5', ' ', '\xA6', /* C8 */
317 '\xAD', ' ', '"', '"', '\'', '\'', '\xF7', '\xD7', /* D0 */
318 '\xFF', ' ', ' ', '\xA4', '\xD0', '\xF0', '\xDE', '\xFE', /* D8 */
319 '\xFD', '\xB7', ' ', ' ', ' ', '\xC2', '\xCA', '\xC1', /* E0 */
320 '\xCB', '\xC8', '\xCD', '\xCE', '\xCF', '\xCC', '\xD3', '\xD4', /* E8 */
321 ' ', '\xD2', '\xDA', '\xDB', '\xD9', ' ', ' ', ' ', /* F0 */
322 '\xAF', ' ', ' ', ' ', '\xB8', ' ', ' ', ' ', /* F8 */