Back to index

tetex-bin  3.0
tex-glyph.c
Go to the documentation of this file.
00001 /* tex-glyph.c: Search for GF/PK files.
00002 
00003 Copyright (C) 1993, 94, 95, 96 Karl Berry.
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Library General Public
00007 License as published by the Free Software Foundation; either
00008 version 2 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Library General Public License for more details.
00014 
00015 You should have received a copy of the GNU Library General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00018 
00019 #include <kpathsea/config.h>
00020 
00021 #include <kpathsea/absolute.h>
00022 #include <kpathsea/expand.h>
00023 #include <kpathsea/fontmap.h>
00024 #include <kpathsea/pathsearch.h>
00025 #include <kpathsea/tex-glyph.h>
00026 #include <kpathsea/tex-make.h>
00027 #include <kpathsea/variable.h>
00028 
00029 /* Routines are in bottom-up order.  */
00030 
00031 /* Support both cmr10.300pk and dpi300/cmr10.pk.  (Use the latter
00032    instead of dpi300\cmr10.pk since DOS supports /'s, but Unix doesn't
00033    support \'s.  */
00034 #define UNIX_BITMAP_SPEC "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
00035 #define DPI_BITMAP_SPEC  "dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
00036 
00037 /* Look up FONTNAME at resolution DPI in PATH, with filename suffix
00038    EXTENSION.  Return file found or NULL.  */
00039 
00040 static string
00041 try_format P3C(const_string, fontname,  unsigned, dpi,
00042                kpse_file_format_type,  format)
00043 {
00044   static const_string bitmap_specs[]
00045     = { UNIX_BITMAP_SPEC, DPI_BITMAP_SPEC, NULL };
00046   const_string *spec;
00047   boolean must_exist;
00048   string ret = NULL;
00049   const_string path = kpse_format_info[format].path;
00050   const_string *sfx;
00051   if (!path)
00052     path = kpse_init_format (format);
00053   
00054   /* Set the suffix on the name we'll be searching for.  */
00055   sfx = kpse_format_info[format].suffix;
00056   if (sfx && *sfx) 
00057     xputenv ("KPATHSEA_FORMAT", *sfx);
00058 
00059   /* OK, the limits on this for loop are a little hokey, but it saves
00060      having to repeat the body.  We want to do it once with `must_exist'
00061      false to avoid looking on the disk for cmr10.600pk if
00062      dpi600/cmr10.pk is in ls-R.  (The time spent in the extra variable
00063      expansions and db searches is negligible.)  */
00064   for (must_exist = false; !ret && must_exist <= true; must_exist++)
00065     {
00066       for (spec = bitmap_specs; !ret && *spec; spec++)
00067         {
00068           string name = kpse_var_expand (*spec);
00069           ret = kpse_path_search (path, name, must_exist);
00070           if (name != ret)
00071             free (name);
00072         }
00073     }
00074     
00075   return ret;
00076 }
00077 
00078 /* Look for FONTNAME at resolution DPI in format FORMAT.  Search the
00079    (entire) PK path first, then the GF path, if we're looking for both.
00080    Return any filename found, and (if we succeeded) fill in GLYPH_FILE.  */
00081 
00082 static string
00083 try_size P4C(const_string, fontname,  unsigned, dpi,
00084              kpse_file_format_type, format,
00085              kpse_glyph_file_type *, glyph_file)
00086 {
00087   kpse_file_format_type format_found;
00088   string ret;
00089   boolean try_gf = format == kpse_gf_format || format == kpse_any_glyph_format;
00090   boolean try_pk = format == kpse_pk_format || format == kpse_any_glyph_format;
00091 
00092   xputenv_int ("KPATHSEA_DPI", dpi);
00093   
00094   /* Look for PK first (since it's more likely to be found), then GF.  */
00095   ret = try_pk ? try_format (fontname, dpi, kpse_pk_format) : NULL;
00096 
00097   if (ret != NULL)
00098     format_found = kpse_pk_format;
00099   else
00100     {
00101       if (try_gf)
00102         {
00103           ret = try_format (fontname, dpi, kpse_gf_format);
00104           format_found = kpse_gf_format;
00105         }
00106     }
00107   
00108   if (ret != NULL && glyph_file)
00109     { /* Success.  Fill in the return info.  Discard const.  */
00110       glyph_file->name = (string) fontname;
00111       glyph_file->dpi = dpi;
00112       glyph_file->format = format_found;
00113     }
00114     
00115   return ret;
00116 }
00117 
00118 /* Look for FONTNAME at resolution DPI, then at the resolutions within
00119    KPSE_BITMAP_TOLERANCE of DPI.  */
00120 
00121 static string
00122 try_resolution P4C(const_string, fontname,  unsigned, dpi,
00123                    kpse_file_format_type, format,
00124                    kpse_glyph_file_type *, glyph_file)
00125 {
00126   string ret = try_size (fontname, dpi, format, glyph_file);
00127   
00128   if (!ret)
00129     {
00130       unsigned r;
00131       unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi);
00132       /* Cast to unsigned to shut up stupid compilers. */
00133       unsigned lower_bound = (int) (dpi - tolerance) < 0 ? 0 : (unsigned)(dpi - tolerance);
00134       unsigned upper_bound = (unsigned)(dpi + tolerance);
00135       
00136       /* Prefer scaling up to scaling down, since scaling down can omit
00137          character features (Tom did this in dvips).  */
00138       for (r = lower_bound; !ret && r <= upper_bound; r++)
00139         if (r != dpi)
00140           ret = try_size (fontname, r, format, glyph_file);
00141     }
00142   
00143   return ret;
00144 }
00145 
00146 /* Look up *FONTNAME_PTR in format FORMAT at DPI in the texfonts.map files
00147    that we can find, returning the filename found and GLYPH_FILE.  Also
00148    set *FONTNAME_PTR to the real name corresponding to the alias found
00149    or the first alias, if that is not an alias itself.  (This allows
00150    mktexpk to only deal with real names.)  */
00151 
00152 static string
00153 try_fontmap P4C(string *, fontname_ptr,  unsigned, dpi,
00154                 kpse_file_format_type, format,
00155                 kpse_glyph_file_type *, glyph_file)
00156 {
00157   string *mapped_names;
00158   string fontname = *fontname_ptr;
00159   string ret = NULL;
00160 
00161   mapped_names = kpse_fontmap_lookup (fontname);
00162   if (mapped_names) {
00163     string mapped_name;
00164     string first_name = *mapped_names;
00165     while (!ret && (mapped_name = *mapped_names++)) {
00166       xputenv ("KPATHSEA_NAME", mapped_name);
00167       ret = try_resolution (mapped_name, dpi, format, glyph_file);
00168     }
00169     if (ret) {
00170       /* If some alias succeeeded, return that alias.  */
00171       *fontname_ptr = xstrdup (mapped_name);
00172     /* Return first alias name, unless that itself is an alias,
00173        in which case do nothing.  */
00174     } else if (!kpse_fontmap_lookup (first_name)) {
00175       *fontname_ptr = xstrdup (first_name);
00176     }
00177   } 
00178 
00179   return ret;
00180 }
00181 
00182 /* Look for FONTNAME in `kpse_fallback_resolutions', omitting DPI if we
00183    happen across it.  Return NULL if nothing found.  Pass GLYPH_FILE
00184    along as usual.  Assume `kpse_fallback_resolutions' is sorted.  */
00185 
00186 static string
00187 try_fallback_resolutions P4C(const_string, fontname,  unsigned, dpi,
00188                              kpse_file_format_type, format,
00189                              kpse_glyph_file_type *, glyph_file)
00190 {
00191   unsigned s;
00192   int loc, max_loc;
00193   int lower_loc, upper_loc;
00194   unsigned lower_diff, upper_diff;
00195   unsigned closest_diff = UINT_MAX;
00196   string ret = NULL; /* In case the only fallback resolution is DPI.  */
00197 
00198   /* First find the fallback size closest to DPI, even including DPI.  */
00199   for (s = 0; kpse_fallback_resolutions[s] != 0; s++)
00200     {
00201       unsigned this_diff = abs (kpse_fallback_resolutions[s] - dpi);
00202       if (this_diff < closest_diff)
00203         {
00204           closest_diff = this_diff;
00205           loc = s;
00206         }
00207     }
00208   if (s == 0)
00209     return ret; /* If nothing in list, quit now.  */
00210   
00211   max_loc = s;
00212   lower_loc = loc - 1;
00213   upper_loc = loc + 1;
00214   
00215   for (;;)
00216     {
00217       unsigned fallback = kpse_fallback_resolutions[loc];
00218       /* Don't bother to try DPI itself again.  */
00219       if (fallback != dpi)
00220         {
00221           ret = try_resolution (fontname, fallback, format, glyph_file);
00222           if (ret)
00223             break;
00224         }
00225       
00226       /* That didn't work. How far away are the locs above or below?  */
00227       lower_diff = lower_loc > -1
00228                    ? dpi - kpse_fallback_resolutions[lower_loc] : INT_MAX;
00229       upper_diff = upper_loc < max_loc
00230                    ? kpse_fallback_resolutions[upper_loc] - dpi : INT_MAX;
00231       
00232       /* But if we're at the end in both directions, quit.  */
00233       if (lower_diff == INT_MAX && upper_diff == INT_MAX)
00234         break;
00235       
00236       /* Go in whichever direction is closest.  */
00237       if (lower_diff < upper_diff)
00238         {
00239           loc = lower_loc;
00240           lower_loc--;
00241         }
00242       else
00243         {
00244           loc = upper_loc;
00245           upper_loc++;
00246         }
00247     }
00248 
00249   return ret;
00250 }
00251 
00252 /* See the .h file for description.  This is the entry point.  */
00253 
00254 string
00255 kpse_find_glyph P4C(const_string, passed_fontname,  unsigned, dpi,
00256                     kpse_file_format_type, format,
00257                     kpse_glyph_file_type *, glyph_file)
00258 {
00259   string ret;
00260   kpse_glyph_source_type source;
00261   string fontname = (string) passed_fontname; /* discard const */
00262   
00263   /* Start the search: try the name we're given.  */
00264   source = kpse_glyph_source_normal;
00265   xputenv ("KPATHSEA_NAME", fontname);
00266   ret = try_resolution (fontname, dpi, format, glyph_file);
00267   
00268   /* Try all the various possibilities in order of preference.  */
00269   if (!ret) {
00270     /* Maybe FONTNAME was an alias.  */
00271     source = kpse_glyph_source_alias;
00272     ret = try_fontmap (&fontname, dpi, format, glyph_file);
00273 
00274     /* If not an alias, try creating it on the fly with mktexpk,
00275        unless FONTNAME is absolute or explicitly relative.  */
00276     if (!ret && !kpse_absolute_p (fontname, true)) {
00277       source = kpse_glyph_source_maketex;
00278       /* `try_resolution' leaves the envvar set randomly.  */
00279       xputenv_int ("KPATHSEA_DPI", dpi);
00280       ret = kpse_make_tex (format, fontname);
00281     }
00282 
00283     /* If mktex... succeeded, set return struct.  Doesn't make sense for
00284        `kpse_make_tex' to set it, since it can only succeed or fail,
00285        unlike the other routines.  */
00286     if (ret && glyph_file) {
00287       KPSE_GLYPH_FILE_DPI (*glyph_file) = dpi;
00288       KPSE_GLYPH_FILE_NAME (*glyph_file) = fontname;
00289     }
00290 
00291     /* If mktex... failed, try any fallback resolutions.  */
00292     else {
00293       if (kpse_fallback_resolutions)
00294         ret = try_fallback_resolutions (fontname, dpi, format, glyph_file);
00295 
00296       /* We're down to the font of last resort.  */
00297       if (!ret && kpse_fallback_font) {
00298         const_string name = kpse_fallback_font;
00299         source = kpse_glyph_source_fallback;
00300         xputenv ("KPATHSEA_NAME", name);
00301 
00302         /* As before, first try it at the given size.  */
00303         ret = try_resolution (name, dpi, format, glyph_file);
00304 
00305         /* The fallback font at the fallback resolutions.  */
00306         if (!ret && kpse_fallback_resolutions)
00307           ret = try_fallback_resolutions (name, dpi, format, glyph_file);
00308       }
00309     }
00310   }
00311   
00312   /* If RET is null, then the caller is not supposed to look at GLYPH_FILE,
00313      so it doesn't matter if we assign something incorrect.  */
00314   if (glyph_file)
00315     KPSE_GLYPH_FILE_SOURCE (*glyph_file) = source;
00316 
00317   /* FIXME: fontname may have been allocated, but (worse) it may also
00318      have been assigned to struct that's passed out of this function.
00319   if (fontname != passed_fontname)
00320     free (fontname);
00321   */
00322   
00323   return ret;
00324 }
00325 
00326 /* The tolerances change whether we base things on DPI1 or DPI2.  */
00327 
00328 boolean
00329 kpse_bitmap_tolerance P2C(double, dpi1,  double, dpi2)
00330 {
00331   unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi2);
00332   unsigned lower_bound = (int) (dpi2 - tolerance) < 0 ? 0 : dpi2 - tolerance;
00333   unsigned upper_bound = dpi2 + tolerance;
00334 
00335   return lower_bound <= dpi1 && dpi1 <= upper_bound;
00336 }
00337 
00338 #ifdef TEST
00339 
00340 void
00341 test_find_glyph (const_string fontname, unsigned dpi)
00342 {
00343   string answer;
00344   kpse_glyph_file_type ret;
00345   
00346   printf ("\nSearch for %s@%u:\n\t", fontname, dpi);
00347 
00348   answer = kpse_find_glyph_format (fontname, dpi,
00349                                    kpse_any_glyph_format, &ret);
00350   if (answer)
00351     {
00352       string format = ret.format == kpse_pk_format ? "pk" : "gf";
00353       if (!ret.name)
00354         ret.name = "(nil)";
00355       printf ("%s\n\t(%s@%u, %s)\n", answer, ret.name, ret.dpi, format);
00356     }
00357   else
00358     puts ("(nil)");
00359 }
00360 
00361 
00362 int
00363 main ()
00364 {
00365   test_find_glyph ("/usr/local/lib/tex/fonts/cm/cmr10", 300); /* absolute */
00366   test_find_glyph ("cmr10", 300);     /* normal */
00367   test_find_glyph ("logo10", 300);    /* find gf */
00368   test_find_glyph ("cmr10", 299);     /* find 300 */
00369   test_find_glyph ("circle10", 300);  /* in fontmap */
00370   test_find_glyph ("none", 300);      /* do not find */
00371   kpse_fallback_font = "cmr10";
00372   test_find_glyph ("fallback", 300);  /* find fallback font cmr10 */
00373   kpse_init_fallback_resolutions ("KPATHSEA_TEST_SIZES");
00374   test_find_glyph ("fallbackdpi", 759); /* find fallback font cmr10@300 */
00375   
00376   xputenv ("GFFONTS", ".");
00377   test_find_glyph ("cmr10", 300);     /* different GFFONTS/TEXFONTS */
00378   
00379   return 0;
00380 }
00381 
00382 #endif /* TEST */
00383 
00384 
00385 /*
00386 Local variables:
00387 test-compile-command: "gcc -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"
00388 End:
00389 */