home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / fontutils-0.6-base.tgz / fontutils-0.6-base.tar / fsf / fontutils / lib / font.c < prev    next >
C/C++ Source or Header  |  1992-06-14  |  14KB  |  464 lines

  1. /* font.c: define (more or less) format-independent font operations.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <ctype.h>
  22.  
  23. #include "filename.h"
  24. #include "font.h"
  25. #include "gf.h"
  26. #include "list.h"
  27. #include "pk.h"
  28. #include "tfm.h"
  29.  
  30.  
  31. /* We want to allow reading of multiple fonts, so we keep some
  32.    information around for each font we read.  */
  33.  
  34. typedef struct
  35. {
  36.   bitmap_format_type bitmap_format;
  37.   boolean bitmap_only;
  38.   font_info_type info;
  39. } internal_font_type;
  40.  
  41. /* The format of the bitmap file for this font.  */
  42. #define INTERNAL_BITMAP_FORMAT(i)  ((i).bitmap_format)
  43.  
  44. /* If the font was opened with `get_bitmap_font', this field is true;
  45.    if with `get_font', false.  */
  46. #define INTERNAL_BITMAP_ONLY(i)  ((i).bitmap_only)
  47.  
  48. /* The filename for the bitmap font.  */
  49. #define INTERNAL_BITMAP_NAME(i)  ((i).bitmap_name)
  50.  
  51. /* The fontwide information.  The parts of this that are found in the
  52.    TFM file are garbage if INTERNAL_BITMAP_ONLY (I) is true.  */
  53. #define INTERNAL_FONT_INFO(i)  ((i).info)
  54.  
  55.  
  56. static void delete_internal_font (string filename);
  57. static internal_font_type *find_internal_font (string font_name);
  58. static void save_internal_font (string font_name, internal_font_type);
  59.  
  60. /* Starting with FONT_NAME as the base filename, e.g., `cmr10', we try
  61.    various extensions to find a PK or GF file at resolution DPI.  This
  62.    bitmap font defines the shapes of the characters.  */
  63.    
  64. bitmap_font_type
  65. get_bitmap_font (string font_name, unsigned dpi)
  66. {
  67.   bitmap_font_type font;
  68.   internal_font_type internal_f;
  69.   internal_font_type *internal_font_ptr;
  70.   string pk_name, gf_name;
  71.   boolean found_pk = false, found_gf = false;
  72.  
  73.   /* If we are passed a null pointer or the empty string, it's got to be
  74.      a mistake.  */
  75.   assert (font_name && *font_name);
  76.  
  77.   /* If we already have the font saved, we just return it, thus (1) saving
  78.      going out to the file system, and (2) causing multiple calls with
  79.      the same FONT_NAME not to open more and more bitmap files.  */
  80.   internal_font_ptr = find_internal_font (font_name); 
  81.   if (internal_font_ptr != NULL)
  82.     return FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*internal_font_ptr));
  83.  
  84.   pk_name = find_pk_filename (font_name, dpi);
  85.   if (pk_name != NULL)
  86.     { /* Found the PK file, so unless something strange is happening
  87.          (like the file being removed between the `find_path_filename'
  88.          call and the `pk_open_input_file' call), we will be able to
  89.          open it.  */
  90.       found_pk = pk_open_input_file (pk_name);
  91.       if (!found_pk)
  92.         FATAL_PERROR (pk_name);
  93.     }
  94.   else if ((gf_name = find_gf_filename (font_name, dpi)) != NULL)
  95.     {
  96.       found_gf = gf_open_input_file (gf_name);
  97.       if (!found_gf)
  98.         {
  99.           perror (gf_name);
  100.           FATAL1 ("(I couldn't find the PK file `%s', either.)", pk_name);
  101.         }
  102.     }
  103.   else
  104.     FATAL2 ("%s.%d{gf,pk}: Nowhere in path", font_name, dpi);
  105.  
  106.     
  107.   /* We've opened the files; get the information we need to return.  */
  108.   if (found_pk)
  109.     {
  110.       pk_preamble_type preamble = pk_get_preamble (pk_name);
  111.  
  112.       BITMAP_FONT_DESIGN_SIZE (font)
  113.         = fix_to_real (PK_DESIGN_SIZE (preamble));
  114.       BITMAP_FONT_COMMENT (font) = PK_COMMENT (preamble);
  115.       BITMAP_FONT_CHECKSUM (font) = PK_CHECKSUM (preamble);
  116.       BITMAP_FONT_FILENAME (font) = pk_name;
  117.  
  118.       INTERNAL_BITMAP_FORMAT (internal_f) = pk_format;
  119.     }
  120.   else if (found_gf)
  121.     {
  122.       gf_postamble_type postamble = gf_get_postamble ();
  123.  
  124.       BITMAP_FONT_DESIGN_SIZE (font)
  125.         = fix_to_real (GF_DESIGN_SIZE (postamble));
  126.       BITMAP_FONT_COMMENT (font) = gf_get_preamble ();
  127.       BITMAP_FONT_CHECKSUM (font) = GF_CHECKSUM (postamble);
  128.       BITMAP_FONT_FILENAME (font) = gf_name;
  129.  
  130.       INTERNAL_BITMAP_FORMAT (internal_f) = gf_format;
  131.     }
  132.   else
  133.     FATAL ("No bitmap file found, but I must have found one");
  134.  
  135.   FONT_BITMAP_FONT (INTERNAL_FONT_INFO (internal_f)) = font;
  136.   INTERNAL_BITMAP_ONLY (internal_f) = true;
  137.  
  138.   save_internal_font (font_name, internal_f);
  139.  
  140.   return font;
  141. }
  142.  
  143.  
  144. /* Look for both a bitmap font named FONT_NAME, and for the TFM file
  145.    FONT_NAME.tfm.  We call `get_bitmap_font' to find the bitmap font. 
  146.    For the TFM file, we use the path in the environment variable
  147.    TEXFONTS; if TEXFONTS isn't set, we use the default defined above.
  148.    
  149.    If FONT_NAME was previously opened with `get_bitmap_font', we give a
  150.    fatal error.  */
  151.  
  152. font_info_type
  153. get_font (string font_name, unsigned dpi)
  154. {
  155.   unsigned bitmap_checksum;
  156.   font_info_type font;
  157.   internal_font_type internal_f;
  158.   internal_font_type *internal_font_ptr;
  159.   unsigned tfm_checksum;
  160.   string tfm_name;
  161.  
  162.   /* If we are passed a null pointer or the empty string, it's got to be
  163.      a mistake.  */
  164.   assert (font_name != NULL && *font_name);
  165.  
  166.   /* If we already have the font saved, we just return it, thus (1) saving
  167.      going out to the file system, and (2) causing multiple calls with
  168.      the same FONT_NAME not to open more and more bitmap files.  */
  169.   internal_font_ptr = find_internal_font (font_name); 
  170.   if (internal_font_ptr != NULL)
  171.     if (INTERNAL_BITMAP_ONLY (*internal_font_ptr))
  172.       FATAL1 ("get_font: `%s' was opened with get_bitmap_font", font_name);
  173.     else
  174.       return INTERNAL_FONT_INFO (*internal_font_ptr);
  175.  
  176.   /* If we don't have the font saved, we have to look for the TFM file.  */
  177.   tfm_name = find_tfm_filename (font_name);
  178.  
  179.   if (tfm_name == NULL)
  180.     FATAL1 ("%s.tfm: Nowhere in path", font_name);
  181.  
  182.   if (!tfm_open_input_file (tfm_name))
  183.     FATAL_PERROR (tfm_name);
  184.  
  185.  
  186.   /* The TFM file is opened.  Save some global information.  */
  187.   FONT_TFM_FONT (font) = tfm_get_global_info ();
  188.   FONT_TFM_FILENAME (font) = tfm_name;
  189.   
  190.   /* Read the (we hope) corresponding bitmap file.  */
  191.   FONT_BITMAP_FONT (font) = get_bitmap_font (font_name, dpi);
  192.   
  193.   /* We have found the bitmap font on the filesystem, so it should be in
  194.      our internal list now.  We will overwrite it below.  */
  195.   internal_font_ptr = find_internal_font (font_name);
  196.   assert (internal_font_ptr != NULL);
  197.   
  198.   /* We've opened the files; now get the information we're supposed to
  199.      return.  */
  200.  
  201.   /* Let's check the checksums.  */
  202.   tfm_checksum = tfm_get_checksum ();
  203.   bitmap_checksum = BITMAP_FONT_CHECKSUM (FONT_BITMAP_FONT (font));
  204.  
  205.   if (tfm_checksum != 0 && bitmap_checksum != 0 
  206.       && tfm_checksum != bitmap_checksum)
  207.     WARNING1 ("%s: TFM and bitmap checksums don't match", font_name);
  208.  
  209.   INTERNAL_FONT_INFO (internal_f) = font;
  210.   INTERNAL_BITMAP_ONLY (internal_f) = false;
  211.   INTERNAL_BITMAP_FORMAT (internal_f)
  212.     = INTERNAL_BITMAP_FORMAT (*internal_font_ptr);
  213.   save_internal_font (font_name, internal_f);
  214.  
  215.   return font;
  216. }
  217.  
  218. /* Close the files we have opened, for tidiness.  */
  219.  
  220. void
  221. close_font (string font_name)
  222. {
  223.   internal_font_type *f = find_internal_font (font_name);
  224.  
  225.   if (f == NULL)
  226.     FATAL1 ("close_font: Font `%s' not open", font_name);
  227.     
  228.   switch (INTERNAL_BITMAP_FORMAT (*f))
  229.     {
  230.     case pk_format:
  231.       {
  232.         string pk_name
  233.           = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
  234.         pk_close_input_file (pk_name);
  235.       }
  236.       break;
  237.     
  238.     case gf_format:
  239.       gf_close_input_file ();
  240.       break;
  241.     
  242.     default:
  243.       FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
  244.     }
  245.  
  246.   if (!INTERNAL_BITMAP_ONLY (*f))
  247.     tfm_close_input_file ();
  248.   
  249.   delete_internal_font (font_name);
  250. }
  251.  
  252. /* Look for the character numbered CODE in the font FONT_NAME.  If it
  253.    doesn't exist, return NULL.  Otherwise, fill in a `char_info_type'
  254.    structure and return a pointer to it. 
  255.    
  256.    This merely calls the get-a-character routine in the appropriate
  257.    library.  */
  258.  
  259. char_info_type *
  260. get_char (string font_name, one_byte code)
  261. {
  262.   char_info_type *c;
  263.   internal_font_type *f = find_internal_font (font_name);
  264.   
  265.   if (f == NULL)
  266.     FATAL1 ("get_char: Font `%s' not open", font_name);
  267.  
  268.   switch (INTERNAL_BITMAP_FORMAT (*f))
  269.     {
  270.     case pk_format:
  271.       {
  272.         string pk_name
  273.           = BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
  274.         pk_char_type *pk_char = pk_get_char (code, pk_name);
  275.         if (pk_char == NULL) return NULL;
  276.         
  277.         c = XTALLOC1 (char_info_type);
  278.         CHARCODE (*c) = PK_CHARCODE (*pk_char);
  279.         CHAR_SET_WIDTH (*c) = PK_H_ESCAPEMENT (*pk_char);
  280.         CHAR_TFM_WIDTH (*c) = PK_TFM_WIDTH (*pk_char);
  281.         CHAR_BB (*c) = PK_CHAR_BB (*pk_char);
  282.         CHAR_BITMAP (*c) = PK_BITMAP (*pk_char);
  283.       }
  284.       break;
  285.     
  286.     case gf_format:
  287.       {
  288.         gf_char_type *gf_char = gf_get_char (code);
  289.         if (gf_char == NULL) return NULL;
  290.  
  291.         c = XTALLOC1 (char_info_type);
  292.         CHARCODE (*c) = GF_CHARCODE (*gf_char);
  293.         CHAR_SET_WIDTH (*c) = GF_H_ESCAPEMENT (*gf_char);
  294.         CHAR_TFM_WIDTH (*c) = GF_TFM_WIDTH (*gf_char);
  295.         CHAR_BB (*c) = GF_CHAR_BB (*gf_char);
  296.         CHAR_BITMAP (*c) = GF_BITMAP (*gf_char);
  297.       }
  298.       break;
  299.     
  300.     default:
  301.       FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
  302.     }
  303.   
  304.   return c;
  305. }
  306.  
  307. /* Look for the character numbered CODE in the font FONT_NAME.  If it
  308.    doesn't exist, return NULL.  Otherwise, fill in a `raw_char_type'
  309.    structure and return a pointer to it. 
  310.    
  311.    This merely calls the corresponding routine in the appropriate
  312.    library.  */
  313.  
  314. raw_char_type *
  315. get_raw_char (string font_name, one_byte code)
  316. {
  317.   raw_char_type *c;
  318.   internal_font_type *f = find_internal_font (font_name);
  319.   
  320.   if (f == NULL)
  321.     FATAL1 ("get_raw_char: Font `%s' not open", font_name);
  322.  
  323.   switch (INTERNAL_BITMAP_FORMAT (*f))
  324.     {
  325.     case pk_format:
  326.       c = NULL;
  327.       break;
  328.     
  329.     case gf_format:
  330.       c = gf_get_raw_char (code);
  331.       break;
  332.       
  333.     default:
  334.       FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
  335.     }
  336.   
  337.   if (c != NULL)
  338.     RAW_CHAR_BITMAP_FORMAT (*c) = INTERNAL_BITMAP_FORMAT (*f);
  339.   return c;
  340. }
  341.  
  342.  
  343. /* Free the information in the raw character RAW_CHAR, including the
  344.    character itself.  */
  345.  
  346. void
  347. free_raw_char (raw_char_type *raw_char)
  348. {
  349.   free (RAW_CHAR_BYTES (*raw_char));
  350.   free (raw_char);
  351. }
  352.  
  353. /* Print the character C to the file F, using ordinary characters.  */
  354.  
  355. void
  356. print_char (FILE *f, char_info_type c)
  357. {
  358.   unsigned this_row, this_col;
  359.   bitmap_type b = CHAR_BITMAP (c);
  360.  
  361.   fprintf (f, "Character 0x%x=%u", CHARCODE (c), CHARCODE (c));
  362.   if (isprint (CHARCODE (c)))
  363.     fprintf (f, " (%c)", CHARCODE (c));
  364.   
  365.   fprintf (f, ":\n");
  366.   
  367.   fprintf (f, "   min/max col %d/%d, min/max row %d/%d, set width %d.\n", 
  368.            CHAR_MIN_COL (c), CHAR_MAX_COL (c),
  369.            CHAR_MIN_ROW (c), CHAR_MAX_ROW (c), CHAR_SET_WIDTH (c));
  370.   
  371.   /* We don't call `print_bitmap' because we want to print the Cartesian
  372.      row number, as well as the bitmap row number.  */
  373.  
  374.   for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++)
  375.     {
  376.       for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++)
  377.         putc (BITMAP_PIXEL (b, this_row, this_col) ? '*' : ' ', f);
  378.       
  379.       fprintf (f, "%3d\t%u\n", CHAR_MAX_ROW (c) - this_row, this_row);
  380.     }
  381. }
  382.  
  383. /* We want to implement a typical key/value setup: here we are given the
  384.    key (FONT_NAME) and the value (F).  We assign an index number to
  385.    FONT_NAME, and store it and F in parallel lists.  If we are passed a
  386.    FONT_NAME that is already in the list, we overwrite the old value.  */
  387.  
  388. static list_type font_name_list, internal_font_list;
  389.  
  390. static void
  391. save_internal_font (string font_name, internal_font_type f)
  392. {
  393.   string *new_name;
  394.   internal_font_type *new_font;
  395.   static boolean first_call = true;
  396.   
  397.   if (first_call)
  398.     { /* Have to construct our lists.  */
  399.       font_name_list = list_init ();
  400.       internal_font_list = list_init ();
  401.       first_call = false;
  402.     }
  403.  
  404.   new_font = find_internal_font (font_name);
  405.   if (new_font == NULL)
  406.     {
  407.       /* Add another pointer to the end of the lists.  */
  408.       new_name = LIST_TAPPEND (&font_name_list, string);
  409.       new_font = LIST_TAPPEND (&internal_font_list, internal_font_type);
  410.  
  411.       /* Save the information.  */
  412.       *new_name = xstrdup (font_name);
  413.     }
  414.   
  415.   /* Either update the existing font, or save the new one.  */
  416.   *new_font = f;
  417. }
  418.  
  419.  
  420. /* This routine returns the font information previously stored with
  421.    FONT_NAME.  If FONT_NAME hasn't been saved, we return NULL.  */
  422.  
  423. static internal_font_type *
  424. find_internal_font (string font_name)
  425. {
  426.   unsigned e;
  427.  
  428.   for (e = 0; e < LIST_SIZE (font_name_list); e++)
  429.     if (STREQ (*(string *) LIST_ELT (font_name_list, e), font_name))
  430.       return (internal_font_type *) LIST_ELT (internal_font_list, e);
  431.  
  432.   return NULL;
  433. }
  434.  
  435.  
  436. /* Remove FILENAME from `font_name_list', by setting the name in
  437.    `font_name_list' to the empty string, so that the element is useless.
  438.    (We don't have any actual memory to free.)  What a kludge.  */
  439.  
  440. static void
  441. delete_internal_font (string filename)
  442. {
  443.   unsigned e;
  444.  
  445.   /* We can't use `find_internal_font', since we need to know the list
  446.      element index, not just the internal font information.  */ 
  447.   for (e = 0; e < LIST_SIZE (font_name_list); e++)
  448.     if (STREQ (*(string *) LIST_ELT (font_name_list, e), filename))
  449.       {
  450.         string *name = LIST_ELT (font_name_list, e);
  451.         internal_font_type *i
  452.           = (internal_font_type *) LIST_ELT (internal_font_list, e);
  453.  
  454.         free (*name);
  455.         *name = "";
  456.         
  457.         free (i);
  458.  
  459.         return;
  460.       }
  461.  
  462.   FATAL1 ("The font `%s' hasn't been saved", filename);
  463. }
  464.