Fix compiler warnings
[texmacs.git] / src / src / Plugins / Metafont / load_tfm.cpp
blobbaa50ebb18678cd6a58b2b398c61e2aac3c32b07
2 /******************************************************************************
3 * MODULE : load_tfm.cpp
4 * DESCRIPTION: load TeX font metric file
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license and comes WITHOUT
8 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
9 * If you don't have this file, write to the Free Software Foundation, Inc.,
10 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11 ******************************************************************************/
13 #include "load_tex.hpp"
14 #include "analyze.hpp"
15 #include "timer.hpp"
17 RESOURCE_CODE(tex_font_metric);
19 /******************************************************************************
20 * Constructors and destructors for tex_font_metric
21 ******************************************************************************/
23 // FIXME: work around compiler bug
24 typedef rep<tex_font_metric> rep_tex_font_metric;
26 tex_font_metric_rep::tex_font_metric_rep (string name):
27 rep_tex_font_metric (name)
29 header = NULL;
30 char_info= NULL;
31 width = NULL;
32 height = NULL;
33 depth = NULL;
34 italic = NULL;
35 lig_kern = NULL;
36 kern = NULL;
37 exten = NULL;
38 param = NULL;
41 tex_font_metric_rep::~tex_font_metric_rep () {
42 if (header != NULL) delete[] header;
43 if (char_info != NULL) delete[] char_info;
44 if (width != NULL) delete[] width;
45 if (height != NULL) delete[] height;
46 if (depth != NULL) delete[] depth;
47 if (italic != NULL) delete[] italic;
48 if (lig_kern != NULL) delete[] lig_kern;
49 if (kern != NULL) delete[] kern;
50 if (exten != NULL) delete[] exten;
51 if (param != NULL) delete[] param;
54 /******************************************************************************
55 * Interpretation of tex_font_metric instances
56 ******************************************************************************/
58 #define byte0(i) (((i)>>24)&255)
59 #define byte1(i) (((i)>>16)&255)
60 #define byte2(i) (((i)>>8)&255)
61 #define byte3(i) ((i)&255)
62 #define word0(i) (((i)>>16)&65535)
63 #define word1(i) ((i)&65535)
65 #define byte1a(i) (((i)>>20)&15)
66 #define byte1b(i) (((i)>>16)&15)
67 #define byte2x(i) (((i)>>10)&63)
68 #define word1x(i) ((i)&32767)
70 int tex_font_metric_rep::w (QN c) {
71 if ((c<bc) || (c>ec)) return 0;
72 return width [byte0 (char_info[c-bc])]; }
73 int tex_font_metric_rep::h (QN c) {
74 if ((c<bc) || (c>ec)) return 0;
75 return height [byte1a (char_info[c-bc])]; }
76 int tex_font_metric_rep::d (QN c) {
77 if ((c<bc) || (c>ec)) return 0;
78 return depth [byte1b (char_info[c-bc])]; }
79 int tex_font_metric_rep::i (QN c) {
80 if ((c<bc) || (c>ec)) return 0;
81 return italic [byte2x (char_info[c-bc])]; }
82 int tex_font_metric_rep::tag (QN c) { return (char_info [c-bc]>>8)&3; }
83 int tex_font_metric_rep::rem (QN c) { return char_info [c-bc] & 255; }
84 QN tex_font_metric_rep::top (QN c) { return (QN) byte0 (exten [rem (c)]); }
85 QN tex_font_metric_rep::mid (QN c) { return (QN) byte1 (exten [rem (c)]); }
86 QN tex_font_metric_rep::bot (QN c) { return (QN) byte2 (exten [rem (c)]); }
87 QN tex_font_metric_rep::rep (QN c) { return (QN) byte3 (exten [rem (c)]); }
88 int tex_font_metric_rep::design_size () { return header[1]; }
89 int tex_font_metric_rep::parameter (int i) { return (i<np)? param [i]: 0; }
90 int tex_font_metric_rep::spc () { return parameter (1); }
91 int tex_font_metric_rep::spc_stretch () { return parameter (2); }
92 int tex_font_metric_rep::spc_shrink () { return parameter (3); }
93 int tex_font_metric_rep::x_height () { return parameter (4); }
94 int tex_font_metric_rep::spc_quad () { return parameter (5); }
95 int tex_font_metric_rep::spc_extra () { return parameter (6); }
97 int
98 tex_font_metric_rep::list_len (QN c) {
99 if (tag(c)!=2) return 1;
100 return list_len (rem (c)) + 1;
104 tex_font_metric_rep::nth_in_list (QN c, int n) {
105 if ((n==1) || (tag(c)!=2)) return c;
106 return nth_in_list (rem (c), n-1);
109 double
110 tex_font_metric_rep::slope () {
111 double slope= ((double) parameter(0)) / ((double) (1<<20));
112 if (slope >= 1.0) slope= 0.25;
113 if (slope <= -1.0) slope= -0.25;
114 return slope;
117 /******************************************************************************
118 * Execution of the ligature kerning program
119 *------------------------------------------------------------------------------
120 * (s, n) the input string of length n
121 * buf the output string of maximal length m
122 * ker the output kerning array of maximal length m
123 * m at input : maximal length of buf and ker;
124 * at output: the length of buf and ker.
125 ******************************************************************************/
127 void
128 tex_font_metric_rep::execute (int* s, int n, int* buf, int* ker, int& m) {
129 STACK_NEW_ARRAY (stack, int, m);
130 int bp, sp=0, i;
132 for (i=0; i<n; i++) stack[sp++]= s[n-1-i];
133 sp--; bp= 0;
135 while (sp>=0) {
136 int cur_char= stack [sp]& 255;
137 // cout << "Processing " << (char) cur_char << "\n";
139 /***************** the ligature-kerning program ******************/
140 if ((cur_char<bc) || (cur_char>ec)) sp--;
141 else if ((tag (cur_char)==1) && (sp>0)) {
142 register int next_char= stack [sp-1]& 255;
143 register int pc= rem (cur_char);
144 if (byte0 (lig_kern [pc]) > 128) pc= word1 (lig_kern [pc]);
146 while (true) {
147 register int instr= lig_kern [pc];
149 if (byte0 (instr) >= 128) { // halt
150 // cout << " Halt\n";
151 ker [bp] = 0;
152 buf [bp++]= stack[sp--];
153 break;
156 if (byte1 (instr) != next_char) { // continue
157 // cout << " " << (char) byte1 (instr) << " != " << (char) next_char
158 // << " => pc := pc + " << (byte0 (instr)+1) << "\n";
159 pc += byte0 (instr)+1;
160 continue;
163 // cout << " " << (char) byte1 (instr) << " == "
164 // << (char) next_char << " => ";
166 if (byte2 (instr) < 128) { // ligature
167 // cout << "Ligature ";
168 int code= byte2 (instr);
169 int a = code>>2;
170 int b = (code>>1)&1;
171 int c = code&1;
172 // cout << "(" << a << "," << b << "," << c << ")\n";
173 if (b==0) sp--;
174 stack [sp++]= byte3 (instr);
175 if (c!=0) stack[sp++]= cur_char;
176 sp--;
177 while (a>0) {
178 ker [bp] = 0;
179 buf [bp++]= stack [sp--];
180 a--;
182 break;
185 else { // kerning
186 // cout << "Kerning (" << kern [word1x (instr)] << ")\n";
187 ker [bp] = kern [word1x (instr)];
188 buf [bp++]= stack [sp--];
189 break;
193 else {
194 ker [bp] = 0;
195 buf [bp++]= stack [sp--];
197 /***************** end ligature-kerning program ******************/
199 if ((bp>=m-2) || (sp>=m-2)) {
200 cerr << "\nString is ";
201 for (i=0; i<n; i++) cerr << (char) s[i];
202 cerr << "\n";
203 fatal_error ("String too complex for ligature kerning",
204 "tex_font_metric_rep::execute",
205 "load-tfm.cpp");
209 m= bp;
210 STACK_DELETE_ARRAY (stack);
213 /******************************************************************************
214 * Get the individual horzontal offsets of characters
215 ******************************************************************************/
217 #define conv(x) ((SI) (((double) (x))*unit))
219 #define ADVANCE(k) \
220 x += conv (w(stack[sp--]) + k); \
221 x_bis= x; \
222 if (pos < n-sp) xpos [pos++] = x;
224 #define SKIP \
225 sp--; \
226 if (pos < n-sp) { \
227 x_bis += conv (w(stack[sp+1])); \
228 xpos [pos++] = x_bis; \
231 void
232 tex_font_metric_rep::get_xpositions (int* s, int n, double unit, SI* xpos) {
233 SI x = 0;
234 SI x_bis= 0;
235 int pos = 1;
237 int m= n + 16;
238 STACK_NEW_ARRAY (stack, int, m);
239 int bp, sp=0, i;
241 for (i=0; i<n; i++) stack[sp++]= s[n-1-i];
242 sp--; bp= 0;
244 while (sp>=0) {
245 int cur_char= stack [sp]& 255;
247 /***************** the ligature-kerning program ******************/
248 if ((cur_char<bc) || (cur_char>ec)) { SKIP; }
249 else if ((tag (cur_char)==1) && (sp>0)) {
250 register int next_char= stack [sp-1]& 255;
251 register int pc= rem (cur_char);
252 if (byte0 (lig_kern [pc]) > 128) pc= word1 (lig_kern [pc]);
254 while (true) {
255 register int instr= lig_kern [pc];
256 if (byte0 (instr) >= 128) { ADVANCE (0); break; }
257 if (byte1 (instr) != next_char) { pc += byte0 (instr)+1; continue; }
258 if (byte2 (instr) < 128) {
259 int code= byte2 (instr);
260 int a = code>>2;
261 int b = (code>>1)&1;
262 int c = code&1;
263 if (b==0) SKIP;
264 stack [sp++]= byte3 (instr);
265 if (c!=0) stack [sp++]= cur_char;
266 SKIP;
267 while (a>0) { ADVANCE (0); a--; }
268 break;
270 else { ADVANCE (kern [word1x (instr)]); break; }
273 else ADVANCE (0);
274 /***************** end ligature-kerning program ******************/
276 if ((bp>=m-2) || (sp>=m-2)) {
277 cerr << "\nString is ";
278 for (i=0; i<n; i++) cerr << (char) s[i];
279 cerr << "\n";
280 fatal_error ("String too complex for ligature kerning",
281 "tex_font_metric_rep::get_xpositions",
282 "load-tfm.cpp");
285 STACK_DELETE_ARRAY (stack);
288 #undef SKIP
289 #undef ADVANCE
290 #undef unit
292 /******************************************************************************
293 * Output of tex_font_metric instances
294 ******************************************************************************/
296 static const char* HOR_RULE= "---------------------------------------------------------------------------\n";
298 double
299 fixed (int i) {
300 double x= ((double) i) / ((double) (1<<20));
301 int j= (int) (1000*x);
302 return ((double) j)*0.001;
305 void
306 print (tex_font_metric tfm) {
307 int i;
308 cout << HOR_RULE;
309 cout << "name: " << tfm->res_name << "\n";
310 cout << HOR_RULE;
311 cout << "checksum: " << tfm->header[0] << "\n";
312 cout << "design size: " << fixed (tfm->header[1]) << "\n";
314 cout << HOR_RULE;
315 for (i=tfm->bc; i<=tfm->ec; i++) {
316 cout << "character ";
317 if ((i&127)<32) cout << i << ":\t";
318 else cout << ((char) i) << ":\t";
319 cout << "w=" << fixed (tfm->w(i)) << ", ";
320 cout << "h=" << fixed (tfm->h(i)) << ", ";
321 cout << "d=" << fixed (tfm->d(i)) << ", ";
322 cout << "i=" << fixed (tfm->i(i));
323 switch (tfm->tag (i)) {
324 case 1: cout << " [lig " << tfm->rem(i) << "]"; break;
325 case 2: cout << " [list " << tfm->rem(i) << "]"; break;
326 case 3: cout << " [ext "
327 << (int) tfm->top(i) << ", "
328 << (int) tfm->mid(i) << ", "
329 << (int) tfm->bot(i) << ", "
330 << (int) tfm->rep(i) << "]"; break;
332 cout << "\n";
335 cout << HOR_RULE;
336 if (tfm->left!=-1)
337 cout << "Left boundary character: " << tfm->left << "\n";
338 if (tfm->right!=-1)
339 cout << "Right boundary character: " << tfm->right << "\n";
340 if (tfm->left_prog!=-1)
341 cout << "Left boundary program: " << tfm->left_prog << "\n";
342 if (tfm->right_prog!=-1)
343 cout << "Right boundary program: " << tfm->right_prog << "\n";
344 if ((tfm->left==-1) && (tfm->right==-1) &&
345 (tfm->left_prog==-1) && (tfm->right_prog==-1))
346 cout << "No boundary characters or programs\n";
348 cout << HOR_RULE;
349 cout << "Slope: " << tfm->slope () << "\n";
350 cout << "Space: " << fixed (tfm->spc ()) << "\n";
351 cout << "Space_stretch: " << fixed (tfm->spc_stretch ()) << "\n";
352 cout << "Space_shrink: " << fixed (tfm->spc_shrink ()) << "\n";
353 cout << "X height: " << fixed (tfm->x_height ()) << "\n";
354 cout << "Quad space: " << fixed (tfm->spc_quad ()) << "\n";
355 cout << "Extra space: " << fixed (tfm->spc_extra ()) << "\n";
357 cout << HOR_RULE;
358 for (i=7; i<tfm->np; i++)
359 cout << "Parameter " << i << ": " << fixed (tfm->parameter (i)) << "\n";
361 cout << HOR_RULE;
364 /******************************************************************************
365 * Main program for loading
366 ******************************************************************************/
368 tex_font_metric
369 load_tfm (url file_name, string family, int size) {
370 tex_font_metric tfm=
371 new tex_font_metric_rep (family * as_string (size) * ".tfm");
373 int i= 0;
374 string s;
375 (void) load_string (file_name, s, true);
376 bench_start ("decode tfm");
378 parse (s, i, tfm->lf);
379 parse (s, i, tfm->lh);
380 parse (s, i, tfm->bc);
381 parse (s, i, tfm->ec);
382 parse (s, i, tfm->nw);
383 parse (s, i, tfm->nh);
384 parse (s, i, tfm->nd);
385 parse (s, i, tfm->ni);
386 parse (s, i, tfm->nl);
387 parse (s, i, tfm->nk);
388 parse (s, i, tfm->ne);
389 parse (s, i, tfm->np);
391 if ((tfm->lf-6) !=
392 (tfm->lh + (tfm->ec + 1 - tfm->bc) +
393 tfm->nw + tfm->nh + tfm->nd + tfm->ni +
394 tfm->nl + tfm->nk + tfm->ne + tfm->np))
395 fatal_error ("invalid tfm file", "load_tfm", "load-tfm.cpp");
397 parse (s, i, tfm->header, tfm->lh);
398 parse (s, i, tfm->char_info, tfm->ec+1- tfm->bc);
399 parse (s, i, tfm->width, tfm->nw);
400 parse (s, i, tfm->height, tfm->nh);
401 parse (s, i, tfm->depth, tfm->nd);
402 parse (s, i, tfm->italic, tfm->ni);
403 parse (s, i, tfm->lig_kern, tfm->nl);
404 parse (s, i, tfm->kern, tfm->nk);
405 parse (s, i, tfm->exten, tfm->ne);
406 parse (s, i, tfm->param, tfm->np);
408 tfm->left= tfm->right= tfm->left_prog= tfm->right_prog= -1;
409 if (tfm->nl > 0) {
410 int l= tfm->lig_kern [0];
411 int r= tfm->lig_kern [tfm->nl- 1];
412 if (byte0 (l) == 255) tfm->right= byte1 (l);
413 if (byte0 (r) == 255) tfm->left_prog= word1 (r);
416 tfm->size= (tfm->header[1] + (1<<19)) >> 20;
418 bench_cumul ("decode tfm");
419 return tfm;