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"
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
)
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); }
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);
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;
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 ******************************************************************************/
128 tex_font_metric_rep::execute (int* s
, int n
, int* buf
, int* ker
, int& m
) {
129 STACK_NEW_ARRAY (stack
, int, m
);
132 for (i
=0; i
<n
; i
++) stack
[sp
++]= s
[n
-1-i
];
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
]);
147 register int instr
= lig_kern
[pc
];
149 if (byte0 (instr
) >= 128) { // halt
150 // cout << " Halt\n";
152 buf
[bp
++]= stack
[sp
--];
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;
163 // cout << " " << (char) byte1 (instr) << " == "
164 // << (char) next_char << " => ";
166 if (byte2 (instr
) < 128) { // ligature
167 // cout << "Ligature ";
168 int code
= byte2 (instr
);
172 // cout << "(" << a << "," << b << "," << c << ")\n";
174 stack
[sp
++]= byte3 (instr
);
175 if (c
!=0) stack
[sp
++]= cur_char
;
179 buf
[bp
++]= stack
[sp
--];
186 // cout << "Kerning (" << kern [word1x (instr)] << ")\n";
187 ker
[bp
] = kern
[word1x (instr
)];
188 buf
[bp
++]= stack
[sp
--];
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
];
203 fatal_error ("String too complex for ligature kerning",
204 "tex_font_metric_rep::execute",
210 STACK_DELETE_ARRAY (stack
);
213 /******************************************************************************
214 * Get the individual horzontal offsets of characters
215 ******************************************************************************/
217 #define conv(x) ((SI) (((double) (x))*unit))
220 x += conv (w(stack[sp--]) + k); \
222 if (pos < n-sp) xpos [pos++] = x;
227 x_bis += conv (w(stack[sp+1])); \
228 xpos [pos++] = x_bis; \
232 tex_font_metric_rep::get_xpositions (int* s
, int n
, double unit
, SI
* xpos
) {
238 STACK_NEW_ARRAY (stack
, int, m
);
241 for (i
=0; i
<n
; i
++) stack
[sp
++]= s
[n
-1-i
];
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
]);
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
);
264 stack
[sp
++]= byte3 (instr
);
265 if (c
!=0) stack
[sp
++]= cur_char
;
267 while (a
>0) { ADVANCE (0); a
--; }
270 else { ADVANCE (kern
[word1x (instr
)]); break; }
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
];
280 fatal_error ("String too complex for ligature kerning",
281 "tex_font_metric_rep::get_xpositions",
285 STACK_DELETE_ARRAY (stack
);
292 /******************************************************************************
293 * Output of tex_font_metric instances
294 ******************************************************************************/
296 static const char* HOR_RULE
= "---------------------------------------------------------------------------\n";
300 double x
= ((double) i
) / ((double) (1<<20));
301 int j
= (int) (1000*x
);
302 return ((double) j
)*0.001;
306 print (tex_font_metric tfm
) {
309 cout
<< "name: " << tfm
->res_name
<< "\n";
311 cout
<< "checksum: " << tfm
->header
[0] << "\n";
312 cout
<< "design size: " << fixed (tfm
->header
[1]) << "\n";
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;
337 cout
<< "Left boundary character: " << tfm
->left
<< "\n";
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";
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";
358 for (i
=7; i
<tfm
->np
; i
++)
359 cout
<< "Parameter " << i
<< ": " << fixed (tfm
->parameter (i
)) << "\n";
364 /******************************************************************************
365 * Main program for loading
366 ******************************************************************************/
369 load_tfm (url file_name
, string family
, int size
) {
371 new tex_font_metric_rep (family
* as_string (size
) * ".tfm");
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
);
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;
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");