Back to index

texmacs  1.0.7.15
tfm.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/tfm.c,v 1.23 2008/11/30 21:12:27 matthias Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014     
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019     
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023 */
00024 
00025 #if HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include <string.h>
00030 
00031 #include "system.h"
00032 #include "mem.h"
00033 #include "mfileio.h"
00034 #include "error.h"
00035 
00036 #include "numbers.h"
00037 #include "dpxutil.h"
00038 
00039 #include "tfm.h"
00040 
00041 #define TFM_FORMAT 1
00042 #define OFM_FORMAT 2
00043 
00044 #define FWBASE ((double) (1<<20))
00045 
00046 static int verbose = 0;
00047 
00048 
00049 #ifndef WITHOUT_ASCII_PTEX
00050 /*
00051  * ID is 9 for vertical JFM file.
00052  */
00053 #define JFM_ID  11
00054 #define JFMV_ID  9
00055 #define IS_JFM(i) ((i) == JFM_ID || (i) == JFMV_ID)
00056 #endif /* !WITHOUT_ASCII_PTEX */
00057 
00058 /*
00059  * TFM Record structure:
00060  * Multiple TFM's may be read in at once.
00061  */
00062 
00063 struct tfm_font
00064 {
00065 #ifndef WITHOUT_ASCII_PTEX
00066   UNSIGNED_BYTE id;
00067   UNSIGNED_BYTE nt;
00068 #endif /* !WITHOUT_ASCII_PTEX */
00069 #ifndef WITHOUT_OMEGA
00070   SIGNED_QUAD   level;
00071 #endif /* !WITHOUT_OMEGA */
00072   UNSIGNED_QUAD wlenfile;
00073   UNSIGNED_QUAD wlenheader;
00074   UNSIGNED_QUAD bc, ec;
00075   UNSIGNED_QUAD nwidths, nheights, ndepths;
00076   UNSIGNED_QUAD nitcor, nlig, nkern, nextens;
00077   UNSIGNED_QUAD nfonparm;
00078 #ifndef WITHOUT_OMEGA
00079   UNSIGNED_QUAD fontdir;
00080   UNSIGNED_QUAD nco, ncw, npc;
00081 #endif /* !WITHOUT_OMEGA */
00082   SIGNED_QUAD   *header;
00083 #ifndef WITHOUT_ASCII_PTEX
00084   UNSIGNED_PAIR *chartypes;
00085 #endif /* !WITHOUT_ASCII_PTEX */
00086   UNSIGNED_QUAD *char_info;
00087   UNSIGNED_PAIR *width_index;
00088   UNSIGNED_BYTE *height_index;
00089   UNSIGNED_BYTE *depth_index;
00090   SIGNED_QUAD   *width;
00091   SIGNED_QUAD   *height;
00092   SIGNED_QUAD   *depth;
00093 };
00094 
00095 static void
00096 tfm_font_init (struct tfm_font *tfm) 
00097 {
00098   tfm->header = NULL;
00099 #ifndef WITHOUT_ASCII_PTEX
00100   tfm->id = 0;
00101   tfm->nt = 0;
00102   tfm->chartypes = NULL;
00103 #endif /* !WITHOUT_ASCII_PTEX */
00104 #ifndef WITHOUT_OMEGA
00105   tfm->level   = 0;
00106   tfm->fontdir = 0;
00107   tfm->nco = tfm->ncw = tfm->npc = 0;
00108 #endif
00109   tfm->char_info    = NULL;
00110   tfm->width_index  = NULL;
00111   tfm->height_index = NULL;
00112   tfm->depth_index  = NULL;
00113   tfm->width = tfm->height = tfm->depth = NULL;
00114 }
00115 
00116 static void
00117 tfm_font_clear (struct tfm_font *tfm)
00118 {
00119   if (tfm) {
00120     if (tfm->header) {
00121       RELEASE(tfm->header);
00122       tfm->header = NULL;
00123     }
00124     if (tfm->char_info) {
00125       RELEASE(tfm->char_info);
00126       tfm->char_info = NULL;
00127     }
00128     if (tfm->width) {
00129       RELEASE(tfm->width);
00130       tfm->width = NULL;
00131     }
00132     if (tfm->height) {
00133       RELEASE(tfm->height);
00134       tfm->height = NULL;
00135     }
00136     if (tfm->depth) {
00137       RELEASE(tfm->depth);
00138       tfm->depth = NULL;
00139     }
00140 #ifndef WITHOUT_ASCII_PTEX
00141     if (tfm->chartypes) {
00142       RELEASE(tfm->chartypes);
00143       tfm->chartypes = NULL;
00144     }
00145 #endif /* !WITHOUT_ASCII_PTEX */
00146     if (tfm->width_index) {
00147       RELEASE(tfm->width_index);
00148       tfm->width_index = NULL;
00149     }
00150     if (tfm->height_index) {
00151       RELEASE(tfm->height_index);
00152       tfm->height_index = NULL;
00153     }
00154     if (tfm->depth_index) {
00155       RELEASE(tfm->depth_index);
00156       tfm->depth_index = NULL;
00157     }
00158   }
00159 }
00160 
00161 
00162 struct coverage
00163 {
00164   long           first_char;
00165   unsigned short num_chars;
00166 };
00167 
00168 /*
00169  * All characters in the same range have same metrics.
00170  */
00171 
00172 struct range_map {
00173   unsigned short   num_coverages;
00174   struct coverage *coverages;
00175   unsigned short  *indices;
00176 };
00177 
00178 /* Special case of num_coverages = 1 */
00179 struct char_map
00180 {
00181   struct coverage coverage;
00182   unsigned short *indices;
00183 };
00184 
00185 static void
00186 release_char_map (struct char_map *map)
00187 {
00188   if (map->indices)
00189     RELEASE(map->indices);
00190   map->indices = NULL;
00191   RELEASE(map);
00192 }
00193 
00194 static void
00195 release_range_map (struct range_map *map)
00196 {
00197   if (map->coverages)
00198     RELEASE(map->coverages);
00199   if (map->indices)
00200     RELEASE(map->indices);
00201   map->coverages = NULL;
00202   map->indices   = NULL;
00203   RELEASE(map);
00204 }
00205 
00206 static long
00207 lookup_char (const struct char_map *map, long charcode)
00208 {
00209   if (charcode >= map->coverage.first_char &&
00210       charcode <= map->coverage.first_char + map->coverage.num_chars)
00211     return map->indices[charcode - map->coverage.first_char];
00212   else
00213     return -1;
00214 
00215   return -1;
00216 }
00217 
00218 static long
00219 lookup_range (const struct range_map *map, long charcode)
00220 {
00221   long  idx;
00222 
00223   for (idx = map->num_coverages - 1; idx >= 0 &&
00224         charcode >= map->coverages[idx].first_char; idx--) {
00225     if (charcode <=
00226        map->coverages[idx].first_char + map->coverages[idx].num_chars)
00227       return map->indices[idx];
00228   }
00229 
00230   return -1;
00231 }
00232 
00233 #define SOURCE_TYPE_TFM 0
00234 #define SOURCE_TYPE_JFM 1
00235 #define SOURCE_TYPE_OFM 2
00236 
00237 #define MAPTYPE_NONE  0
00238 #define MAPTYPE_CHAR  1
00239 #define MAPTYPE_RANGE 2
00240 
00241 #define FONT_DIR_HORIZ 0
00242 #define FONT_DIR_VERT  1
00243 
00244 struct font_metric
00245 {
00246   char    *tex_name;
00247   fixword  designsize;
00248   char    *codingscheme;
00249 
00250   int  fontdir;
00251   long firstchar, lastchar;
00252   
00253   fixword *widths;
00254   fixword *heights;
00255   fixword *depths;
00256 
00257   struct {
00258     int   type;
00259     void *data;
00260   } charmap;
00261 
00262   int source;
00263 };
00264 
00265 static void
00266 fm_init (struct font_metric *fm) 
00267 {
00268   fm->tex_name = NULL;
00269   fm->firstchar = 0;
00270   fm->lastchar  = 0;
00271   fm->fontdir   = FONT_DIR_HORIZ;
00272   fm->codingscheme = NULL;
00273   fm->designsize   = 0;
00274 
00275   fm->widths  = NULL;
00276   fm->heights = NULL;
00277   fm->depths  = NULL;
00278 
00279   fm->charmap.type = MAPTYPE_NONE;
00280   fm->charmap.data = NULL;
00281 
00282   fm->source = SOURCE_TYPE_TFM;
00283 }
00284 
00285 static void
00286 fm_clear (struct font_metric *fm)
00287 {
00288   if (fm) {
00289     if (fm->tex_name)
00290       RELEASE(fm->tex_name);
00291     if (fm->widths)
00292       RELEASE(fm->widths);
00293     if (fm->heights)
00294       RELEASE(fm->heights);
00295     if (fm->depths)
00296       RELEASE(fm->depths);
00297     if (fm->codingscheme)
00298       RELEASE(fm->codingscheme);
00299 
00300     switch (fm->charmap.type) {
00301     case MAPTYPE_CHAR:
00302       release_char_map(fm->charmap.data);
00303       break;
00304     case MAPTYPE_RANGE:
00305       release_range_map(fm->charmap.data);
00306       break;
00307     }
00308   }
00309 }
00310 
00311 #ifndef MAX_FONTS
00312 #define MAX_FONTS 16
00313 #endif
00314 
00315 struct font_metric *fms = NULL;
00316 static unsigned numfms = 0, max_fms = 0;
00317 
00318 static void
00319 fms_need (unsigned n)
00320 {
00321   if (n > max_fms) {
00322     max_fms = MAX(max_fms + MAX_FONTS, n);
00323     fms = RENEW(fms, max_fms, struct font_metric);
00324   }
00325 }
00326 
00327 void
00328 tfm_set_verbose (void)
00329 {
00330   verbose++;
00331 }
00332 
00333 
00334 static long
00335 fread_fwords (SIGNED_QUAD *words, SIGNED_QUAD nmemb, FILE *fp)
00336 {
00337   long i;
00338 
00339   for (i = 0; i < nmemb; i++)
00340     words[i] = get_signed_quad(fp);
00341 
00342   return nmemb*4;
00343 }
00344 
00345 static long
00346 fread_uquads (UNSIGNED_QUAD *quads, SIGNED_QUAD nmemb, FILE *fp)
00347 {
00348   long i;
00349 
00350   for (i = 0; i < nmemb; i++) {
00351     quads[i] = get_unsigned_quad(fp);
00352   }
00353 
00354   return nmemb*4;
00355 }
00356 
00357 /*
00358  * TFM and JFM
00359  */
00360 static void
00361 tfm_check_size (struct tfm_font *tfm, SIGNED_QUAD tfm_file_size)
00362 {
00363   UNSIGNED_QUAD expected_size = 6;
00364 
00365   /* Removed the warning message caused by EC TFM metric files.
00366    *
00367   if (tfm->wlenfile != tfm_file_size / 4) {
00368     WARN("TFM file size is %ld bytes but it says it is %ld bytes!",
00369         tfm_file_size, tfm->wlenfile * 4);
00370     if (tfm_file_size > tfm->wlenfile * 4) {
00371       WARN("Proceeding nervously...");
00372     } else {
00373       ERROR("Can't proceed...");
00374     }
00375   }
00376    */
00377   if (tfm_file_size < tfm->wlenfile * 4) {
00378     ERROR("Can't proceed...");
00379   }
00380 
00381   expected_size += (tfm->ec - tfm->bc + 1);
00382   expected_size += tfm->wlenheader;
00383   expected_size += tfm->nwidths;
00384   expected_size += tfm->nheights;
00385   expected_size += tfm->ndepths;
00386   expected_size += tfm->nitcor;
00387   expected_size += tfm->nlig;
00388   expected_size += tfm->nkern;
00389   expected_size += tfm->nextens;
00390   expected_size += tfm->nfonparm;
00391 #ifndef WITHOUT_ASCII_PTEX
00392   if (IS_JFM(tfm->id)) {
00393     expected_size += tfm->nt + 1;
00394   }
00395 #endif /* !WITHOUT_ASCII_PTEX */
00396   if (expected_size != tfm->wlenfile) {
00397     WARN("TFM file size is expected to be %ld bytes but it says it is %ld bytes!",
00398         expected_size * 4, tfm->wlenfile * 4);
00399     if (tfm_file_size > expected_size *4) {
00400       WARN("Proceeding nervously...");
00401     } else {
00402       ERROR("Can't proceed...");
00403     }
00404   }
00405 }
00406 
00407 static void
00408 tfm_get_sizes (FILE *tfm_file, SIGNED_QUAD tfm_file_size, struct tfm_font *tfm)
00409 {
00410 #ifndef WITHOUT_ASCII_PTEX
00411   {
00412     UNSIGNED_PAIR first_hword;
00413 
00414     /*
00415      * The first half word of TFM/JFM is TFM ID for JFM or size of
00416      * TFM file in word for TFM. TFM with 9*4 or 11*4 bytes is not
00417      * expected to be a valid TFM. So, we always assume that TFMs
00418      * starting with 00 09 or 00 0B is JFM.
00419      */
00420     first_hword = get_unsigned_pair(tfm_file);
00421     if (IS_JFM(first_hword)) {
00422       tfm->id = first_hword;
00423       tfm->nt = get_unsigned_pair(tfm_file);
00424       tfm->wlenfile = get_unsigned_pair(tfm_file);
00425     } else {
00426       tfm->wlenfile = first_hword;
00427     }
00428   }
00429 #else /* WITHOUT_ASCII_PTEX */
00430   tfm->wlenfile = get_unsigned_pair(tfm_file);
00431 #endif /* !WITHOUT_ASCII_PTEX */
00432 
00433   tfm->wlenheader = get_unsigned_pair(tfm_file);
00434   tfm->bc = get_unsigned_pair(tfm_file);
00435   tfm->ec = get_unsigned_pair(tfm_file);
00436   if (tfm->ec < tfm->bc) {
00437     ERROR("TFM file error: ec(%u) < bc(%u) ???", tfm->ec, tfm->bc);
00438   }
00439   tfm->nwidths  = get_unsigned_pair(tfm_file);
00440   tfm->nheights = get_unsigned_pair(tfm_file);
00441   tfm->ndepths  = get_unsigned_pair(tfm_file);
00442   tfm->nitcor   = get_unsigned_pair(tfm_file);
00443   tfm->nlig     = get_unsigned_pair(tfm_file);
00444   tfm->nkern    = get_unsigned_pair(tfm_file);
00445   tfm->nextens  = get_unsigned_pair(tfm_file);
00446   tfm->nfonparm = get_unsigned_pair(tfm_file);
00447 
00448   tfm_check_size(tfm, tfm_file_size);
00449 
00450   return;
00451 }
00452 
00453 #ifndef WITHOUT_ASCII_PTEX
00454 static void
00455 jfm_do_char_type_array (FILE *tfm_file, struct tfm_font *tfm)
00456 {
00457   UNSIGNED_PAIR charcode;
00458   UNSIGNED_PAIR chartype;
00459   long i;
00460 
00461   tfm->chartypes = NEW(65536, UNSIGNED_PAIR);
00462   for (i = 0; i < 65536; i++) {
00463     tfm->chartypes[i] = 0;
00464   }
00465   for (i = 0; i < tfm->nt; i++) {
00466     charcode = get_unsigned_pair(tfm_file);
00467     chartype = get_unsigned_pair(tfm_file);
00468     tfm->chartypes[charcode] = chartype;
00469   }
00470 }
00471 
00472 static void
00473 jfm_make_charmap (struct font_metric *fm, struct tfm_font *tfm)
00474 {
00475   if (tfm->nt > 1) {
00476     struct char_map *map;
00477     long   code;
00478 
00479     fm->charmap.type = MAPTYPE_CHAR;
00480     fm->charmap.data = map = NEW(1, struct char_map);
00481     map->coverage.first_char = 0;
00482     map->coverage.num_chars  = 0xFFFFu;
00483     map->indices    = NEW(0x10000L, unsigned short);
00484 
00485     for (code = 0; code <= 0xFFFFu; code++) {
00486       map->indices[code] = tfm->chartypes[code];
00487     }
00488   } else {
00489     struct range_map *map;
00490 
00491     fm->charmap.type = MAPTYPE_RANGE;
00492     fm->charmap.data = map = NEW(1, struct range_map);
00493     map->num_coverages = 1;
00494     map->coverages     = NEW(map->num_coverages, struct coverage);
00495     map->coverages[0].first_char = 0;
00496     map->coverages[0].num_chars  = 0xFFFFu;
00497     map->indices = NEW(1, unsigned short);
00498     map->indices[0] = 0; /* Only default type used. */
00499   }
00500 }
00501 #endif /* !WITHOUT_ASCII_PTEX */
00502 
00503 static void
00504 tfm_unpack_arrays (struct font_metric *fm, struct tfm_font *tfm)
00505 {
00506   UNSIGNED_QUAD charinfo;
00507   UNSIGNED_PAIR width_index, height_index, depth_index;
00508   int i;
00509 
00510   fm->widths  = NEW(256, fixword);
00511   fm->heights = NEW(256, fixword);
00512   fm->depths  = NEW(256, fixword);
00513   for (i = 0; i < 256; i++) {
00514     fm->widths [i] = 0;
00515     fm->heights[i] = 0;
00516     fm->depths [i] = 0;
00517   }
00518 
00519   for (i = tfm->bc; i <= tfm->ec; i++ ) {
00520     charinfo     = tfm->char_info[i - tfm->bc];
00521     width_index  = (charinfo / 16777216ul);
00522     height_index = (charinfo / 0x100000ul) & 0xf;
00523     depth_index  = (charinfo / 0x10000ul)  & 0xf;
00524     fm->widths [i] = tfm->width [width_index];
00525     fm->heights[i] = tfm->height[height_index];
00526     fm->depths [i] = tfm->depth [depth_index];
00527   }
00528 
00529   return;
00530 }
00531 
00532 static int
00533 sput_bigendian (char *s, SIGNED_QUAD v, int n)
00534 {
00535   int i;
00536 
00537   for (i = n-1; i >= 0; i--) {
00538     s[i] = (char) (v & 0xff);
00539     v >>= 8;
00540   }
00541 
00542   return n;
00543 }
00544 
00545 static void
00546 tfm_unpack_header (struct font_metric *fm, struct tfm_font *tfm)
00547 {
00548   if (tfm->wlenheader < 12) {
00549     fm->codingscheme = NULL;
00550   } else {
00551     int   i, len;
00552     char *p;
00553 
00554     len = (tfm->header[2] >> 24);
00555     if (len < 0 || len > 39)
00556       ERROR("Invalid TFM header.");
00557     if (len > 0) {
00558       fm->codingscheme = NEW(40, char);
00559       p = fm->codingscheme;
00560       p += sput_bigendian(p, tfm->header[2], 3);
00561       for (i = 1; i <= len / 4; i++) {
00562        p += sput_bigendian(p, tfm->header[2+i], 4);
00563       }
00564       fm->codingscheme[len] = '\0';
00565     } else {
00566       fm->codingscheme = NULL;
00567     }
00568   }
00569 
00570   fm->designsize = tfm->header[1];
00571 }
00572 
00573 #ifndef WITHOUT_OMEGA
00574 
00575 static void
00576 ofm_check_size_one (struct tfm_font *tfm, SIGNED_QUAD ofm_file_size)
00577 {
00578   UNSIGNED_QUAD ofm_size = 14;
00579 
00580   ofm_size += 2*(tfm->ec - tfm->bc + 1);
00581   ofm_size += tfm->wlenheader;
00582   ofm_size += tfm->nwidths;
00583   ofm_size += tfm->nheights;
00584   ofm_size += tfm->ndepths;
00585   ofm_size += tfm->nitcor;
00586   ofm_size += 2*(tfm->nlig);
00587   ofm_size += tfm->nkern;
00588   ofm_size += 2*(tfm->nextens);
00589   ofm_size += tfm->nfonparm;
00590   if (tfm->wlenfile != ofm_file_size / 4 ||
00591       tfm->wlenfile != ofm_size) {
00592     ERROR("OFM file problem.  Table sizes don't agree.");
00593   }
00594 }
00595 
00596 static void
00597 ofm_get_sizes (FILE *ofm_file, UNSIGNED_QUAD ofm_file_size, struct tfm_font *tfm)
00598 {
00599   tfm->level = get_signed_quad(ofm_file);
00600 
00601   tfm->wlenfile   = get_signed_quad(ofm_file);
00602   tfm->wlenheader = get_signed_quad(ofm_file);
00603   tfm->bc = get_signed_quad(ofm_file);
00604   tfm->ec = get_signed_quad(ofm_file);
00605   if (tfm->ec < tfm->bc) {
00606     ERROR("OFM file error: ec(%u) < bc(%u) ???", tfm->ec, tfm->bc);
00607   }
00608   tfm->nwidths  = get_signed_quad(ofm_file);
00609   tfm->nheights = get_signed_quad(ofm_file);
00610   tfm->ndepths  = get_signed_quad(ofm_file);
00611   tfm->nitcor   = get_signed_quad(ofm_file);
00612   tfm->nlig     = get_signed_quad(ofm_file);
00613   tfm->nkern    = get_signed_quad(ofm_file);
00614   tfm->nextens  = get_signed_quad(ofm_file);
00615   tfm->nfonparm = get_signed_quad(ofm_file);
00616   tfm->fontdir  = get_signed_quad(ofm_file);
00617   if (tfm->fontdir) {
00618     WARN("I may be interpreting a font direction incorrectly.");
00619   }
00620   if (tfm->level == 0) {
00621     ofm_check_size_one(tfm, ofm_file_size);
00622   } else if (tfm->level == 1) {
00623     tfm->nco = get_signed_quad(ofm_file);
00624     tfm->ncw = get_signed_quad(ofm_file);
00625     tfm->npc = get_signed_quad(ofm_file);
00626     seek_absolute(ofm_file, 4*(tfm->nco - tfm->wlenheader));
00627   } else {
00628     ERROR("Can't handle OFM files with level > 1");
00629   }
00630 
00631   return;
00632 }
00633 
00634 static void
00635 ofm_do_char_info_zero (FILE *tfm_file, struct tfm_font *tfm)
00636 {
00637   UNSIGNED_QUAD num_chars;
00638 
00639   num_chars = tfm->ec - tfm->bc + 1;
00640   if (num_chars != 0) {
00641     UNSIGNED_QUAD i;
00642 
00643     tfm->width_index  = NEW(num_chars, UNSIGNED_PAIR);
00644     tfm->height_index = NEW(num_chars, UNSIGNED_BYTE);
00645     tfm->depth_index  = NEW(num_chars, UNSIGNED_BYTE);
00646     for (i = 0; i < num_chars; i++) {
00647       tfm->width_index [i] = get_unsigned_pair(tfm_file);
00648       tfm->height_index[i] = get_unsigned_byte(tfm_file);
00649       tfm->depth_index [i] = get_unsigned_byte(tfm_file);
00650       /* Ignore remaining quad */
00651       get_unsigned_quad(tfm_file);
00652     }
00653   }
00654 }
00655 
00656 static void
00657 ofm_do_char_info_one (FILE *tfm_file, struct tfm_font *tfm)
00658 {
00659   UNSIGNED_QUAD num_char_infos;
00660   UNSIGNED_QUAD num_chars;
00661 
00662   num_char_infos = tfm->ncw / (3 + (tfm->npc / 2));
00663   num_chars      = tfm->ec - tfm ->bc + 1;
00664 
00665   if (num_chars != 0) {
00666     UNSIGNED_QUAD i;
00667     UNSIGNED_QUAD char_infos_read;
00668 
00669     tfm->width_index  = NEW(num_chars, UNSIGNED_PAIR);
00670     tfm->height_index = NEW(num_chars, UNSIGNED_BYTE);
00671     tfm->depth_index  = NEW(num_chars, UNSIGNED_BYTE);
00672     char_infos_read   = 0;
00673     for (i = 0; i < num_chars &&
00674           char_infos_read < num_char_infos; i++) {
00675       int repeats, j;
00676 
00677       tfm->width_index [i] = get_unsigned_pair(tfm_file);
00678       tfm->height_index[i] = get_unsigned_byte(tfm_file);
00679       tfm->depth_index [i] = get_unsigned_byte(tfm_file);
00680       /* Ignore next quad */
00681       get_unsigned_quad(tfm_file);
00682       repeats = get_unsigned_pair(tfm_file);
00683       /* Skip params */
00684       for (j = 0; j < tfm->npc; j++) {
00685        get_unsigned_pair(tfm_file);
00686       }
00687       /* Remove word padding if necessary */
00688       if (ISEVEN(tfm->npc)){
00689        get_unsigned_pair(tfm_file);
00690       }
00691       char_infos_read++;
00692       if (i + repeats > num_chars) {
00693        ERROR("Repeats causes number of characters to be exceeded.");
00694       }
00695       for (j = 0; j < repeats; j++) {
00696        tfm->width_index [i+j+1] = tfm->width_index [i];
00697        tfm->height_index[i+j+1] = tfm->height_index[i];
00698        tfm->depth_index [i+j+1] = tfm->depth_index [i];
00699       }
00700       /* Skip ahead because we have already handled repeats */
00701       i += repeats;
00702     }
00703   }
00704 }
00705 
00706 static void
00707 ofm_unpack_arrays (struct font_metric *fm,
00708                  struct tfm_font *tfm, UNSIGNED_QUAD num_chars)
00709 {
00710   long i;
00711 
00712   fm->widths  = NEW(tfm->bc + num_chars, fixword);
00713   fm->heights = NEW(tfm->bc + num_chars, fixword);
00714   fm->depths  = NEW(tfm->bc + num_chars, fixword);
00715   for (i = 0; i < num_chars; i++) {
00716     fm->widths [tfm->bc + i] = tfm->width [ tfm->width_index [i] ];
00717     fm->heights[tfm->bc + i] = tfm->height[ tfm->height_index[i] ];
00718     fm->depths [tfm->bc + i] = tfm->depth [ tfm->depth_index [i] ];
00719   }
00720 }
00721 
00722 static void
00723 read_ofm (struct font_metric *fm, FILE *ofm_file, UNSIGNED_QUAD ofm_file_size)
00724 {
00725   struct tfm_font tfm;
00726 
00727   tfm_font_init(&tfm);
00728 
00729   ofm_get_sizes(ofm_file, ofm_file_size, &tfm);
00730 
00731   if (tfm.level < 0 || tfm.level > 1)
00732     ERROR ("OFM level %d not supported.", tfm.level);
00733 
00734   if (tfm.wlenheader > 0) {
00735     tfm.header = NEW(tfm.wlenheader, fixword);
00736     fread_fwords(tfm.header, tfm.wlenheader, ofm_file);
00737   }
00738   if (tfm.level == 0) {
00739     ofm_do_char_info_zero(ofm_file, &tfm);
00740   } else if (tfm.level == 1) {
00741     ofm_do_char_info_one(ofm_file, &tfm);
00742   }
00743   if (tfm.nwidths > 0) {
00744     tfm.width = NEW(tfm.nwidths, fixword);
00745     fread_fwords(tfm.width, tfm.nwidths, ofm_file);
00746   }
00747   if (tfm.nheights > 0) {
00748     tfm.height = NEW(tfm.nheights, fixword);
00749     fread_fwords(tfm.height, tfm.nheights, ofm_file);
00750   }
00751   if (tfm.ndepths > 0) {
00752     tfm.depth = NEW(tfm.ndepths, fixword);
00753     fread_fwords(tfm.depth, tfm.ndepths, ofm_file);
00754   }
00755 
00756   ofm_unpack_arrays(fm, &tfm, tfm.ec - tfm.bc + 1);
00757   tfm_unpack_header(fm, &tfm);
00758   fm->firstchar = tfm.bc;
00759   fm->lastchar  = tfm.ec;
00760   fm->source    = SOURCE_TYPE_OFM;
00761 
00762   tfm_font_clear(&tfm);
00763 
00764   return;
00765 }
00766 #endif /* !WITHOUT_OMEGA */
00767 
00768 static void
00769 read_tfm (struct font_metric *fm, FILE *tfm_file, UNSIGNED_QUAD tfm_file_size)
00770 {
00771   struct tfm_font tfm;
00772 
00773   tfm_font_init(&tfm);
00774 
00775   tfm_get_sizes(tfm_file, tfm_file_size, &tfm);
00776   fm->firstchar = tfm.bc;
00777   fm->lastchar  = tfm.ec;
00778   if (tfm.wlenheader > 0) {
00779     tfm.header = NEW(tfm.wlenheader, fixword);
00780     fread_fwords(tfm.header, tfm.wlenheader, tfm_file);
00781   }
00782 #ifndef WITHOUT_ASCII_PTEX
00783   if (IS_JFM(tfm.id)) {
00784     jfm_do_char_type_array(tfm_file, &tfm);
00785     jfm_make_charmap(fm, &tfm);
00786     fm->firstchar = 0;
00787     fm->lastchar  = 0xFFFFl;
00788     fm->fontdir   = (tfm.id == JFMV_ID) ? FONT_DIR_VERT : FONT_DIR_HORIZ;
00789     fm->source    = SOURCE_TYPE_JFM;
00790   }
00791 #endif /* !WITHOUT_ASCII_PTEX */
00792   if (tfm.ec - tfm.bc + 1 > 0) {
00793     tfm.char_info = NEW(tfm.ec - tfm.bc + 1, UNSIGNED_QUAD);
00794     fread_uquads(tfm.char_info, tfm.ec - tfm.bc + 1, tfm_file);
00795   }
00796   if (tfm.nwidths > 0) {
00797     tfm.width = NEW(tfm.nwidths, fixword);
00798     fread_fwords(tfm.width, tfm.nwidths, tfm_file);
00799   }
00800   if (tfm.nheights > 0) {
00801     tfm.height = NEW(tfm.nheights, fixword);
00802     fread_fwords(tfm.height, tfm.nheights, tfm_file);
00803   }
00804   if (tfm.ndepths > 0) {
00805     tfm.depth = NEW(tfm.ndepths, fixword);
00806     fread_fwords(tfm.depth, tfm.ndepths, tfm_file);
00807   }
00808   tfm_unpack_arrays(fm, &tfm);
00809   tfm_unpack_header(fm, &tfm);
00810 
00811   tfm_font_clear(&tfm);
00812 
00813   return;
00814 }
00815 
00816 #if 0
00817 int
00818 tfm_open_old (const char *tfm_name, int must_exist)
00819 {
00820   FILE *tfm_file;
00821   int i, format = TFM_FORMAT;
00822   UNSIGNED_QUAD tfm_file_size;
00823   char *file_name = NULL;
00824 
00825   for (i = 0; i < numfms; i++) {
00826     if (!strcmp(tfm_name, fms[i].tex_name))
00827       return i;
00828   }
00829 
00830   /*
00831    * The procedure to search tfm or ofm files:
00832    * 1. Search tfm file with the given name with the must_exist flag unset.
00833    * 2. Search ofm file with the given name with the must_exist flag unset.
00834    * 3. If not found and must_exist flag is set, try again to search
00835    *    tfm file with the must_exist flag set.
00836    * 4. If not found and must_exist flag is not set, return -1.
00837    */
00838 
00839 
00840   /*
00841    * We first look for OFM and then TFM.
00842    * The reason for this change is incompatibility introduced when dvipdfmx
00843    * started to write correct glyph metrics to output PDF for CID fonts.
00844    * I'll not explain this in detail... This change is mostly specific to
00845    * Japanese support.
00846    */
00847 #if 0
00848   if ((file_name = kpse_find_file(tfm_name, kpse_tfm_format, 0))) {
00849     format = TFM_FORMAT;
00850   } else if ((file_name = kpse_find_file(tfm_name, kpse_ofm_format, 0))) {
00851     format = OFM_FORMAT;
00852   }
00853 #endif
00854  {
00855    char *ofm_name, *suffix;
00856 
00857    suffix = strrchr(tfm_name, '.');
00858    if (!suffix || (strcmp(suffix, ".tfm") != 0 &&
00859                  strcmp(suffix, ".ofm") != 0)) {
00860      ofm_name = NEW(strlen(tfm_name) + strlen(".ofm") + 1, char);
00861      strcpy(ofm_name, tfm_name);
00862      strcat(ofm_name, ".ofm");
00863    } else {
00864      ofm_name = NULL;
00865    }
00866    if (ofm_name &&
00867        (file_name = kpse_find_file(ofm_name, kpse_ofm_format, 0)) != NULL) {
00868      format = OFM_FORMAT;
00869    } else if ((file_name =
00870               kpse_find_file(tfm_name, kpse_tfm_format, 0)) != NULL) {
00871      format = TFM_FORMAT;
00872    } else if ((file_name =
00873               kpse_find_file(tfm_name, kpse_ofm_format, 0)) != NULL) {
00874      format = OFM_FORMAT;
00875    }
00876    if (ofm_name)
00877      RELEASE(ofm_name);
00878  }
00879 
00880   /*
00881    * In case that must_exist is set, MiKTeX returns always non-NULL value
00882    * even if the tfm file is not found.
00883    */
00884   if (file_name == NULL) {
00885     if (must_exist) {
00886       if ((file_name = kpse_find_file(tfm_name, kpse_tfm_format, 1)) != NULL)
00887        format = TFM_FORMAT;
00888       else {
00889        ERROR("Unable to find TFM file \"%s\".", tfm_name);
00890       }
00891     } else {
00892       return -1;
00893     }
00894   }
00895   tfm_file = MFOPEN(file_name, FOPEN_RBIN_MODE);
00896 
00897   if (verbose) {
00898     if (format == TFM_FORMAT)
00899       MESG("(TFM:%s", tfm_name);
00900     else if (format == OFM_FORMAT)
00901       MESG("(OFM:%s", tfm_name);
00902     if (verbose > 1)
00903       MESG("[%s]", file_name);
00904   }
00905   
00906   RELEASE(file_name);
00907   
00908 
00909   tfm_file_size = file_size(tfm_file);
00910   if (tfm_file_size < 24) {
00911     ERROR("TFM/OFM file too small to be a valid file.");
00912   }
00913   
00914   
00915   if (!tfm_file) {
00916     ERROR("Could not open specified TFM/OFM file \"%s\".", tfm_name);
00917   }
00918 
00919 
00920   fms_need(numfms + 1);
00921   fm_init(fms + numfms);
00922 
00923 #ifndef WITHOUT_OMEGA
00924   if (format == OFM_FORMAT)
00925     read_ofm(&fms[numfms], tfm_file, tfm_file_size);
00926   else
00927 #endif /* !WITHOUT_OMEGA */
00928     {
00929       read_tfm(&fms[numfms], tfm_file, tfm_file_size);
00930     }
00931 
00932   MFCLOSE(tfm_file);
00933 
00934   fms[numfms].tex_name = NEW(strlen(tfm_name)+1, char);
00935   strcpy(fms[numfms].tex_name, tfm_name);
00936 
00937   if (verbose) 
00938     MESG(")");
00939 
00940   return numfms++;
00941 }
00942 
00943 #endif
00944 
00945 int
00946 tfm_open (const char *tfm_name, int must_exist)
00947 {
00948   FILE *tfm_file;
00949   int i;
00950   UNSIGNED_QUAD tfm_file_size;
00951   char *tex_name = NULL;
00952 
00953   {
00954     // find tex_name
00955     int i = strlen(tfm_name)-1;
00956     while (i>=0) {
00957       if (tfm_name[i] != '/') i--;
00958       else break;
00959     }
00960     i++;
00961     tex_name = NEW(strlen(tfm_name+i),char);
00962     strcpy(tex_name,tfm_name+i);
00963   }
00964   
00965   
00966   for (i = 0; i < numfms; i++) {
00967     if (!strcmp(tex_name, fms[i].tex_name))
00968       return i;
00969   }
00970 
00971   tfm_file = MFOPEN(tfm_name, FOPEN_RBIN_MODE);
00972   
00973 #if 0
00974   if (verbose) {
00975     if (format == TFM_FORMAT)
00976       MESG("(TFM:%s", tfm_name);
00977     else if (format == OFM_FORMAT)
00978       MESG("(OFM:%s", tfm_name);
00979     if (verbose > 1)
00980       MESG("[%s]", file_name);
00981   }
00982 #endif
00983   
00984   
00985   tfm_file_size = file_size(tfm_file);
00986   if (tfm_file_size < 24) {
00987     ERROR("TFM file too small to be a valid file.");
00988   }
00989   
00990   
00991   if (!tfm_file) {
00992     ERROR("Could not open specified TFM file \"%s\".", tfm_name);
00993   }
00994   
00995   
00996   fms_need(numfms + 1);
00997   fm_init(fms + numfms);
00998   
00999   {
01000     read_tfm(&fms[numfms], tfm_file, tfm_file_size);
01001   }
01002   
01003   MFCLOSE(tfm_file);
01004   
01005   fms[numfms].tex_name = NEW(strlen(tex_name)+1, char);
01006   strcpy(fms[numfms].tex_name, tex_name);
01007   
01008   if (verbose) 
01009     MESG(")");
01010   
01011   RELEASE(tex_name);
01012   
01013   return numfms++;
01014 }
01015 
01016 
01017 void
01018 tfm_close_all (void)
01019 {
01020   int  i;
01021 
01022   if (fms) {
01023     for (i = 0; i < numfms; i++) {
01024       fm_clear(&(fms[i]));
01025     }
01026     RELEASE(fms);
01027   }
01028 }
01029 
01030 #define CHECK_ID(n) do {\
01031   if ((n) < 0 || (n) >= numfms)\
01032     ERROR("TFM: Invalid TFM ID: %d", (n));\
01033 } while (0)
01034 
01035 fixword
01036 tfm_get_fw_width (int font_id, SIGNED_QUAD ch)
01037 {
01038   struct font_metric *fm;
01039   long idx = 0;
01040 
01041   CHECK_ID(font_id);
01042 
01043   fm = &(fms[font_id]);
01044   if (ch >= fm->firstchar && ch <= fm->lastchar) {
01045     switch (fm->charmap.type) {
01046     case MAPTYPE_CHAR:
01047       idx = lookup_char(fm->charmap.data, ch);
01048       if (idx < 0)
01049        ERROR("Invalid char: %ld\n", ch);
01050       break;
01051     case MAPTYPE_RANGE:
01052       idx = lookup_range(fm->charmap.data, ch);
01053       if (idx < 0)
01054        ERROR("Invalid char: %ld\n", ch);
01055       break;
01056     default:
01057       idx = ch;
01058     }
01059   } else {
01060     ERROR("Invalid char: %ld\n", ch);
01061   }
01062 
01063   return fm->widths[idx];
01064 }
01065 
01066 fixword
01067 tfm_get_fw_height (int font_id, SIGNED_QUAD ch)
01068 {
01069   struct font_metric *fm;
01070   long idx = 0;
01071 
01072   CHECK_ID(font_id);
01073 
01074   fm = &(fms[font_id]);
01075   if (ch >= fm->firstchar && ch <= fm->lastchar) {
01076     switch (fm->charmap.type) {
01077     case MAPTYPE_CHAR:
01078       idx = lookup_char(fm->charmap.data, ch);
01079       if (idx < 0)
01080        ERROR("Invalid char: %ld\n", ch);
01081       break;
01082     case MAPTYPE_RANGE:
01083       idx = lookup_range(fm->charmap.data, ch);
01084       if (idx < 0)
01085        ERROR("Invalid char: %ld\n", ch);
01086       break;
01087     default:
01088       idx = ch;
01089     }
01090   } else {
01091     ERROR("Invalid char: %ld\n", ch);
01092   }
01093 
01094   return fm->heights[idx];
01095 }
01096 
01097 fixword
01098 tfm_get_fw_depth (int font_id, SIGNED_QUAD ch)
01099 {
01100   struct font_metric *fm;
01101   long idx = 0;
01102 
01103   CHECK_ID(font_id);
01104 
01105   fm = &(fms[font_id]);
01106   if (ch >= fm->firstchar && ch <= fm->lastchar) {
01107     switch (fm->charmap.type) {
01108     case MAPTYPE_CHAR:
01109       idx = lookup_char(fm->charmap.data, ch);
01110       if (idx < 0)
01111        ERROR("Invalid char: %ld\n", ch);
01112       break;
01113     case MAPTYPE_RANGE:
01114       idx = lookup_range(fm->charmap.data, ch);
01115       if (idx < 0)
01116        ERROR("Invalid char: %ld\n", ch);
01117       break;
01118     default:
01119       idx = ch;
01120     }
01121   } else {
01122     ERROR("Invalid char: %ld\n", ch);
01123   }
01124 
01125   return fm->depths[idx];
01126 }
01127 
01128 
01129 /*
01130  * tfm_get_width returns the width of the font
01131  * as a (double) fraction of the design size.
01132  */
01133 double
01134 tfm_get_width (int font_id, SIGNED_QUAD ch)
01135 {
01136   return ((double) tfm_get_fw_width(font_id, ch)/FWBASE);
01137 }
01138 
01139 #if 0
01140 double
01141 tfm_get_height (int font_id, SIGNED_QUAD ch)
01142 {
01143   return ((double) tfm_get_fw_height(font_id, ch)/FWBASE);
01144 }
01145 
01146 double
01147 tfm_get_depth (int font_id, SIGNED_QUAD ch)
01148 {
01149   return ((double) tfm_get_fw_depth(font_id, ch)/FWBASE);
01150 }
01151 #endif
01152 
01153 /* tfm_string_xxx() do not work for OFM... */
01154 fixword
01155 tfm_string_width (int font_id, const unsigned char *s, unsigned len)
01156 {
01157   fixword result = 0;
01158   struct font_metric *fm;
01159   unsigned i;
01160 
01161   CHECK_ID(font_id);
01162 
01163   fm = &(fms[font_id]);
01164 #ifndef WITHOUT_ASCII_PTEX
01165   if (fm->source == SOURCE_TYPE_JFM) {
01166     for (i = 0; i < len/2; i++) {
01167       SIGNED_QUAD ch;
01168 
01169       ch = (s[2*i] << 8)|s[2*i+1];
01170       result += tfm_get_fw_width(font_id, ch);
01171     }
01172   } else
01173 #endif
01174     for (i = 0; i < len; i++) {
01175       result += tfm_get_fw_width(font_id, s[i]);
01176     }
01177 
01178   return result;
01179 }
01180 
01181 fixword
01182 tfm_string_depth (int font_id, const unsigned char *s, unsigned len)
01183 {
01184   fixword result = 0;
01185   struct font_metric *fm;
01186   unsigned i;
01187 
01188   CHECK_ID(font_id);
01189 
01190   fm = &(fms[font_id]);
01191 #ifndef WITHOUT_ASCII_PTEX
01192   if (fm->source == SOURCE_TYPE_JFM) {
01193     for (i = 0; i < len/2; i++) {
01194       SIGNED_QUAD ch;
01195 
01196       ch = (s[2*i] << 8)|s[2*i+1];
01197       result += tfm_get_fw_depth(font_id, ch);
01198     }
01199   } else
01200 #endif
01201     for (i = 0; i < len; i++) {
01202       result = MAX(result, tfm_get_fw_depth(font_id, s[i]));
01203     }
01204 
01205   return result;
01206 }
01207 
01208 fixword
01209 tfm_string_height (int font_id, const unsigned char *s, unsigned len)
01210 {
01211   fixword result = 0;
01212   struct font_metric *fm;
01213   unsigned i;
01214 
01215   CHECK_ID(font_id);
01216 
01217   fm = &(fms[font_id]);
01218 #ifndef WITHOUT_ASCII_PTEX
01219   if (fm->source == SOURCE_TYPE_JFM) {
01220     for (i = 0; i < len/2; i++) {
01221       SIGNED_QUAD ch;
01222 
01223       ch = (s[2*i] << 8)|s[2*i+1];
01224       result += tfm_get_fw_height(font_id, ch);
01225     }
01226   } else
01227 #endif
01228     for (i = 0; i < len; i++) {
01229       result = MAX(result, tfm_get_fw_height(font_id, s[i]));
01230     }
01231 
01232   return result;
01233 }
01234 
01235 double
01236 tfm_get_design_size (int font_id)
01237 {
01238   CHECK_ID(font_id);
01239 
01240   return (double) (fms[font_id].designsize)/FWBASE*(72.0/72.27);
01241 }
01242 
01243 #if 0
01244 char *
01245 tfm_get_codingscheme (int font_id)
01246 {
01247   CHECK_ID(font_id);
01248 
01249   return fms[font_id].codingscheme;
01250 }
01251 
01252 #ifndef WITHOUT_ASCII_PTEX
01253 /* Vertical version of JFM */
01254 int
01255 tfm_is_vert (int font_id)
01256 {
01257   CHECK_ID(font_id);
01258 
01259   return (fms[font_id].fontdir == FONT_DIR_VERT) ? 1 : 0;
01260 }
01261 #else /* WITHOUT_ASCII_PTEX */
01262 int
01263 tfm_is_vert (int font_id)
01264 {
01265   return 0;
01266 }
01267 #endif /* !WITHOUT_ASCII_PTEX */
01268 #endif
01269 
01270 int
01271 tfm_exists (const char *tfm_name)
01272 {
01273 #ifdef NOKPSE
01274   char *fullname;
01275 
01276   fullname = kpse_find_file(tfm_name, kpse_ofm_format, 0);
01277   if (fullname) {
01278     RELEASE(fullname);
01279     return 1;
01280   }
01281   fullname = kpse_find_file(tfm_name, kpse_tfm_format, 0);
01282   if (fullname) {
01283     RELEASE(fullname);
01284     return 1;
01285   }
01286 #else
01287 #endif
01288   return 0;
01289 }