Back to index

texmacs  1.0.7.15
load_tfm.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : load_tfm.cpp
00004 * DESCRIPTION: load TeX font metric file
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "load_tex.hpp"
00013 #include "analyze.hpp"
00014 #include "timer.hpp"
00015 
00016 RESOURCE_CODE(tex_font_metric);
00017 
00018 /******************************************************************************
00019 * Constructors and destructors for tex_font_metric
00020 ******************************************************************************/
00021 
00022 // FIXME: work around compiler bug
00023 typedef rep<tex_font_metric> rep_tex_font_metric;
00024 
00025 tex_font_metric_rep::tex_font_metric_rep (string name):
00026   rep_tex_font_metric (name)
00027 {
00028   header   = NULL;
00029   char_info= NULL;
00030   width    = NULL;
00031   height   = NULL;
00032   depth    = NULL;
00033   italic   = NULL;
00034   lig_kern = NULL;
00035   kern     = NULL;
00036   exten    = NULL;
00037   param    = NULL;
00038 }
00039 
00040 tex_font_metric_rep::~tex_font_metric_rep () {
00041   if (header != NULL) tm_delete_array (header);
00042   if (char_info != NULL) tm_delete_array (char_info);
00043   if (width != NULL) tm_delete_array (width);
00044   if (height != NULL) tm_delete_array (height);
00045   if (depth != NULL) tm_delete_array (depth);
00046   if (italic != NULL) tm_delete_array (italic);
00047   if (lig_kern != NULL) tm_delete_array (lig_kern);
00048   if (kern != NULL) tm_delete_array (kern);
00049   if (exten != NULL) tm_delete_array (exten);
00050   if (param != NULL) tm_delete_array (param);
00051 }
00052 
00053 /******************************************************************************
00054 * Interpretation of tex_font_metric instances
00055 ******************************************************************************/
00056 
00057 #define byte0(i) (((i)>>24)&255)
00058 #define byte1(i) (((i)>>16)&255)
00059 #define byte2(i) (((i)>>8)&255)
00060 #define byte3(i) ((i)&255)
00061 #define word0(i) (((i)>>16)&65535)
00062 #define word1(i) ((i)&65535)
00063 
00064 #define byte1a(i) (((i)>>20)&15)
00065 #define byte1b(i) (((i)>>16)&15)
00066 #define byte2x(i) (((i)>>10)&63)
00067 #define word1x(i) ((i)&32767)
00068 
00069 int tex_font_metric_rep::w (QN c) {
00070   if ((c<bc) || (c>ec)) return 0;
00071   return width [byte0 (char_info[c-bc])]; }
00072 int tex_font_metric_rep::h (QN c) {
00073   if ((c<bc) || (c>ec)) return 0;
00074   return height [byte1a (char_info[c-bc])]; }
00075 int tex_font_metric_rep::d (QN c) {
00076   if ((c<bc) || (c>ec)) return 0;
00077   return depth [byte1b (char_info[c-bc])]; }
00078 int tex_font_metric_rep::i (QN c) {
00079   if ((c<bc) || (c>ec)) return 0;
00080   return italic [byte2x (char_info[c-bc])]; }
00081 int tex_font_metric_rep::tag (QN c) { return (char_info [c-bc]>>8)&3; }
00082 int tex_font_metric_rep::rem (QN c) { return char_info  [c-bc] & 255; }
00083 QN  tex_font_metric_rep::top (QN c) { return (QN) byte0 (exten [rem (c)]); }
00084 QN  tex_font_metric_rep::mid (QN c) { return (QN) byte1 (exten [rem (c)]); }
00085 QN  tex_font_metric_rep::bot (QN c) { return (QN) byte2 (exten [rem (c)]); }
00086 QN  tex_font_metric_rep::rep (QN c) { return (QN) byte3 (exten [rem (c)]); }
00087 int tex_font_metric_rep::design_size () { return header[1]; }
00088 int tex_font_metric_rep::parameter (int i) { return (i<np)? param [i]: 0; }
00089 int tex_font_metric_rep::spc () { return parameter (1); }
00090 int tex_font_metric_rep::spc_stretch () { return parameter (2); }
00091 int tex_font_metric_rep::spc_shrink () { return parameter (3); }
00092 int tex_font_metric_rep::x_height () { return parameter (4); }
00093 int tex_font_metric_rep::spc_quad () { return parameter (5); }
00094 int tex_font_metric_rep::spc_extra () { return parameter (6); }
00095 
00096 int
00097 tex_font_metric_rep::list_len (QN c) {
00098   if (tag(c)!=2) return 1;
00099   return list_len (rem (c)) + 1;
00100 }
00101 
00102 QN
00103 tex_font_metric_rep::nth_in_list (QN c, int n) {
00104   if ((n==1) || (tag(c)!=2)) return c;
00105   return nth_in_list (rem (c), n-1);
00106 }
00107 
00108 double
00109 tex_font_metric_rep::slope () {
00110   double slope= ((double) parameter(0)) / ((double) (1<<20));
00111   if (slope >= 1.0) slope= 0.25;
00112   if (slope <= -1.0) slope= -0.25;
00113   return slope;
00114 }
00115 
00116 /******************************************************************************
00117 * Execution of the ligature kerning program
00118 *------------------------------------------------------------------------------
00119 * (s, n) the input string of length n
00120 * buf    the output string of maximal length m
00121 * ker    the output kerning array of maximal length m
00122 * m      at input : maximal length of buf and ker;
00123 *        at output: the length of buf and ker.
00124 ******************************************************************************/
00125 
00126 void
00127 tex_font_metric_rep::execute (int* s, int n, int* buf, int* ker, int& m) {
00128   STACK_NEW_ARRAY (stack, int, m);
00129   int bp, sp=0, i;
00130 
00131   for (i=0; i<n; i++) stack[sp++]= s[n-1-i];
00132   sp--; bp= 0;
00133 
00134   while (sp>=0) {
00135     int cur_char= stack [sp]& 255;
00136     // cout << "Processing " << (char) cur_char << "\n";
00137 
00138     /***************** the ligature-kerning program ******************/
00139     if ((cur_char<bc) || (cur_char>ec)) sp--;
00140     else if ((tag (cur_char)==1) && (sp>0)) {
00141       register int next_char= stack [sp-1]& 255;
00142       register int pc= rem (cur_char);
00143       if (byte0 (lig_kern [pc]) > 128) pc= word1 (lig_kern [pc]);
00144 
00145       while (true) {
00146        register int instr= lig_kern [pc];
00147 
00148        //if (byte0 (instr) >= 128) { // halt
00149        //  // cout << "  Halt\n";
00150        //  ker [bp]  = 0;
00151        //  buf [bp++]= stack[sp--];
00152        //  break;
00153        //}
00154 
00155        if (byte1 (instr) != next_char) { // continue
00156          // cout << "  " << (char) byte1 (instr) << " != " << (char) next_char
00157          //      << " => pc := pc + " << (byte0 (instr)+1) << "\n";
00158          int skip_byte = byte0(instr);
00159          if (skip_byte >= 128) { // current instruction is the final instruction
00160            // cout << "  Halt\n";
00161            ker [bp]  = 0;
00162            buf [bp++]= stack[sp--];
00163            break;
00164          }
00165          else {
00166            pc += skip_byte+1;
00167            continue;
00168          }
00169        }
00170 
00171        // cout << "  " << (char) byte1 (instr) << " == "
00172        //      << (char) next_char << " => ";
00173 
00174        if (byte2 (instr) < 128) { // ligature
00175          // cout << "Ligature ";
00176          int code= byte2 (instr);
00177          int a   = code>>2;
00178          int b   = (code>>1)&1;
00179          int c   = code&1;
00180          // cout << "(" << a << "," << b << "," << c << ")\n";
00181          if (b==0) sp--;
00182          stack [sp++]= byte3 (instr);
00183          if (c!=0) stack[sp++]= cur_char;
00184          sp--;
00185          while (a>0) {
00186            ker [bp]  = 0;
00187            buf [bp++]= stack [sp--];
00188            a--;
00189          }
00190          break;
00191        }
00192 
00193        else { // kerning
00194          // cout << "Kerning (" << kern  [word1x (instr)] << ")\n";
00195          ker [bp]  = kern  [word1x (instr)];
00196          buf [bp++]= stack [sp--];
00197          break;
00198        }
00199       }
00200     }
00201     else {
00202       ker [bp]  = 0;
00203       buf [bp++]= stack [sp--];
00204     }
00205     /***************** end ligature-kerning program ******************/
00206 
00207     if ((bp>=m-2) || (sp>=m-2)) {
00208       cerr << "\nString is ";
00209       for (i=0; i<n; i++) cerr << (char) s[i];
00210       cerr << "\n";
00211       FAILED ("string too complex for ligature kerning");
00212     }
00213   }
00214   
00215   m= bp;
00216   STACK_DELETE_ARRAY (stack);
00217 }
00218 
00219 /******************************************************************************
00220 * Get the individual horzontal offsets of characters
00221 ******************************************************************************/
00222 
00223 #define conv(x) ((SI) (((double) (x))*unit))
00224 
00225 #define ADVANCE(k)                         \
00226   x += conv (w(stack[sp--]) + k);          \
00227   x_bis= x;                                \
00228   if (pos < n-sp) xpos [pos++] = x;
00229 
00230 #define SKIP                               \
00231   sp--;                                    \
00232   if (pos < n-sp) {                        \
00233     x_bis += conv (w(stack[sp+1]));        \
00234     xpos [pos++] = x_bis;                  \
00235   }
00236 
00237 void
00238 tex_font_metric_rep::get_xpositions (int* s, int n, double unit, SI* xpos) {
00239   SI  x    = 0;
00240   SI  x_bis= 0;
00241   int pos  = 1;
00242 
00243   int m= n + 16;
00244   STACK_NEW_ARRAY (stack, int, m);
00245   int bp, sp=0, i;
00246 
00247   for (i=0; i<n; i++) stack[sp++]= s[n-1-i];
00248   sp--; bp= 0;
00249 
00250   while (sp>=0) {
00251     int cur_char= stack [sp]& 255;
00252 
00253     /***************** the ligature-kerning program ******************/
00254     if ((cur_char<bc) || (cur_char>ec)) { SKIP; }
00255     else if ((tag (cur_char)==1) && (sp>0)) {
00256       register int next_char= stack [sp-1]& 255;
00257       register int pc= rem (cur_char);
00258       if (byte0 (lig_kern [pc]) > 128) pc= word1 (lig_kern [pc]);
00259 
00260       while (true) {
00261        register int instr= lig_kern [pc];
00262        if (byte0 (instr) >= 128) { ADVANCE (0); break; }
00263        if (byte1 (instr) != next_char) { pc += byte0 (instr)+1; continue; }
00264        if (byte2 (instr) < 128) {
00265          int code= byte2 (instr);
00266          int a   = code>>2;
00267          int b   = (code>>1)&1;
00268          int c   = code&1;
00269          if (b==0) SKIP;
00270          stack [sp++]= byte3 (instr);
00271          if (c!=0) stack [sp++]= cur_char;
00272          SKIP;
00273          while (a>0) { ADVANCE (0); a--; }
00274          break;
00275        }
00276        else { ADVANCE (kern [word1x (instr)]); break; }
00277       }
00278     }
00279     else ADVANCE (0);
00280     /***************** end ligature-kerning program ******************/
00281 
00282     if ((bp>=m-2) || (sp>=m-2)) {
00283       cerr << "\nString is ";
00284       for (i=0; i<n; i++) cerr << (char) s[i];
00285       cerr << "\n";
00286       FAILED ("string too complex for ligature kerning");
00287     }
00288   }
00289   STACK_DELETE_ARRAY (stack);
00290 }
00291 
00292 #undef SKIP
00293 #undef ADVANCE
00294 #undef unit
00295 
00296 /******************************************************************************
00297 * Output of tex_font_metric instances
00298 ******************************************************************************/
00299 
00300 static const char* HOR_RULE= "---------------------------------------------------------------------------\n";
00301 
00302 double
00303 fixed (int i) {
00304   double x= ((double) i) / ((double) (1<<20));
00305   int j= (int) (1000*x);
00306   return ((double) j)*0.001;
00307 }
00308 
00309 void
00310 print (tex_font_metric tfm) {
00311   int i;
00312   cout << HOR_RULE;
00313   cout << "name:        " << tfm->res_name << "\n";
00314   cout << HOR_RULE;
00315   cout << "checksum:    " << tfm->header[0] << "\n";
00316   cout << "design size: " << fixed (tfm->header[1]) << "\n";
00317 
00318   cout << HOR_RULE;
00319   for (i=tfm->bc; i<=tfm->ec; i++) {
00320     cout << "character ";
00321     if ((i&127)<32) cout << i << ":\t";
00322     else cout << ((char) i) << ":\t";
00323     cout << "w=" << fixed (tfm->w(i)) << ", ";
00324     cout << "h=" << fixed (tfm->h(i)) << ", ";
00325     cout << "d=" << fixed (tfm->d(i)) << ", ";
00326     cout << "i=" << fixed (tfm->i(i));
00327     switch (tfm->tag (i)) {
00328     case 1: cout << " [lig " << tfm->rem(i) << "]"; break;
00329     case 2: cout << " [list " << tfm->rem(i) << "]"; break;
00330     case 3: cout << " [ext "
00331                << (int) tfm->top(i) << ", "
00332                << (int) tfm->mid(i) << ", " 
00333                << (int) tfm->bot(i) << ", " 
00334                << (int) tfm->rep(i) << "]"; break;
00335     }
00336     cout << "\n";
00337   }
00338 
00339   cout << HOR_RULE;
00340   if (tfm->left!=-1)
00341     cout << "Left boundary character:  " << tfm->left << "\n";
00342   if (tfm->right!=-1)
00343     cout << "Right boundary character: " << tfm->right << "\n";
00344   if (tfm->left_prog!=-1) 
00345     cout << "Left boundary program:    " << tfm->left_prog << "\n";
00346   if (tfm->right_prog!=-1)
00347     cout << "Right boundary program:   " << tfm->right_prog << "\n";
00348   if ((tfm->left==-1) && (tfm->right==-1) &&
00349       (tfm->left_prog==-1) && (tfm->right_prog==-1))
00350     cout << "No boundary characters or programs\n";
00351 
00352   cout << HOR_RULE;
00353   cout << "Slope:         " << tfm->slope () << "\n";
00354   cout << "Space:         " << fixed (tfm->spc ()) << "\n";
00355   cout << "Space_stretch: " << fixed (tfm->spc_stretch ()) << "\n";
00356   cout << "Space_shrink:  " << fixed (tfm->spc_shrink ()) << "\n";
00357   cout << "X height:      " << fixed (tfm->x_height ()) << "\n";
00358   cout << "Quad space:    " << fixed (tfm->spc_quad ()) << "\n";
00359   cout << "Extra space:   " << fixed (tfm->spc_extra ()) << "\n";
00360 
00361   cout << HOR_RULE;
00362   for (i=7; i<tfm->np; i++)
00363     cout << "Parameter " << i << ": " << fixed (tfm->parameter (i)) << "\n";
00364 
00365   cout << HOR_RULE;
00366 }
00367 
00368 /******************************************************************************
00369 * Main program for loading
00370 ******************************************************************************/
00371 
00372 tex_font_metric
00373 load_tfm (url file_name, string family, int size) {
00374   tex_font_metric tfm=
00375     tm_new<tex_font_metric_rep> (family * as_string (size) * ".tfm");
00376 
00377   int i= 0;
00378   string s;
00379   (void) load_string (file_name, s, true);
00380   bench_start ("decode tfm");
00381 
00382   parse (s, i, tfm->lf);
00383   parse (s, i, tfm->lh);
00384   parse (s, i, tfm->bc);
00385   parse (s, i, tfm->ec);
00386   parse (s, i, tfm->nw);
00387   parse (s, i, tfm->nh);
00388   parse (s, i, tfm->nd);
00389   parse (s, i, tfm->ni);
00390   parse (s, i, tfm->nl);
00391   parse (s, i, tfm->nk);
00392   parse (s, i, tfm->ne);
00393   parse (s, i, tfm->np);
00394 
00395   if ((tfm->lf-6) !=
00396       (tfm->lh + (tfm->ec + 1 - tfm->bc) +
00397        tfm->nw + tfm->nh + tfm->nd + tfm->ni +
00398        tfm->nl + tfm->nk + tfm->ne + tfm->np))
00399     FAILED ("invalid tfm file");
00400   
00401   parse (s, i, tfm->header, tfm->lh);
00402   parse (s, i, tfm->char_info, tfm->ec+1- tfm->bc);
00403   parse (s, i, tfm->width, tfm->nw);
00404   parse (s, i, tfm->height, tfm->nh);
00405   parse (s, i, tfm->depth, tfm->nd);
00406   parse (s, i, tfm->italic, tfm->ni);
00407   parse (s, i, tfm->lig_kern, tfm->nl);
00408   parse (s, i, tfm->kern, tfm->nk);
00409   parse (s, i, tfm->exten, tfm->ne);
00410   parse (s, i, tfm->param, tfm->np);
00411   
00412   tfm->left= tfm->right= tfm->left_prog= tfm->right_prog= -1;
00413   if (tfm->nl > 0) {
00414     int l= tfm->lig_kern [0];
00415     int r= tfm->lig_kern [tfm->nl- 1];
00416     if (byte0 (l) == 255) tfm->right= byte1 (l);
00417     if (byte0 (r) == 255) tfm->left_prog= word1 (r);
00418   }
00419 
00420   tfm->size= (tfm->header[1] + (1<<19)) >> 20;
00421 
00422   bench_cumul ("decode tfm");
00423   return tfm;
00424 }