1 /****************************************************************************
2 * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002
3 ****************************************************************************
4 * rrd_afm.h Parsing afm tables to find width of strings.
5 ****************************************************************************/
8 #include "rrd_afm_data.h"
15 # define DLOG(x) fprintf x
21 /* Adobe SVG View and Batik 1.1.1 can't handle ligatures.
22 So disable it as we just waste speed.
23 Besides, it doesn't matter much in normal text.
25 #define ENABLE_LIGATURES 0
27 static const afm_fontinfo *afm_last_used_font;
29 #define is_font(p, name) \
30 (!strcmp(p->postscript_name, name) || !strcmp(p->fullname, name))
32 static const afm_fontinfo *afm_searchfont(const char *name)
35 const afm_fontinfo *p = afm_last_used_font;
36 if (p && is_font(p, name))
39 for (i = 0; i < afm_fontinfo_count; i++, p++) {
40 if (is_font(p, name)) {
41 afm_last_used_font = p;
48 static const afm_fontinfo *afm_findfont(const char *name)
50 const afm_fontinfo *p = afm_searchfont(name);
53 if (1 || DEBUG) fprintf(stderr, "Can't find font '%s'\n", name);
54 p = afm_searchfont("Helvetica");
60 const char *afm_get_font_postscript_name(const char* font)
62 const afm_fontinfo *p = afm_findfont(font);
63 return p ? p->postscript_name : "Helvetica";
66 static int afm_find_char_index(const afm_fontinfo *fontinfo,
76 indexP = fontinfo->highchars_index;
79 numIndexChars = fontinfo->highchars_count;
80 DLOG((stderr, " find highbit, num = %d\n", numIndexChars));
81 if (ch1 >= 161 && ch1 <= 255) {
83 DLOG((stderr, " 161, idx = %d -> %d\n", idx, indexP[idx]));
84 if (idx < numIndexChars && indexP[idx] == ch1) {
86 DLOG((stderr, " 161-guessed ok to %d\n", idx));
90 for (i = 0; i < numIndexChars; i++) {
91 DLOG((stderr, " compares to %d -> %d\n", indexP[i], i));
95 DLOG((stderr, "Did not find %d in highchars_index ??\n", ch1));
100 static afm_cunicode afm_find_combined_ligature(const afm_fontinfo *fontinfo,
101 afm_cunicode ch1, afm_cunicode ch2)
103 afm_cunicode *p = fontinfo->ligatures;
104 int num = fontinfo->ligatures_count;
108 DLOG((stderr, " find-lig, num = %d\n", num));
109 for (i = 0; i < num; i++, p += 3) {
110 DLOG((stderr, " lig: %d + %d -> %d (%c %c %c)\n",
111 p[0], p[1], p[2], p[0], p[1], p[2]));
112 if (ch1 == *p && ch2 == p[1]) {
113 DLOG((stderr, " matches.\n"));
121 #define READ_ESCAPED(p, val) \
122 if ((val = *p++) == 0) { \
124 } else if (!--val) { \
130 static long afm_find_kern(const afm_fontinfo *fontinfo,
131 int kern_idx, afm_cunicode ch2)
133 afm_cuint8 *p8 = fontinfo->kerning_data + kern_idx;
135 READ_ESCAPED(p8, num);
136 DLOG((stderr, " find kern, num pairs = %d\n", num));
139 READ_ESCAPED(p8, ch);
140 DLOG((stderr, " pair-char = %d\n", ch));
142 DLOG((stderr, " got kern = %d\n", *(afm_csint8*)p8));
143 return *(afm_csint8*)p8;
151 /* measure width of a text string */
152 double afm_get_text_width ( double start, const char* font, double size,
153 double tabwidth, const char* text)
155 const afm_fontinfo *fontinfo = afm_findfont(font);
158 const unsigned char *up = (const unsigned char*)text;
159 DLOG((stderr, "================= %s\n", text));
160 if (fontinfo == NULL)
161 return size * strlen(text);
163 afm_unicode ch1, ch2;
165 if ((ch1 = *up) == 0)
167 ch1 = afm_host2unicode(ch1); /* unsafe macro */
169 ch2 = afm_host2unicode(ch2); /* unsafe macro */
170 DLOG((stderr, "------------- Loop: %d + %d (%c%c) at %d\n",
171 ch1, ch2, ch1, ch2 ? ch2 : ' ',
172 (up - (const unsigned char*)text) - 1));
173 idx1 = afm_find_char_index(fontinfo, ch1);
174 DLOG((stderr, " idx1 = %d\n", idx1));
177 int ch1_new = afm_find_combined_ligature(fontinfo, ch1, ch2);
178 DLOG((stderr, " lig-ch = %d\n", ch1_new));
181 idx1 = afm_find_char_index(fontinfo, ch1);
182 ch2 = afm_host2unicode(*++up);
183 DLOG((stderr, " -> idx1 = %d, ch2 = %d (%c)\n",
184 idx1, ch2, ch2 ? ch2 : ' '));
188 width += fontinfo->widths[idx1];
189 DLOG((stderr, "Plain width of %d = %d\n", ch1, fontinfo->widths[idx1]));
190 if (fontinfo->kerning_index && ch2) {
191 kern_idx = fontinfo->kerning_index[idx1];
192 DLOG((stderr, " kern_idx = %d\n", kern_idx));
194 width += afm_find_kern(fontinfo, kern_idx, ch2);
197 widthf = (width * 6 / 1000.0) * size;
198 DLOG((stderr, "Returns %ld (%ld) -> %f\n", width, width * 6, widthf));
203 const unsigned char afm_mac2iso[128] = {
204 '\xC4', '\xC5', '\xC7', '\xC9', '\xD1', '\xD6', '\xDC', '\xE1', // 80
205 '\xE0', '\xE2', '\xE4', '\xE3', '\xE5', '\xE7', '\xE9', '\xE8', // 88
206 '\xEA', '\xEB', '\xED', '\xEC', '\xEE', '\xEF', '\xF1', '\xF3', // 90
207 '\xF2', '\xF4', '\xF6', '\xF5', '\xFA', '\xF9', '\xFB', '\xFC', // 98
208 '\xDD', '\xB0', '\xA2', '\xA3', '\xA7', ' ', '\xB6', '\xDF', // A0
209 '\xAE', '\xA9', ' ', '\xB4', '\xA8', ' ', '\xC6', '\xD8', // A8
210 ' ', '\xB1', '\xBE', ' ', '\xA5', '\xB5', ' ', ' ', // B0
211 '\xBD', '\xBC', ' ', '\xAA', '\xBA', ' ', '\xE6', '\xF8', // B8
212 '\xBF', '\xA1', '\xAC', ' ', ' ', ' ', ' ', '\xAB', // C0
213 '\xBB', ' ', '\xA0', '\xC0', '\xC3', '\xD5', ' ', '\xA6', // C8
214 '\xAD', ' ', '"', '"', '\'', '\'', '\xF7', '\xD7', // D0
215 '\xFF', ' ', ' ', '\xA4', '\xD0', '\xF0', '\xDE', '\xFE', // D8
216 '\xFD', '\xB7', ' ', ' ', ' ', '\xC2', '\xCA', '\xC1', // E0
217 '\xCB', '\xC8', '\xCD', '\xCE', '\xCF', '\xCC', '\xD3', '\xD4', // E8
218 ' ', '\xD2', '\xDA', '\xDB', '\xD9', ' ', ' ', ' ', // F0
219 '\xAF', ' ', ' ', ' ', '\xB8', ' ', ' ', ' ', // F8