1 /* tex-glyph.c: Search for GF/PK files.
3 Copyright 1997, 98, 99, 2005 Olaf Weber.
4 Copyright 1993, 94, 95, 96 Karl Berry.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <kpathsea/config.h>
24 #include <kpathsea/absolute.h>
25 #include <kpathsea/expand.h>
26 #include <kpathsea/fontmap.h>
27 #include <kpathsea/pathsearch.h>
28 #include <kpathsea/tex-glyph.h>
29 #include <kpathsea/tex-make.h>
30 #include <kpathsea/variable.h>
32 /* Routines are in bottom-up order. */
34 /* Support both cmr10.300pk and dpi300/cmr10.pk. (Use the latter
35 instead of dpi300\cmr10.pk since DOS supports /'s, but Unix doesn't
37 #define UNIX_BITMAP_SPEC "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
38 #define DPI_BITMAP_SPEC "dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
40 /* Look up FONTNAME at resolution DPI in PATH, with filename suffix
41 EXTENSION. Return file found or NULL. */
44 try_format P3C(const_string, fontname, unsigned, dpi,
45 kpse_file_format_type, format)
47 static const_string bitmap_specs[]
48 = { UNIX_BITMAP_SPEC, DPI_BITMAP_SPEC, NULL };
52 const_string path = kpse_format_info[format].path;
55 path = kpse_init_format (format);
57 /* Set the suffix on the name we'll be searching for. */
58 sfx = kpse_format_info[format].suffix;
60 xputenv ("KPATHSEA_FORMAT", *sfx);
62 /* OK, the limits on this for loop are a little hokey, but it saves
63 having to repeat the body. We want to do it once with `must_exist'
64 false to avoid looking on the disk for cmr10.600pk if
65 dpi600/cmr10.pk is in ls-R. (The time spent in the extra variable
66 expansions and db searches is negligible.) */
67 for (must_exist = false; !ret && must_exist <= true; must_exist++)
69 for (spec = bitmap_specs; !ret && *spec; spec++)
71 string name = kpse_var_expand (*spec);
72 ret = kpse_path_search (path, name, must_exist);
81 /* Look for FONTNAME at resolution DPI in format FORMAT. Search the
82 (entire) PK path first, then the GF path, if we're looking for both.
83 Return any filename found, and (if we succeeded) fill in GLYPH_FILE. */
86 try_size P4C(const_string, fontname, unsigned, dpi,
87 kpse_file_format_type, format,
88 kpse_glyph_file_type *, glyph_file)
90 kpse_file_format_type format_found;
92 boolean try_gf = format == kpse_gf_format || format == kpse_any_glyph_format;
93 boolean try_pk = format == kpse_pk_format || format == kpse_any_glyph_format;
95 xputenv_int ("KPATHSEA_DPI", dpi);
97 /* Look for PK first (since it's more likely to be found), then GF. */
98 ret = try_pk ? try_format (fontname, dpi, kpse_pk_format) : NULL;
101 format_found = kpse_pk_format;
106 ret = try_format (fontname, dpi, kpse_gf_format);
107 format_found = kpse_gf_format;
111 if (ret != NULL && glyph_file)
112 { /* Success. Fill in the return info. Discard const. */
113 glyph_file->name = (string) fontname;
114 glyph_file->dpi = dpi;
115 glyph_file->format = format_found;
121 /* Look for FONTNAME at resolution DPI, then at the resolutions within
122 KPSE_BITMAP_TOLERANCE of DPI. */
125 try_resolution P4C(const_string, fontname, unsigned, dpi,
126 kpse_file_format_type, format,
127 kpse_glyph_file_type *, glyph_file)
129 string ret = try_size (fontname, dpi, format, glyph_file);
134 unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi);
135 /* Cast to unsigned to shut up stupid compilers. */
136 unsigned lower_bound = (int) (dpi - tolerance) < 0 ? 0 : (unsigned)(dpi - tolerance);
137 unsigned upper_bound = (unsigned)(dpi + tolerance);
139 /* Prefer scaling up to scaling down, since scaling down can omit
140 character features (Tom did this in dvips). */
141 for (r = lower_bound; !ret && r <= upper_bound; r++)
143 ret = try_size (fontname, r, format, glyph_file);
149 /* Look up *FONTNAME_PTR in format FORMAT at DPI in the texfonts.map files
150 that we can find, returning the filename found and GLYPH_FILE. Also
151 set *FONTNAME_PTR to the real name corresponding to the alias found
152 or the first alias, if that is not an alias itself. (This allows
153 mktexpk to only deal with real names.) */
156 try_fontmap P4C(string *, fontname_ptr, unsigned, dpi,
157 kpse_file_format_type, format,
158 kpse_glyph_file_type *, glyph_file)
160 string *mapped_names;
161 string fontname = *fontname_ptr;
164 mapped_names = kpse_fontmap_lookup (fontname);
167 string first_name = *mapped_names;
168 while (!ret && (mapped_name = *mapped_names++)) {
169 xputenv ("KPATHSEA_NAME", mapped_name);
170 ret = try_resolution (mapped_name, dpi, format, glyph_file);
173 /* If some alias succeeeded, return that alias. */
174 *fontname_ptr = xstrdup (mapped_name);
175 /* Return first alias name, unless that itself is an alias,
176 in which case do nothing. */
177 } else if (!kpse_fontmap_lookup (first_name)) {
178 *fontname_ptr = xstrdup (first_name);
185 /* Look for FONTNAME in `kpse_fallback_resolutions', omitting DPI if we
186 happen across it. Return NULL if nothing found. Pass GLYPH_FILE
187 along as usual. Assume `kpse_fallback_resolutions' is sorted. */
190 try_fallback_resolutions P4C(const_string, fontname, unsigned, dpi,
191 kpse_file_format_type, format,
192 kpse_glyph_file_type *, glyph_file)
196 int lower_loc, upper_loc;
197 unsigned lower_diff, upper_diff;
198 unsigned closest_diff = UINT_MAX;
199 string ret = NULL; /* In case the only fallback resolution is DPI. */
201 /* First find the fallback size closest to DPI, even including DPI. */
202 for (s = 0; kpse_fallback_resolutions[s] != 0; s++)
204 unsigned this_diff = abs (kpse_fallback_resolutions[s] - dpi);
205 if (this_diff < closest_diff)
207 closest_diff = this_diff;
212 return ret; /* If nothing in list, quit now. */
220 unsigned fallback = kpse_fallback_resolutions[loc];
221 /* Don't bother to try DPI itself again. */
224 ret = try_resolution (fontname, fallback, format, glyph_file);
229 /* That didn't work. How far away are the locs above or below? */
230 lower_diff = lower_loc > -1
231 ? dpi - kpse_fallback_resolutions[lower_loc] : INT_MAX;
232 upper_diff = upper_loc < max_loc
233 ? kpse_fallback_resolutions[upper_loc] - dpi : INT_MAX;
235 /* But if we're at the end in both directions, quit. */
236 if (lower_diff == INT_MAX && upper_diff == INT_MAX)
239 /* Go in whichever direction is closest. */
240 if (lower_diff < upper_diff)
255 /* See the .h file for description. This is the entry point. */
258 kpse_find_glyph P4C(const_string, passed_fontname, unsigned, dpi,
259 kpse_file_format_type, format,
260 kpse_glyph_file_type *, glyph_file)
263 kpse_glyph_source_type source;
264 string fontname = (string) passed_fontname; /* discard const */
266 /* Start the search: try the name we're given. */
267 source = kpse_glyph_source_normal;
268 xputenv ("KPATHSEA_NAME", fontname);
269 ret = try_resolution (fontname, dpi, format, glyph_file);
271 /* Try all the various possibilities in order of preference. */
273 /* Maybe FONTNAME was an alias. */
274 source = kpse_glyph_source_alias;
275 ret = try_fontmap (&fontname, dpi, format, glyph_file);
277 /* If not an alias, try creating it on the fly with mktexpk,
278 unless FONTNAME is absolute or explicitly relative. */
279 if (!ret && !kpse_absolute_p (fontname, true)) {
280 source = kpse_glyph_source_maketex;
281 /* `try_resolution' leaves the envvar set randomly. */
282 xputenv_int ("KPATHSEA_DPI", dpi);
283 ret = kpse_make_tex (format, fontname);
286 /* If mktex... succeeded, set return struct. Doesn't make sense for
287 `kpse_make_tex' to set it, since it can only succeed or fail,
288 unlike the other routines. */
289 if (ret && glyph_file) {
290 KPSE_GLYPH_FILE_DPI (*glyph_file) = dpi;
291 KPSE_GLYPH_FILE_NAME (*glyph_file) = fontname;
294 /* If mktex... failed, try any fallback resolutions. */
296 if (kpse_fallback_resolutions)
297 ret = try_fallback_resolutions (fontname, dpi, format, glyph_file);
299 /* We're down to the font of last resort. */
300 if (!ret && kpse_fallback_font) {
301 const_string name = kpse_fallback_font;
302 source = kpse_glyph_source_fallback;
303 xputenv ("KPATHSEA_NAME", name);
305 /* As before, first try it at the given size. */
306 ret = try_resolution (name, dpi, format, glyph_file);
308 /* The fallback font at the fallback resolutions. */
309 if (!ret && kpse_fallback_resolutions)
310 ret = try_fallback_resolutions (name, dpi, format, glyph_file);
315 /* If RET is null, then the caller is not supposed to look at GLYPH_FILE,
316 so it doesn't matter if we assign something incorrect. */
318 KPSE_GLYPH_FILE_SOURCE (*glyph_file) = source;
320 /* FIXME: fontname may have been allocated, but (worse) it may also
321 have been assigned to struct that's passed out of this function.
322 if (fontname != passed_fontname)
329 /* The tolerances change whether we base things on DPI1 or DPI2. */
332 kpse_bitmap_tolerance P2C(double, dpi1, double, dpi2)
334 unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi2);
335 unsigned lower_bound = (int) (dpi2 - tolerance) < 0 ? 0 : dpi2 - tolerance;
336 unsigned upper_bound = dpi2 + tolerance;
338 return lower_bound <= dpi1 && dpi1 <= upper_bound;
344 test_find_glyph (const_string fontname, unsigned dpi)
347 kpse_glyph_file_type ret;
349 printf ("\nSearch for %s@%u:\n\t", fontname, dpi);
351 answer = kpse_find_glyph_format (fontname, dpi,
352 kpse_any_glyph_format, &ret);
355 string format = ret.format == kpse_pk_format ? "pk" : "gf";
358 printf ("%s\n\t(%s@%u, %s)\n", answer, ret.name, ret.dpi, format);
368 test_find_glyph ("/usr/local/lib/tex/fonts/cm/cmr10", 300); /* absolute */
369 test_find_glyph ("cmr10", 300); /* normal */
370 test_find_glyph ("logo10", 300); /* find gf */
371 test_find_glyph ("cmr10", 299); /* find 300 */
372 test_find_glyph ("circle10", 300); /* in fontmap */
373 test_find_glyph ("none", 300); /* do not find */
374 kpse_fallback_font = "cmr10";
375 test_find_glyph ("fallback", 300); /* find fallback font cmr10 */
376 kpse_init_fallback_resolutions ("KPATHSEA_TEST_SIZES");
377 test_find_glyph ("fallbackdpi", 759); /* find fallback font cmr10@300 */
379 xputenv ("GFFONTS", ".");
380 test_find_glyph ("cmr10", 300); /* different GFFONTS/TEXFONTS */
390 test-compile-command: "gcc -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"