fix spelling and syntax, especially in messages that are printed -- Mike Slifcak
[rrdtool.git] / src / rrd_afm.c
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  ****************************************************************************/
6
7 #include "rrd_afm.h"
8 #include "rrd_afm_data.h"
9
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #if 0
14 # define DEBUG 1
15 # define DLOG(x) fprintf x
16 #else
17 # define DEBUG 0
18 # define DLOG(x) 
19 #endif
20
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.
24 */
25 #define ENABLE_LIGATURES 0
26
27 static const afm_fontinfo *afm_last_used_font;
28
29 #define is_font(p, name) \
30   (!strcmp(p->postscript_name, name) || !strcmp(p->fullname, name))
31
32 static const afm_fontinfo *afm_searchfont(const char *name)
33 {
34   int i;
35   const afm_fontinfo *p = afm_last_used_font;
36   if (p && is_font(p, name))
37     return p;
38   p = afm_fontinfolist;
39   for (i = 0; i < afm_fontinfo_count; i++, p++) {
40     if (is_font(p, name)) {
41       afm_last_used_font = p;
42       return p;
43     }
44   }
45   return NULL;
46 }
47
48 static const afm_fontinfo *afm_findfont(const char *name)
49 {
50   const afm_fontinfo *p = afm_searchfont(name);
51   if (p)
52     return p;
53   if (1 || DEBUG) fprintf(stderr, "Can't find font '%s'\n", name);
54   p = afm_searchfont("Helvetica");
55   if (p)
56     return p;
57   return NULL;
58 }
59
60 const char *afm_get_font_postscript_name(const char* font)
61 {
62   const afm_fontinfo *p = afm_findfont(font);
63   return p ? p->postscript_name : "Helvetica";
64 }
65
66 static int afm_find_char_index(const afm_fontinfo *fontinfo,
67     afm_cunicode ch1)
68 {
69   int idx = ch1 - 32;
70   afm_cuint16 *indexP;
71   int numIndexChars, i;
72   if (idx <= 0)
73     return 0;
74   if (idx <= 126 - 32)
75     return idx;
76   indexP = fontinfo->highchars_index;
77   if (indexP == 0)
78     return 0;
79   numIndexChars = fontinfo->highchars_count;
80   DLOG((stderr, " find highbit, num = %d\n", numIndexChars));
81   if (ch1 >= 161 && ch1 <= 255) {
82     idx = ch1 - 161;
83     DLOG((stderr, "  161, idx = %d -> %d\n", idx, indexP[idx]));
84     if (idx < numIndexChars && indexP[idx] == ch1) {
85       idx += 127 - 32;
86       DLOG((stderr, "  161-guessed ok to %d\n", idx));
87       return idx;
88     }
89   }
90   for (i = 0; i < numIndexChars; i++) {
91     DLOG((stderr, "    compares to %d -> %d\n", indexP[i], i));
92     if (indexP[i] == ch1)
93       return i + 127 - 32;
94   }
95   DLOG((stderr, "Did not find %d in highchars_index ??\n", ch1));
96   return 0;
97 }
98
99 #if ENABLE_LIGATURES
100 static afm_cunicode afm_find_combined_ligature(const afm_fontinfo *fontinfo,
101     afm_cunicode ch1, afm_cunicode ch2)
102 {
103   afm_cunicode *p = fontinfo->ligatures;
104   int num = fontinfo->ligatures_count;
105   int i;
106   if (!num)
107     return 0;
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"));
114       return p[2];
115     }
116   }
117   return 0;
118 }
119 #endif
120
121 #define READ_ESCAPED(p, val) \
122   if ((val = *p++) == 0) { \
123     val = 254 + *p++; \
124   } else if (!--val) { \
125     val = *p++ << 8; \
126     val |= *p++; \
127   }
128
129
130 static long afm_find_kern(const afm_fontinfo *fontinfo,
131     int kern_idx, afm_cunicode ch2)
132 {
133   afm_cuint8 *p8 = fontinfo->kerning_data + kern_idx;
134   int num;
135   READ_ESCAPED(p8, num);
136   DLOG((stderr, " find kern, num pairs = %d\n", num));
137   while (num > 0) {
138     afm_unicode ch;
139     READ_ESCAPED(p8, ch);
140     DLOG((stderr, "     pair-char = %d\n", ch));
141     if (ch == ch2) {
142       DLOG((stderr, " got kern = %d\n", *(afm_csint8*)p8));
143       return *(afm_csint8*)p8;
144     }
145     p8++;
146     num--;
147   }
148   return 0;
149 }
150
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)
154 {
155   const afm_fontinfo *fontinfo = afm_findfont(font);
156   long width = 0;
157   double widthf;
158   const unsigned char *up = (const unsigned char*)text;
159   DLOG((stderr, "================= %s\n", text));
160   if (fontinfo == NULL)
161     return size * strlen(text);
162   while (1) {
163     afm_unicode ch1, ch2;
164     int idx1, kern_idx;
165     if ((ch1 = *up) == 0)
166       break;
167     ch1 = afm_host2unicode(ch1); /* unsafe macro */
168     ch2 = *++up;
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));
175 #if ENABLE_LIGATURES
176     if (ch2) {
177       int ch1_new = afm_find_combined_ligature(fontinfo, ch1, ch2);
178       DLOG((stderr, "  lig-ch = %d\n", ch1_new));
179       if (ch1_new) {
180         ch1 = 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 : ' '));
185       }
186     }
187 #endif
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));
193       if (kern_idx > 0)
194         width += afm_find_kern(fontinfo, kern_idx, ch2);
195     }
196   }
197   widthf = (width * 6 / 1000.0) * size;
198   DLOG((stderr, "Returns %ld (%ld) -> %f\n", width, width * 6, widthf));
199   return widthf;
200 }
201
202 #ifdef __APPLE__
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
220 };
221 #endif