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 / charspace / char.c < prev    next >
C/C++ Source or Header  |  1992-07-19  |  12KB  |  383 lines

  1. /* char.c: functions to muck with `char_type's.
  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 "list.h"
  22. #include "report.h"
  23.  
  24. #include "char.h"
  25. #include "kern.h"
  26. #include "main.h"
  27. #include "symtab.h"
  28.  
  29.  
  30. static boolean resolve_sidebearing (sidebearing_type *);
  31. static void update_kerns (char_type *, tfm_char_type *);
  32. static void update_metrics (real, real, char_info_type *, tfm_char_type *);
  33. static void update_sidebearings (char_type *, char_info_type *,
  34.                                  tfm_char_type *);
  35. static char_type *update_via_name (string, char_info_type *, tfm_char_type *);
  36. static void update_width (char_type *, char_info_type *, tfm_char_type *);
  37.  
  38. /* Initialize the parts of the character structure.  */
  39.  
  40. char_type
  41. init_char ()
  42. {
  43.   char_type c;
  44.   
  45.   CHAR_BITMAP_INFO (c) = NULL;
  46.   CHAR_TFM_INFO (c) = NULL;
  47.   CHAR_LSB (c) = NULL;
  48.   CHAR_RSB (c) = NULL;
  49.   CHAR_KERNS (c) = list_init ();
  50.   
  51.   return c;
  52. }
  53.  
  54. /* Our goal here is to extract the information about the character CODE
  55.    from the symbol table, and fill in the information from the bitmap
  56.    and TFM fonts.  We also read ligature information from the encoding
  57.    vector.  C_PTR_ADDR is the address of a pointer to the `char_type' we
  58.    fill in (or will be).
  59.    
  60.    Thus far, we have information only in the symbol table, and thus
  61.    can be retrieved only by character name.  But when it comes
  62.    time to output, we obviously have to do it by number.  If we can find
  63.    `encoding_info's name for CODE in the symbol table, great -- we can
  64.    make *C_PTR_ADDR point at that character and fill it in.  If not,
  65.    then we allocate some new space -- just because the character wasn't
  66.    mentioned in the CMI files shouldn't mean it doesn't get output.
  67.    (Only if we can't find bitmap information for a character do we not
  68.    output it.)
  69.    
  70.    We return true if CODE will be output, false if not.  */
  71.  
  72. void
  73. do_char (charcode_type code, char_type **c_ptr_addr)
  74. {
  75.   static unsigned char_count = 0;
  76.   string char_name;
  77.   tfm_char_type *tfm_char = NULL;
  78.   
  79.   /* Check that the character CODE exists in the input font.  */
  80.   char_info_type *bitmap_char = get_char (input_name, code);
  81.  
  82.   /* If no bitmap information, give up.  Everything else we can fake.  */
  83.   if (bitmap_char == NULL)
  84.     return;
  85.   
  86.   REPORT1 ("[%d", CHARCODE (*bitmap_char));
  87.   
  88.   /* Look for existing TFM information.  */
  89.   if (have_tfm)
  90.     tfm_char = tfm_get_char (code);
  91.   
  92.   /* If no prior TFM file, or if the character CODE wasn't there,
  93.      initialize `tfm_char' from the bitmap information.  */
  94.   if (tfm_char == NULL)
  95.     {
  96.       tfm_char = XTALLOC1 (tfm_char_type);
  97.       *tfm_char = tfm_new_char ();
  98.       
  99.       TFM_CHAR_EXISTS (*tfm_char) = true;
  100.       TFM_CHARCODE (*tfm_char) = code;
  101.       TFM_HEIGHT (*tfm_char)
  102.         = PIXELS_TO_POINTS (CHAR_HEIGHT (*bitmap_char), dpi_real);
  103.       TFM_DEPTH (*tfm_char)
  104.         = PIXELS_TO_POINTS (CHAR_DEPTH (*bitmap_char), dpi_real);
  105.       /* Leave the italic correction at zero, since we don't know how to
  106.          compute a reasonable value.  And don't bother to compute the
  107.          width, since we do so below.  */
  108.     }
  109.   
  110.   /* We've initialized the TFM and bitmap information from previously
  111.      existing files.  Next, get the character name from the global
  112.      `encoding_info', so we can get at info in the symbol table.  */
  113.   char_name = ENCODING_CHAR_NAME (encoding_info, code);
  114.  
  115.   if (char_name == NULL)
  116.     WARNING1 ("No character name for character %d", code);
  117.   else
  118.     *c_ptr_addr = update_via_name (char_name, bitmap_char, tfm_char);
  119.   
  120.   /* If we haven't allocated a `char_type' yet, do so.  The fields which
  121.      get used for the CMI stuff -- the side bearings and kern list --
  122.      don't need to be initialized.  */
  123.   if (*c_ptr_addr == NULL)
  124.     *c_ptr_addr = XTALLOC1 (char_type);
  125.  
  126.   /* Set the pointers in *C_PTR_ADDR to the new bitmap and TFM info.  */
  127.   CHAR_BITMAP_INFO (**c_ptr_addr) = bitmap_char;
  128.   CHAR_TFM_INFO (**c_ptr_addr) = tfm_char;
  129.   
  130.   REPORT1 ("]%c", ++char_count % 13 == 0 ? '\n' : ' ');
  131.  
  132.   return;
  133. }
  134.  
  135. /* Assume that CHAR_NAME exists in the encoding vector.  If looking up
  136.    CHAR_NAME in the symbol table yields a character, return a pointer to
  137.    the `char_type' in the symbol table with updated side bearing
  138.    information.  Otherwise we return NULL.  In any case, update TFM_CHAR
  139.    with the ligatures from the global `encoding_info'.  */
  140.  
  141. static char_type *
  142. update_via_name (string char_name, char_info_type *bitmap_char,
  143.                  tfm_char_type *tfm_char)
  144. {
  145.   list_type enc_ligs;
  146.   unsigned l;
  147.   char_type *c_ptr = NULL;
  148.  
  149.   /* We have a character name, so look for side bearing info.  */
  150.   symval_type *sv = symtab_lookup (char_name);
  151.  
  152.   if (sv == NULL)
  153.     WARNING1 ("%s: Undefined in CMI files", char_name);
  154.  
  155.   else if (SYMVAL_TAG (*sv) == symval_char)
  156.     { 
  157.       /* We'll return `c_ptr', a pointer to the struct in the symbol table.  */
  158.       c_ptr = &SYMVAL_CHAR (*sv);
  159.  
  160.       update_sidebearings (c_ptr, bitmap_char, tfm_char);
  161.       update_kerns (c_ptr, tfm_char);
  162.     }
  163.  
  164.   else if (SYMVAL_TAG (*sv) == symval_char_width)
  165.     { 
  166.       /* We'll return `c_ptr', a pointer to the struct in the symbol table.  */
  167.       c_ptr = &SYMVAL_CHAR (*sv);
  168.  
  169.       update_width (c_ptr, bitmap_char, tfm_char);
  170.       update_kerns (c_ptr, tfm_char);
  171.     }
  172.  
  173.   else
  174.     WARNING1 ("%s: Not defined as a character", char_name);
  175.  
  176.   /* Regardless of whether CHAR_NAME was in the symbol table, we can
  177.      also update the ligature list from `encoding_info'.  */
  178.   enc_ligs = ENCODING_CHAR_LIG (encoding_info, CHARCODE (*bitmap_char));
  179.   for (l = 0; l < LIST_SIZE (enc_ligs); l++)
  180.     {
  181.       tfm_ligature_type *lig = LIST_ELT (enc_ligs, l);
  182.       tfm_set_ligature (&TFM_LIGATURE (*tfm_char), lig->character,
  183.                         lig->ligature);
  184.     }
  185.  
  186.   return c_ptr;
  187. }
  188.  
  189. /* Update the set width and sidebearings for a character defined with
  190.    `char-width'.  We take the RSB info in C_PTR to be the desired set
  191.    width and the LSB to be the percentage of whitespace to make the left
  192.    side bearing.  We update BITMAP_CHAR and TFM_CHAR correspondingly.  */
  193.  
  194. static void
  195. update_width (char_type *c_ptr, char_info_type *bitmap_char,
  196.               tfm_char_type *tfm_char)
  197. {
  198.   real lsb_percent = 0.0;
  199.   charcode_type code = CHARCODE (*bitmap_char);
  200.   /* We might not have info for the character, though, so set up the
  201.      defaults as the existing metrics.  */
  202.   boolean changed_metrics = false;
  203.   real lsb = CHAR_MIN_COL (*bitmap_char);
  204.   real real_width = CHAR_SET_WIDTH (*bitmap_char);
  205.  
  206.   /* Find the lsb percent.  */
  207.   if (CHAR_LSB (*c_ptr) == NULL)
  208.     WARNING1 ("char %d: No left side bearing information", code);
  209.   else if (resolve_sidebearing (CHAR_LSB (*c_ptr)))
  210.     {
  211.       lsb_percent = SB_REAL (*CHAR_LSB (*c_ptr));
  212.       if (lsb_percent <= 0.0)
  213.         WARNING2 ("char %d: lsb percent (%f) must be nonnegative",
  214.                   code, lsb_percent);
  215.     }
  216.  
  217.   if (CHAR_RSB (*c_ptr) == NULL)
  218.     WARNING1 ("char %d: No set width information", CHARCODE (*bitmap_char));
  219.   else if (resolve_sidebearing (CHAR_RSB (*c_ptr)))
  220.     {
  221.       real_width = SB_REAL (*CHAR_RSB (*c_ptr));
  222.       changed_metrics = true;
  223.     }
  224.  
  225.   /* If we have a positive percent, figure out the new lsb.  */
  226.   if (lsb_percent > 0.0)
  227.     {
  228.       real whitespace = real_width - CHAR_BITMAP_WIDTH (*bitmap_char);
  229.       lsb = whitespace * lsb_percent;
  230.       changed_metrics = true;
  231.     }
  232.  
  233.   /* If necessary, update the widths.  */
  234.   if (changed_metrics)
  235.     update_metrics (real_width, lsb, bitmap_char, tfm_char);
  236. }
  237.  
  238.  
  239. /* Call `resolve_sidebearing' on the sidebearing info in C_PTR.  If that
  240.    succeeds, update the various widths and side bearing info in
  241.    BITMAP_CHAR and TFM_CHAR.  This is called for characters defined with
  242.    the `char' command.  */
  243.  
  244. static void
  245. update_sidebearings (char_type *c_ptr, char_info_type *bitmap_char,
  246.                      tfm_char_type *tfm_char)
  247. {
  248.   /* We might not have side bearing info for it, so set up the defaults
  249.      as the existing side bearings.  */
  250.   boolean changed_sb = false;
  251.   real lsb = CHAR_MIN_COL (*bitmap_char);
  252.   real rsb = CHAR_SET_WIDTH (*bitmap_char) - CHAR_MAX_COL (*bitmap_char);
  253.  
  254.   /* Compute the side bearings.  */
  255.   if (CHAR_LSB (*c_ptr) == NULL)
  256.     WARNING1 ("char %d: No left side bearing information",
  257.               CHARCODE (*bitmap_char));
  258.   else if (resolve_sidebearing (CHAR_LSB (*c_ptr)))
  259.     {
  260.       lsb = SB_REAL (*CHAR_LSB (*c_ptr));
  261.       changed_sb = true;
  262.     }
  263.  
  264.   if (CHAR_RSB (*c_ptr) == NULL)
  265.     WARNING1 ("char %d: No right side bearing information",
  266.               CHARCODE (*bitmap_char));
  267.   else if (resolve_sidebearing (CHAR_RSB (*c_ptr)))
  268.     {
  269.       rsb = SB_REAL (*CHAR_RSB (*c_ptr));
  270.       changed_sb = true;
  271.     }
  272.  
  273.   /* If the side bearings changed, then update the widths.  */
  274.   if (changed_sb)
  275.     {
  276.       real real_width = lsb + CHAR_BITMAP_WIDTH (*bitmap_char) + rsb;
  277.       update_metrics (real_width, lsb, bitmap_char, tfm_char);
  278.     }
  279. }
  280.  
  281. /* Following routines are called by both `update_sidebearings' and
  282.    `update_width'.  */
  283.  
  284. /* Try to make the definition of SB into a number, by looking up names
  285.    in the symbol table.  */
  286.  
  287. static boolean
  288. resolve_sidebearing (sidebearing_type *sb)
  289. {
  290.   boolean ok;
  291.   symval_type sv;
  292.   
  293.   /* This should have already been checked.  */
  294.   assert (sb != NULL);
  295.   
  296.   /* Make SB into a symval so we can resolve it.  */
  297.   SYMVAL_TAG (sv) = SB_TAG (*sb);
  298.   SYMVAL_REAL_STRING (sv) = SB_VALUE (*sb);
  299.   
  300.   ok = symval_resolve (&sv);
  301.   
  302.   if (ok)
  303.     {
  304.       SB_TAG (*sb) = symval_real;
  305.       SB_REAL (*sb) = SYMVAL_REAL (sv);
  306.     }
  307.   else
  308.     {
  309.       string desc = symval_as_string (sv);
  310.       WARNING1 ("Unresolvable sidebearing definition `%s'", desc);
  311.       free (desc);
  312.     }
  313.  
  314.   return ok;
  315. }
  316.  
  317.  
  318. /* Update the widths and side bearings in BITMAP_CHAR and TFM_CHAR
  319.    according to REAL_WIDTH and LSB.  */
  320.  
  321. static void
  322. update_metrics (real real_width, real lsb, char_info_type *bitmap_char,
  323.                 tfm_char_type *tfm_char)
  324. {
  325.   int pixel_width = ROUND (real_width);
  326.   real point_width = PIXELS_TO_POINTS (real_width, dpi_real);
  327.   real ds = get_designsize_in_points ();
  328.  
  329.   TFM_WIDTH (*tfm_char) = point_width;
  330.   CHAR_TFM_WIDTH (*bitmap_char) = real_to_fix (point_width / ds);
  331.   CHAR_SET_WIDTH (*bitmap_char) = pixel_width;
  332.   CHAR_MIN_COL (*bitmap_char) = lsb;
  333.   CHAR_MAX_COL (*bitmap_char) = lsb + CHAR_BITMAP_WIDTH (*bitmap_char);
  334. }
  335.  
  336. /* Update the kern list in TFM_CHAR from any kerns in *C_PTR.  */
  337.  
  338. static void
  339. update_kerns (char_type *c_ptr, tfm_char_type *tfm_char)
  340. {
  341.   unsigned k;
  342.   list_type char_kerns = CHAR_KERNS (*c_ptr);
  343.   
  344.   for (k = 0; k < LIST_SIZE (char_kerns); k++)
  345.     {
  346.       char_kern_type *kern_elt = LIST_ELT (char_kerns, k);
  347.  
  348.       /* If the name of the kern character isn't in the global
  349.          `encoding_info', skip it.  */ 
  350.       int code = encoding_number (encoding_info, kern_elt->character);
  351.  
  352.       if (code != -1)
  353.         {
  354.           if (symval_resolve (&kern_elt->kern))
  355.             {
  356.               real pixel_kern = SYMVAL_REAL (kern_elt->kern);
  357.               real points_kern = PIXELS_TO_POINTS (pixel_kern, dpi_real);
  358.               
  359.               tfm_set_kern (&TFM_KERN (*tfm_char), code, points_kern);
  360.         }
  361.           else
  362.             {
  363.               string desc = symval_as_string (kern_elt->kern);
  364.               WARNING2 ("%s: Unresolvable kern value `%s'",
  365.                      kern_elt->character, desc);
  366.               free (desc);
  367.         }
  368.     }
  369.     }
  370. }
  371.  
  372. /* We need to do this several times, so...  Have to use the global
  373.    `dpi-real'.  */
  374.  
  375. real
  376. get_designsize_in_points ()
  377. {
  378.   real ds_pixels = symtab_lookup_real ("designsize");
  379.   real ds_points = PIXELS_TO_POINTS (ds_pixels, dpi_real);
  380.   
  381.   return ds_points;
  382. }
  383.