Back to index

tetex-bin  3.0
tfm.c
Go to the documentation of this file.
00001 /*  $Header$
00002 
00003     This is dvipdfm, a DVI to PDF translator.
00004     Copyright (C) 1998, 1999 by Mark A. Wicks
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019     
00020     The author may be contacted via the e-mail address
00021 
00022        mwicks@kettering.edu
00023 */
00024 
00025 #include <stdio.h>
00026 #include "system.h"
00027 #include "mem.h"
00028 #include "error.h"
00029 #include "mfileio.h"
00030 #include "pdflimits.h"
00031 #include "numbers.h"
00032 #include "tfm.h"
00033 #include "config.h"
00034 
00035 #define FWBASE ((double) (1<<20))
00036 
00037 static char tfm_verbose = 0;
00038 static char tfm_debug = 0;
00039 
00040 /* TFM Record structure
00041      Multiple TFM's may be read in at once */
00042 
00043 struct a_tfm
00044 {
00045   UNSIGNED_QUAD wlenfile, wlenheader;
00046   UNSIGNED_QUAD bc, ec;
00047   UNSIGNED_QUAD nwidths, nheights, ndepths;
00048   UNSIGNED_QUAD nitcor, nlig, nkern, nextens;
00049   UNSIGNED_QUAD nfonparm;
00050   UNSIGNED_QUAD font_direction;    /* Used only in OFMs.  TFMs don't have
00051                              this field*/
00052   UNSIGNED_QUAD nco, ncw, npc;
00053   SIGNED_QUAD *header;
00054   UNSIGNED_QUAD *char_info;
00055   UNSIGNED_PAIR *width_index;
00056   UNSIGNED_BYTE *height_index;
00057   UNSIGNED_BYTE *depth_index;
00058   SIGNED_QUAD *width;
00059   SIGNED_QUAD *height;
00060   SIGNED_QUAD *depth;
00061   char *tex_name;
00062   fixword *unpacked_widths;
00063   fixword *unpacked_heights;
00064   fixword *unpacked_depths;
00065 };
00066 
00067 void a_tfm_init (struct a_tfm *a_tfm) 
00068 {
00069   a_tfm->header = NULL;
00070   a_tfm->char_info = NULL;
00071   a_tfm->width_index = NULL;
00072   a_tfm->height_index = NULL;
00073   a_tfm->depth_index = NULL;
00074   a_tfm->width = NULL;
00075   a_tfm->height = NULL;
00076   a_tfm->depth = NULL;
00077   a_tfm->unpacked_widths = NULL;
00078   a_tfm->unpacked_heights = NULL;
00079   a_tfm->unpacked_depths = NULL;
00080 }
00081 
00082 
00083 struct a_tfm *tfm = NULL;
00084 static unsigned numtfms = 0, max_tfms = 0; /* numtfms should equal
00085                                          numfonts in dvi.c */
00086 static void tfms_need (unsigned n)
00087 {
00088   if (n > max_tfms) {
00089     max_tfms = MAX (max_tfms+MAX_FONTS, n);
00090     tfm = RENEW (tfm, max_tfms, struct a_tfm);
00091   }
00092 }
00093 
00094 /* External Routine */
00095 
00096 void tfm_set_verbose (void)
00097 {
00098   tfm_verbose += 1;
00099 }
00100 
00101 void tfm_set_debug (void)
00102 {
00103   tfm_verbose = 1;
00104   tfm_debug = 1;
00105 }
00106 
00107 static UNSIGNED_PAIR sum_of_tfm_sizes (struct a_tfm *a_tfm)
00108 {
00109   unsigned long result = 6;
00110   result += (a_tfm -> ec - a_tfm -> bc + 1);
00111   result += a_tfm -> wlenheader;
00112   result += a_tfm -> nwidths;
00113   result += a_tfm -> nheights;
00114   result += a_tfm -> ndepths;
00115   result += a_tfm -> nitcor;
00116   result += a_tfm -> nlig;
00117   result += a_tfm -> nkern;
00118   result += a_tfm -> nextens;
00119   result += a_tfm -> nfonparm;
00120   return result;
00121 }
00122 
00123 static SIGNED_QUAD sum_of_ofm_sizes (struct a_tfm *a_tfm)
00124 {
00125   unsigned long result = 14;
00126   result += 2*(a_tfm -> ec - a_tfm -> bc + 1);
00127   result += a_tfm -> wlenheader;
00128   result += a_tfm -> nwidths;
00129   result += a_tfm -> nheights;
00130   result += a_tfm -> ndepths;
00131   result += a_tfm -> nitcor;
00132   result += 2*(a_tfm -> nlig);
00133   result += a_tfm -> nkern;
00134   result += 2*(a_tfm -> nextens);
00135   result += a_tfm -> nfonparm;
00136   return result;
00137 }
00138 
00139 
00140 static void get_sizes (FILE *tfm_file, SIGNED_QUAD tfm_file_size,
00141                      struct a_tfm *a_tfm)
00142 {
00143   a_tfm -> wlenfile = get_unsigned_pair (tfm_file);
00144   a_tfm -> wlenheader = get_unsigned_pair (tfm_file);
00145   a_tfm -> bc = get_unsigned_pair (tfm_file);
00146   a_tfm -> ec = get_unsigned_pair (tfm_file);
00147   if (a_tfm -> ec < a_tfm -> bc) {
00148     ERROR ("TFM file error (ec < bc)\n");
00149   }
00150   a_tfm -> nwidths = get_unsigned_pair (tfm_file);
00151   a_tfm -> nheights = get_unsigned_pair (tfm_file);
00152   a_tfm -> ndepths = get_unsigned_pair (tfm_file);
00153   a_tfm -> nitcor = get_unsigned_pair (tfm_file);
00154   a_tfm -> nlig = get_unsigned_pair (tfm_file);
00155   a_tfm -> nkern = get_unsigned_pair (tfm_file);
00156   a_tfm -> nextens = get_unsigned_pair (tfm_file);
00157   a_tfm -> nfonparm = get_unsigned_pair (tfm_file);
00158   if (tfm_debug) {
00159     fprintf (stderr, "\nComputed size (words)%d\n", sum_of_tfm_sizes (a_tfm));
00160     fprintf (stderr, "Stated size (words)%ld\n", a_tfm -> wlenfile);
00161     fprintf (stderr, "Actual size (bytes)%ld\n", tfm_file_size);
00162   }
00163   if ( a_tfm -> wlenfile != tfm_file_size/4 ||
00164        sum_of_tfm_sizes (a_tfm) != a_tfm -> wlenfile) {
00165     if (tfm_file_size/4 > a_tfm -> wlenfile) {
00166       fprintf (stderr, "\nHmm.  A TFM file is larger than it says it is!");
00167       fprintf (stderr, "\nProceeding nervously...\n");
00168     } else {
00169       ERROR ("TFM file problem.  Table sizes don't agree.\n");
00170     }
00171   }
00172   return;
00173 }
00174 
00175 static int ofm_get_sizes (FILE *ofm_file,  UNSIGNED_QUAD ofm_file_size,
00176                         struct a_tfm *a_tfm)
00177 {
00178   SIGNED_QUAD level;
00179   level = get_signed_quad (ofm_file);
00180   a_tfm -> wlenfile = get_signed_quad (ofm_file);
00181   a_tfm -> wlenheader = get_signed_quad (ofm_file);
00182   a_tfm -> bc = get_signed_quad (ofm_file);
00183   a_tfm -> ec = get_signed_quad (ofm_file);
00184   if (a_tfm -> ec < a_tfm -> bc) {
00185     ERROR ("OFM file error (ec < bc)\n");
00186   }
00187   a_tfm -> nwidths = get_signed_quad (ofm_file);
00188   a_tfm -> nheights = get_signed_quad (ofm_file);
00189   a_tfm -> ndepths = get_signed_quad (ofm_file);
00190   a_tfm -> nitcor = get_signed_quad (ofm_file);
00191   a_tfm -> nlig = get_signed_quad (ofm_file);
00192   a_tfm -> nkern = get_signed_quad (ofm_file);
00193   a_tfm -> nextens = get_signed_quad (ofm_file);
00194   a_tfm -> nfonparm = get_signed_quad (ofm_file);
00195   a_tfm -> font_direction = get_signed_quad (ofm_file);
00196   if (a_tfm->font_direction) {
00197     fprintf (stderr, "Warning:  I may be interpreting a font direction incorrectly.\n");
00198   }
00199   if (level == 0) {
00200     if (a_tfm -> wlenfile != ofm_file_size/4 ||
00201        sum_of_ofm_sizes (a_tfm) != a_tfm -> wlenfile) {
00202       ERROR ("OFM file problem.  Table sizes don't agree.\n");
00203     }
00204     if (level == 0 && tfm_debug) {
00205       fprintf (stderr, "Computed size (words)%ld\n", sum_of_ofm_sizes (a_tfm));
00206       fprintf (stderr, "Stated size (words)%ld\n", a_tfm -> wlenfile);
00207       fprintf (stderr, "Actual size (bytes)%ld\n", ofm_file_size);
00208     }
00209   } else if (level == 1) {
00210     a_tfm -> nco = get_signed_quad (ofm_file);
00211     a_tfm -> ncw = get_signed_quad (ofm_file);
00212     a_tfm -> npc = get_signed_quad (ofm_file);
00213     seek_absolute (ofm_file, 4*(a_tfm -> nco));
00214   } else {
00215     ERROR ("Can't handle OFM files with level > 1");
00216   }
00217   return (int) (level);
00218 }
00219 
00220 static void dump_sizes (struct a_tfm *a_tfm)
00221 {
00222   fprintf (stderr, "\nwlenfile: %ld, ", a_tfm -> wlenfile);
00223   fprintf (stderr, "wlenheader: %ld\n", a_tfm -> wlenheader);
00224   fprintf (stderr, "bc: %ld, ", a_tfm -> bc);
00225   fprintf (stderr, "ec: %ld, ", a_tfm -> ec);
00226   fprintf (stderr, "nwidths: %ld, ", a_tfm -> nwidths);
00227   fprintf (stderr, "nheights: %ld, ", a_tfm -> nheights);
00228   fprintf (stderr, "ndepths: %ld\n", a_tfm -> ndepths);
00229   fprintf (stderr, "nitcor: %ld, ", a_tfm -> nitcor);
00230   fprintf (stderr, "nlig: %ld, ", a_tfm -> nlig);
00231   fprintf (stderr, "nkern: %ld, ", a_tfm -> nkern);
00232   fprintf (stderr, "nextens: %ld, ", a_tfm -> nextens);
00233   fprintf (stderr, "nfonparm: %ld\n", a_tfm -> nfonparm);
00234   return;
00235 }
00236 
00237 
00238 static void get_fix_word_array (FILE *tfm_file, SIGNED_QUAD *a_word,
00239                             SIGNED_QUAD length)
00240 {
00241   unsigned i;
00242   for (i=0; i< length; i++) {
00243     a_word[i] = get_signed_quad (tfm_file);
00244   }
00245   return;
00246 }
00247 
00248 static void get_unsigned_quad_array (FILE *tfm_file, UNSIGNED_QUAD *a_word,
00249                                  SIGNED_QUAD length)
00250 {
00251   unsigned i;
00252   for (i=0; i< length; i++) {
00253     a_word[i] = get_unsigned_quad (tfm_file);
00254   }
00255   return;
00256 }
00257 
00258 static void do_fix_word_array (FILE *tfm_file, SIGNED_QUAD **a, SIGNED_QUAD len)
00259 {
00260   if (len != 0) {
00261     *a = NEW (len, SIGNED_QUAD);
00262     get_fix_word_array (tfm_file, *a, len);
00263   } else
00264     *a = NULL;
00265   return;
00266 }
00267 
00268 static void do_unsigned_quad_array (FILE *tfm_file, UNSIGNED_QUAD **a, UNSIGNED_PAIR len)
00269 {
00270   if (len != 0) {
00271     *a = NEW (len, UNSIGNED_QUAD);
00272     get_unsigned_quad_array (tfm_file, *a, len);
00273   } else
00274     *a = NULL;
00275   return;
00276 }
00277 static void unpack_widths(struct a_tfm *a_tfm)
00278 {
00279   int i;
00280   UNSIGNED_QUAD charinfo;
00281   UNSIGNED_PAIR width_index;
00282   a_tfm -> unpacked_widths = NEW (256, fixword);
00283   for (i=0; i<256; i++) {
00284     (a_tfm ->unpacked_widths)[i] = 0;
00285   }
00286   for (i=(a_tfm->bc); i<=(a_tfm->ec); i++ ) {
00287     charinfo = (a_tfm->char_info)[i-(a_tfm->bc)];
00288     width_index = (charinfo / 16777216ul);
00289     (a_tfm->unpacked_widths)[i] = (a_tfm->width)[width_index];
00290   }
00291   return;
00292 }
00293 
00294 static void unpack_heights(struct a_tfm *a_tfm)
00295 {
00296   int i;
00297   UNSIGNED_QUAD charinfo;
00298   UNSIGNED_PAIR height_index;
00299   a_tfm -> unpacked_heights = NEW (256, fixword);
00300   for (i=0; i<256; i++) {
00301     (a_tfm ->unpacked_heights)[i] = 0;
00302   }
00303   for (i=(a_tfm->bc); i<=(a_tfm->ec); i++ ) {
00304     charinfo = (a_tfm->char_info)[i-(a_tfm->bc)];
00305     height_index = (charinfo / 0x100000ul) & 0xf;
00306     (a_tfm->unpacked_heights)[i] = (a_tfm->height)[height_index];
00307   }
00308   return;
00309 }
00310 
00311 static void unpack_depths(struct a_tfm *a_tfm)
00312 {
00313   int i;
00314   UNSIGNED_QUAD charinfo;
00315   UNSIGNED_PAIR depth_index;
00316   a_tfm -> unpacked_depths = NEW (256, fixword);
00317   for (i=0; i<256; i++) {
00318     (a_tfm ->unpacked_depths)[i] = 0;
00319   }
00320   for (i=(a_tfm->bc); i<=(a_tfm->ec); i++ ) {
00321     charinfo = (a_tfm->char_info)[i-(a_tfm->bc)];
00322     depth_index = (charinfo / 0x10000ul) & 0xf;
00323     (a_tfm->unpacked_depths)[i] = (a_tfm->depth)[depth_index];
00324   }
00325   return;
00326 }
00327 
00328 static void get_arrays (FILE *tfm_file, struct a_tfm *a_tfm)
00329 {
00330   if (tfm_debug) fprintf (stderr, "Reading %ld word header\n",
00331                        a_tfm->wlenheader);
00332   do_fix_word_array (tfm_file, &(a_tfm -> header), a_tfm -> wlenheader);
00333   if (tfm_debug) fprintf (stderr, "Reading %ld char_infos\n",
00334                        (a_tfm->ec)-(a_tfm->bc)+1);
00335   do_unsigned_quad_array (tfm_file, &(a_tfm -> char_info), (a_tfm->ec)-(a_tfm->bc)+1);
00336   if (tfm_debug) fprintf (stderr, "Reading %ld widths\n",
00337                        a_tfm -> nwidths);
00338   do_fix_word_array (tfm_file, &(a_tfm -> width), a_tfm -> nwidths);
00339   if (tfm_debug) fprintf (stderr, "Reading %ld heights\n",
00340                        a_tfm -> nheights);
00341   do_fix_word_array (tfm_file, &(a_tfm -> height), a_tfm -> nheights);
00342   if (tfm_debug) fprintf (stderr, "Reading %ld depths\n",
00343                        a_tfm -> ndepths);
00344   do_fix_word_array (tfm_file, &(a_tfm -> depth), a_tfm -> ndepths);
00345   unpack_widths (a_tfm);
00346   unpack_heights (a_tfm);
00347   unpack_depths (a_tfm);
00348   return;
00349 }
00350 
00351 static void do_ofm_zero_char_info (FILE *tfm_file, struct a_tfm *a_tfm)
00352 {
00353   unsigned i;
00354   UNSIGNED_QUAD num_chars;
00355   num_chars = a_tfm->ec - a_tfm->bc + 1;
00356   if (num_chars != 0) {
00357     a_tfm -> width_index = NEW (num_chars, UNSIGNED_PAIR);
00358     a_tfm -> height_index = NEW (num_chars, UNSIGNED_BYTE);
00359     a_tfm -> depth_index = NEW (num_chars, UNSIGNED_BYTE);
00360     a_tfm -> unpacked_widths = NEW (a_tfm->bc+num_chars, fixword);
00361     a_tfm -> unpacked_heights = NEW (a_tfm->bc+num_chars, fixword);
00362     a_tfm -> unpacked_depths = NEW (a_tfm->bc+num_chars, fixword);
00363   }
00364   for (i=0; i<num_chars; i++) {
00365     (a_tfm->width_index)[i] = get_unsigned_pair (tfm_file);
00366     (a_tfm->height_index)[i] = get_unsigned_byte (tfm_file);
00367     (a_tfm->depth_index)[i] = get_unsigned_byte (tfm_file);
00368     /* Ignore remaining quad */
00369     get_unsigned_quad (tfm_file);
00370   }
00371 }
00372 
00373 static void do_ofm_one_char_info (FILE *tfm_file, struct a_tfm *a_tfm)
00374 {
00375   UNSIGNED_QUAD i;
00376   UNSIGNED_QUAD num_char_infos, char_infos_read;
00377   UNSIGNED_QUAD num_chars;
00378   UNSIGNED_QUAD char_info_size;
00379   char_info_size = 3 + (a_tfm->npc/2);
00380   num_char_infos = (a_tfm -> ncw) / char_info_size;
00381   num_chars = (a_tfm->ec - a_tfm ->bc) + 1;
00382   if (tfm_debug)
00383     fprintf (stderr, "\nReading %ld level 1 chars\n", num_chars);
00384   if (num_chars != 0) {
00385     a_tfm -> width_index = NEW (num_chars, UNSIGNED_PAIR);
00386     a_tfm -> height_index = NEW (num_chars, UNSIGNED_BYTE);
00387     a_tfm -> depth_index = NEW (num_chars, UNSIGNED_BYTE);
00388     a_tfm -> unpacked_widths = NEW (a_tfm->bc+num_chars, fixword);
00389     a_tfm -> unpacked_heights = NEW (a_tfm->bc+num_chars, fixword);
00390     a_tfm -> unpacked_depths = NEW (a_tfm->bc+num_chars, fixword);
00391   }
00392   for (i=0, char_infos_read = 0; i<num_chars && char_infos_read < num_char_infos; i++) {
00393     int repeats, j;
00394     (a_tfm->width_index)[i] = get_unsigned_pair (tfm_file);
00395     (a_tfm->height_index)[i] = get_unsigned_byte (tfm_file);
00396     (a_tfm->depth_index)[i] = get_unsigned_byte (tfm_file);
00397     /* Ignore next quad */
00398     get_unsigned_quad (tfm_file);
00399     repeats = get_unsigned_pair (tfm_file);
00400     /* Skip params */
00401     for (j=0; j<a_tfm->npc; j++) {
00402       get_unsigned_pair (tfm_file);
00403     }
00404     /* Remove word padding if necessary */
00405     if (ISEVEN (a_tfm->npc)){
00406       get_unsigned_pair (tfm_file);
00407     }
00408     char_infos_read += 1;
00409     if (i+repeats > num_chars)
00410       ERROR ("repeats causes number of characters to be exceeded");
00411     for (j=0; j<repeats; j++) {
00412       a_tfm->width_index[i+j+1] = a_tfm->width_index[i];
00413       a_tfm->height_index[i+j+1] = a_tfm->height_index[i];
00414       a_tfm->depth_index[i+j+1] = a_tfm->depth_index[i];
00415     }
00416     /* Skip ahead because we have already handled repeats */
00417     i += repeats;
00418   }
00419   if (tfm_debug) {
00420     fprintf (stderr, "\npackets read = %ld/%ld\n", char_infos_read,
00421             num_char_infos);
00422     fprintf (stderr, "\ncharacters defined = %ld/%ld\n", i, num_chars);
00423   }
00424 }
00425 
00426 static void ofm_unpack_arrays (struct a_tfm *a_tfm, UNSIGNED_QUAD num_chars)
00427 {
00428   unsigned i;
00429   for (i=0; i<num_chars; i++) {
00430     (a_tfm->unpacked_widths)[a_tfm->bc+i] = (a_tfm->width)[(a_tfm->width_index)[i]];
00431     (a_tfm->unpacked_heights)[a_tfm->bc+i] = (a_tfm->height)[(a_tfm->height_index)[i]];
00432     (a_tfm->unpacked_depths)[a_tfm->bc+i] = (a_tfm->depth)[(a_tfm->depth_index)[i]];
00433   }
00434 }
00435 
00436 static void ofm_get_arrays (FILE *tfm_file, struct a_tfm *a_tfm, int level)
00437 {
00438   switch (level) {
00439   case 0:
00440     if (tfm_debug) fprintf (stderr, "Reading %ld word header\n",
00441                          a_tfm->wlenheader);
00442     do_fix_word_array (tfm_file, &(a_tfm -> header), a_tfm ->
00443                      wlenheader);
00444     if (tfm_debug) fprintf (stderr, "Reading %ld char_infos\n",
00445                          (a_tfm->ec)-(a_tfm->bc)+1);
00446     do_ofm_zero_char_info (tfm_file, a_tfm);
00447     break;
00448   case 1:
00449     if (tfm_debug) fprintf (stderr, "Reading %ld char_infos words\n",
00450                          a_tfm->ncw);
00451     do_ofm_one_char_info (tfm_file, a_tfm);
00452     break;
00453   default:
00454     ERROR ("level != 0 or 1 in ofm_get_arrays()");
00455   }
00456   if (tfm_debug) fprintf (stderr, "Reading %ld widths\n",
00457                        a_tfm -> nwidths);
00458   do_fix_word_array (tfm_file, &(a_tfm -> width), a_tfm -> nwidths);
00459   if (tfm_debug) fprintf (stderr, "Reading %ld heights\n",
00460                        a_tfm -> nheights);
00461   do_fix_word_array (tfm_file, &(a_tfm -> height), a_tfm -> nheights);
00462   if (tfm_debug) fprintf (stderr, "Reading %ld depths\n",
00463                        a_tfm -> ndepths);
00464   do_fix_word_array (tfm_file, &(a_tfm -> depth), a_tfm -> ndepths);
00465   ofm_unpack_arrays (a_tfm, (a_tfm->ec)-(a_tfm->bc)+1);
00466   return;
00467 }
00468 
00469 static void get_ofm (FILE *ofm_file, UNSIGNED_QUAD ofm_file_size,
00470                    struct a_tfm *a_tfm)
00471 {
00472   int level;
00473   level = ofm_get_sizes (ofm_file, ofm_file_size, a_tfm);
00474   ofm_get_arrays (ofm_file, a_tfm, level);
00475   return;
00476 }
00477 
00478 static void get_tfm (FILE *tfm_file, UNSIGNED_QUAD tfm_file_size,
00479                    struct a_tfm *a_tfm)
00480 {
00481   get_sizes (tfm_file, tfm_file_size, a_tfm);
00482   get_arrays (tfm_file, a_tfm);
00483   return;
00484 }
00485 
00486 /* External Routine */
00487 
00488 int tfm_open (const char *tfm_name)
00489 {
00490   FILE *tfm_file;
00491   int i;
00492   UNSIGNED_QUAD tfm_file_size;
00493   char *full_tfm_file_name;
00494   for (i=0; i<numtfms; i++) {
00495     if (!strcmp (tfm_name, tfm[i].tex_name))
00496       break;
00497   }
00498   if (i == numtfms) { /* Name hasn't already been loaded */
00499     if ((full_tfm_file_name = kpse_find_tfm (tfm_name))) {
00500       tfms_need (numtfms+1);
00501       a_tfm_init (tfm+numtfms);
00502       if (!(tfm_file = MFOPEN (full_tfm_file_name, FOPEN_RBIN_MODE))) {
00503        fprintf (stderr, "\n%s: ", tfm_name);
00504        ERROR ("Specified TFM file cannot be opened");
00505       }
00506       if (tfm_verbose == 1)
00507        fprintf (stderr, "(TFM:%s", tfm_name);
00508       if (tfm_verbose > 1)
00509        fprintf (stderr, "(TFM:%s", full_tfm_file_name);
00510       if ((tfm_file_size = file_size(tfm_file)) < 24) {
00511        ERROR ("TFM file too small to be a valid file\n");
00512       }
00513       get_tfm (tfm_file, tfm_file_size, &tfm[numtfms]);
00514 #ifdef HAVE_OMEGA_FORMATS       
00515     } else if ((full_tfm_file_name = kpse_find_ofm (tfm_name))) {
00516       tfms_need (numtfms+1);
00517       a_tfm_init (tfm+numtfms);
00518       if (!(tfm_file = MFOPEN (full_tfm_file_name, FOPEN_RBIN_MODE))) {
00519        fprintf (stderr, "\n%s:  ", tfm_name);
00520        ERROR ("OFM file cannot be opened");
00521       }
00522       if (tfm_verbose == 1)
00523        fprintf (stderr, "(OFM:%s", tfm_name);
00524       if (tfm_verbose > 1)
00525        fprintf (stderr, "(OFM:%s", full_tfm_file_name);
00526       if ((tfm_file_size = file_size(tfm_file)) < 24) {
00527        ERROR ("OFM file too small to be a valid file\n");
00528       }
00529       get_ofm (tfm_file, tfm_file_size, &tfm[numtfms]);
00530 #endif       
00531     } else {
00532       fprintf (stderr, "\n%s:  ", tfm_name);
00533       ERROR ("Unable to find a TFM or OFM file");
00534     }
00535     tfm[numtfms].tex_name = NEW (strlen(tfm_name)+1, char);
00536     strcpy (tfm[numtfms].tex_name, tfm_name);
00537     MFCLOSE (tfm_file);
00538     if (tfm_verbose) 
00539       fprintf (stderr, ")");
00540     if (tfm_verbose>3) {
00541       dump_sizes (&tfm[numtfms]);
00542     }
00543     return numtfms++;
00544   } else { /* Name has been loaded before */
00545     return i;
00546   }
00547 }
00548 
00549 void tfm_close_all(void)
00550 {
00551   int i;
00552   for (i=0; i<numtfms; i++) {
00553     if (tfm[i].header)
00554       RELEASE (tfm[i].header);
00555     if (tfm[i].char_info)
00556       RELEASE (tfm[i].char_info);
00557     if (tfm[i].width)
00558       RELEASE (tfm[i].width);
00559     if (tfm[i].height)
00560       RELEASE (tfm[i].height);
00561     if (tfm[i].depth)
00562       RELEASE (tfm[i].depth);
00563     RELEASE (tfm[i].tex_name);
00564     RELEASE (tfm[i].unpacked_widths);
00565     RELEASE (tfm[i].unpacked_heights);
00566     RELEASE (tfm[i].unpacked_depths);
00567     if (tfm[i].width_index)
00568       RELEASE (tfm[i].width_index);
00569     if (tfm[i].height_index)
00570       RELEASE (tfm[i].height_index);
00571     if (tfm[i].depth_index)
00572       RELEASE (tfm[i].depth_index);
00573   }
00574   if (tfm)
00575     RELEASE (tfm);
00576 }
00577 
00578 /* tfm_get_width returns the width of the font
00579    as a (double) fraction of the design size */
00580 double tfm_get_width (int font_id, UNSIGNED_QUAD ch)
00581 {
00582   if (tfm[font_id].unpacked_widths && ch <= tfm[font_id].ec)
00583     return (double) (tfm[font_id].unpacked_widths)[ch] / FWBASE;
00584   else return 0.0;
00585 }
00586 
00587 double tfm_get_height (int font_id, UNSIGNED_QUAD ch)
00588 {
00589   if (tfm[font_id].unpacked_heights && ch <= tfm[font_id].ec)
00590     return (double) (tfm[font_id].unpacked_heights)[ch] / FWBASE;
00591   else return 0.0;
00592 }
00593 
00594 double tfm_get_depth (int font_id, UNSIGNED_QUAD ch)
00595 {
00596   if (tfm[font_id].unpacked_depths && ch <= tfm[font_id].ec)
00597     return (tfm[font_id].unpacked_depths)[ch]/FWBASE;
00598   else return 0.0;
00599 }
00600 
00601 fixword tfm_get_fw_width (int font_id, UNSIGNED_QUAD ch)
00602 {
00603   if (tfm[font_id].unpacked_widths && ch <= tfm[font_id].ec) {
00604     return (tfm[font_id].unpacked_widths)[ch];
00605   }
00606   return 0;
00607 }
00608 
00609 fixword tfm_get_fw_height (int font_id, UNSIGNED_QUAD ch)
00610 {
00611   if (tfm[font_id].unpacked_heights && ch <= tfm[font_id].ec)
00612     return (tfm[font_id].unpacked_heights)[ch];
00613   return 0;
00614 }
00615 
00616 fixword tfm_get_fw_depth (int font_id, UNSIGNED_QUAD ch)
00617 {
00618   if (tfm[font_id].unpacked_depths && ch <= tfm[font_id].ec)
00619     return (tfm[font_id].unpacked_depths)[ch];
00620   return 0;
00621 }
00622 
00623 fixword tfm_string_width (int font_id, unsigned char *s, unsigned len)
00624 {
00625   fixword result = 0;
00626   unsigned i;
00627   if (tfm[font_id].unpacked_widths) 
00628     for (i=0; i<len; i++) {
00629       if (s[i] <= tfm[font_id].ec)
00630        result += tfm[font_id].unpacked_widths[s[i]];
00631     }
00632   return result;
00633 }
00634 
00635 fixword tfm_string_depth (int font_id, unsigned char *s, unsigned len)
00636 {
00637   fixword result = 0;
00638   unsigned i;
00639   if (tfm[font_id].unpacked_depths) 
00640     for (i=0; i<len; i++) {
00641       if (s[i] <= tfm[font_id].ec)
00642        result = MAX(result, tfm[font_id].unpacked_depths[s[i]]);
00643     }
00644   return result;
00645 }
00646 
00647 fixword tfm_string_height (int font_id, unsigned char *s, unsigned len)
00648 {
00649   fixword result = 0;
00650   unsigned i;
00651   if (tfm[font_id].unpacked_heights) 
00652     for (i=0; i<len; i++) {
00653       if (s[i] <= tfm[font_id].ec)
00654        result = MAX(result, tfm[font_id].unpacked_heights[s[i]-tfm[font_id].bc]);
00655     }
00656   return result;
00657 }
00658 
00659 UNSIGNED_PAIR tfm_get_firstchar (int font_id)
00660 {
00661   return tfm[font_id].bc;
00662 }
00663 
00664 UNSIGNED_PAIR tfm_get_lastchar (int font_id)
00665 {
00666   return tfm[font_id].ec;
00667 }
00668 
00669 double tfm_get_design_size (int font_id)
00670 {
00671   return ((tfm[font_id].header))[1]/FWBASE*(72.0/72.27);
00672 }
00673 
00674 
00675 double tfm_get_max_width (int font_id)
00676 {
00677   SIGNED_QUAD max = 0;
00678   int i;
00679   for (i=0; i<tfm[font_id].nwidths; i++) {
00680     if ((tfm[font_id].width)[i] > max)
00681       max = (tfm[font_id].width)[i];
00682   }
00683   return (max/FWBASE);
00684 }
00685 
00686 int tfm_is_fixed_width (int font_id)
00687 {
00688   /* We always have two widths since width[0] = 0.
00689      A fixed width font will have width[1] = something
00690      and not have any other widths */
00691   return (tfm[font_id].nwidths == 2);
00692 }
00693 
00694 double tfm_get_max_height (int font_id)
00695 {
00696   SIGNED_QUAD max = 0;
00697   int i;
00698   for (i=0; i<tfm[font_id].nheights; i++) {
00699     if ((tfm[font_id].height)[i] > max)
00700       max = (tfm[font_id].height)[i];
00701   }
00702   return (max/FWBASE);
00703 }
00704 
00705 double tfm_get_max_depth (int font_id)
00706 {
00707   SIGNED_QUAD max = 0;
00708   int i;
00709   for (i=0; i<tfm[font_id].ndepths; i++) {
00710     if ((tfm[font_id].depth)[i] > max)
00711       max = (tfm[font_id].depth)[i];
00712   }
00713   return (max/FWBASE);
00714 }