5bf6e91696b1de68c3a9a518a0ecf25f7f213eac
1 /****************************************************************************
2 * RRDtool 1.2.4 Copyright by Tobi Oetiker, 1997-2005
3 ****************************************************************************
4 * rrd_afm.h Parsing afm tables to find width of strings.
5 ****************************************************************************/
7 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
8 #include "../confignt/config.h"
9 #else
10 #include "config.h"
11 #endif
13 #include "rrd_afm.h"
14 #include "rrd_afm_data.h"
16 #include <stdlib.h>
17 #include <stdio.h>
19 #ifdef HAVE_STRING_H
20 #include <string.h>
21 #endif
23 #if 0
24 # define DEBUG 1
25 # define DLOG(x) fprintf x
26 #else
27 # define DEBUG 0
28 # define DLOG(x)
29 #endif
31 /* Adobe SVG View and Batik 1.1.1 can't handle ligatures.
32 So disable it as we just waste speed.
33 Besides, it doesn't matter much in normal text.
34 */
35 #define ENABLE_LIGATURES 0
37 static const afm_fontinfo *afm_last_used_font;
39 #define is_font(p, name) \
40 (!strcmp(p->postscript_name, name) || !strcmp(p->fullname, name))
42 static const afm_fontinfo *afm_searchfont(const char *name)
43 {
44 int i;
45 const afm_fontinfo *p = afm_last_used_font;
46 if (p && is_font(p, name))
47 return p;
48 p = afm_fontinfolist;
49 for (i = 0; i < afm_fontinfo_count; i++, p++) {
50 if (is_font(p, name)) {
51 afm_last_used_font = p;
52 return p;
53 }
54 }
55 return NULL;
56 }
58 static const afm_fontinfo *afm_findfont(const char *name)
59 {
60 const afm_fontinfo *p = afm_searchfont(name);
61 if (p)
62 return p;
63 if (1 || DEBUG) fprintf(stderr, "Can't find font '%s'\n", name);
64 p = afm_searchfont("Helvetica");
65 if (p)
66 return p;
67 return NULL;
68 }
70 const char *afm_get_font_postscript_name(const char* font)
71 {
72 const afm_fontinfo *p = afm_findfont(font);
73 return p ? p->postscript_name : "Helvetica";
74 }
76 double afm_get_ascender(const char* font, double size)
77 {
78 const afm_fontinfo *p = afm_findfont(font);
79 return p ? p->ascender : 10; /* just a guess to avoid really bad design if we don't know the font */
80 }
82 double afm_get_descender(const char* font, double size)
83 {
84 const afm_fontinfo *p = afm_findfont(font);
85 return p ? p->descender : 4; /* just a guess to avoid really bad design if we don't know the font */
86 }
88 static int afm_find_char_index(const afm_fontinfo *fontinfo,
89 afm_cunicode ch1)
90 {
91 int idx = ch1 - 32;
92 afm_cuint16 *indexP;
93 int numIndexChars, i;
94 if (idx <= 0)
95 return 0;
96 if (idx <= 126 - 32)
97 return idx;
98 indexP = fontinfo->highchars_index;
99 if (indexP == 0)
100 return 0;
101 numIndexChars = fontinfo->highchars_count;
102 DLOG((stderr, " find highbit, num = %d\n", numIndexChars));
103 if (ch1 >= 161 && ch1 <= 255) {
104 idx = ch1 - 161;
105 DLOG((stderr, " 161, idx = %d -> %d\n", idx, indexP[idx]));
106 if (idx < numIndexChars && indexP[idx] == ch1) {
107 idx += 127 - 32;
108 DLOG((stderr, " 161-guessed ok to %d\n", idx));
109 return idx;
110 }
111 }
112 for (i = 0; i < numIndexChars; i++) {
113 DLOG((stderr, " compares to %d -> %d\n", indexP[i], i));
114 if (indexP[i] == ch1)
115 return i + 127 - 32;
116 }
117 DLOG((stderr, "Did not find %d in highchars_index ??\n", ch1));
118 return 0;
119 }
121 #if ENABLE_LIGATURES
122 static afm_cunicode afm_find_combined_ligature(const afm_fontinfo *fontinfo,
123 afm_cunicode ch1, afm_cunicode ch2)
124 {
125 afm_cunicode *p = fontinfo->ligatures;
126 int num = fontinfo->ligatures_count;
127 int i;
128 if (!num)
129 return 0;
130 DLOG((stderr, " find-lig, num = %d\n", num));
131 for (i = 0; i < num; i++, p += 3) {
132 DLOG((stderr, " lig: %d + %d -> %d (%c %c %c)\n",
133 p[0], p[1], p[2], p[0], p[1], p[2]));
134 if (ch1 == *p && ch2 == p[1]) {
135 DLOG((stderr, " matches.\n"));
136 return p[2];
137 }
138 }
139 return 0;
140 }
141 #endif
143 #define READ_ESCAPED(p, val) \
144 if ((val = *p++) == 0) { \
145 val = 254 + *p++; \
146 } else if (!--val) { \
147 val = *p++ << 8; \
148 val |= *p++; \
149 }
152 static long afm_find_kern(const afm_fontinfo *fontinfo,
153 int kern_idx, afm_cunicode ch2)
154 {
155 afm_cuint8 *p8 = fontinfo->kerning_data + kern_idx;
156 int num;
157 READ_ESCAPED(p8, num);
158 DLOG((stderr, " find kern, num pairs = %d\n", num));
159 while (num > 0) {
160 afm_unicode ch;
161 READ_ESCAPED(p8, ch);
162 DLOG((stderr, " pair-char = %d\n", ch));
163 if (ch == ch2) {
164 DLOG((stderr, " got kern = %d\n", *(afm_csint8*)p8));
165 return *(afm_csint8*)p8;
166 }
167 p8++;
168 num--;
169 }
170 return 0;
171 }
173 /* measure width of a text string */
174 double afm_get_text_width ( double start, const char* font, double size,
175 double tabwidth, const char* text)
176 {
177 const afm_fontinfo *fontinfo = afm_findfont(font);
178 long width = 0;
179 double widthf;
180 const unsigned char *up = (const unsigned char*)text;
181 DLOG((stderr, "================= %s\n", text));
182 if (fontinfo == NULL)
183 return size * strlen(text);
184 while (1) {
185 afm_unicode ch1, ch2;
186 int idx1, kern_idx;
187 if ((ch1 = *up) == 0)
188 break;
189 ch1 = afm_host2unicode(ch1); /* unsafe macro */
190 ch2 = *++up;
191 ch2 = afm_host2unicode(ch2); /* unsafe macro */
192 DLOG((stderr, "------------- Loop: %d + %d (%c%c) at %d\n",
193 ch1, ch2, ch1, ch2 ? ch2 : ' ',
194 (up - (const unsigned char*)text) - 1));
195 idx1 = afm_find_char_index(fontinfo, ch1);
196 DLOG((stderr, " idx1 = %d\n", idx1));
197 #if ENABLE_LIGATURES
198 if (ch2) {
199 int ch1_new = afm_find_combined_ligature(fontinfo, ch1, ch2);
200 DLOG((stderr, " lig-ch = %d\n", ch1_new));
201 if (ch1_new) {
202 ch1 = ch1_new;
203 idx1 = afm_find_char_index(fontinfo, ch1);
204 ch2 = afm_host2unicode(*++up);
205 DLOG((stderr, " -> idx1 = %d, ch2 = %d (%c)\n",
206 idx1, ch2, ch2 ? ch2 : ' '));
207 }
208 }
209 #endif
210 width += fontinfo->widths[idx1];
211 DLOG((stderr, "Plain width of %d = %d\n", ch1, fontinfo->widths[idx1]));
212 if (fontinfo->kerning_index && ch2) {
213 kern_idx = fontinfo->kerning_index[idx1];
214 DLOG((stderr, " kern_idx = %d\n", kern_idx));
215 if (kern_idx > 0)
216 width += afm_find_kern(fontinfo, kern_idx, ch2);
217 }
218 }
219 widthf = (width * 6 / 1000.0) * size;
220 DLOG((stderr, "Returns %ld (%ld) -> %f\n", width, width * 6, widthf));
221 return widthf;
222 }
224 #ifdef __APPLE__
225 const unsigned char afm_mac2iso[128] = {
226 '\xC4', '\xC5', '\xC7', '\xC9', '\xD1', '\xD6', '\xDC', '\xE1', /* 80 */
227 '\xE0', '\xE2', '\xE4', '\xE3', '\xE5', '\xE7', '\xE9', '\xE8', /* 88 */
228 '\xEA', '\xEB', '\xED', '\xEC', '\xEE', '\xEF', '\xF1', '\xF3', /* 90 */
229 '\xF2', '\xF4', '\xF6', '\xF5', '\xFA', '\xF9', '\xFB', '\xFC', /* 98 */
230 '\xDD', '\xB0', '\xA2', '\xA3', '\xA7', ' ', '\xB6', '\xDF', /* A0 */
231 '\xAE', '\xA9', ' ', '\xB4', '\xA8', ' ', '\xC6', '\xD8', /* A8 */
232 ' ', '\xB1', '\xBE', ' ', '\xA5', '\xB5', ' ', ' ', /* B0 */
233 '\xBD', '\xBC', ' ', '\xAA', '\xBA', ' ', '\xE6', '\xF8', /* B8 */
234 '\xBF', '\xA1', '\xAC', ' ', ' ', ' ', ' ', '\xAB', /* C0 */
235 '\xBB', ' ', '\xA0', '\xC0', '\xC3', '\xD5', ' ', '\xA6', /* C8 */
236 '\xAD', ' ', '"', '"', '\'', '\'', '\xF7', '\xD7', /* D0 */
237 '\xFF', ' ', ' ', '\xA4', '\xD0', '\xF0', '\xDE', '\xFE', /* D8 */
238 '\xFD', '\xB7', ' ', ' ', ' ', '\xC2', '\xCA', '\xC1', /* E0 */
239 '\xCB', '\xC8', '\xCD', '\xCE', '\xCF', '\xCC', '\xD3', '\xD4', /* E8 */
240 ' ', '\xD2', '\xDA', '\xDB', '\xD9', ' ', ' ', ' ', /* F0 */
241 '\xAF', ' ', ' ', ' ', '\xB8', ' ', ' ', ' ', /* F8 */
242 };
243 #endif