1 /* tex-glyph.c: search for GF/PK files.
3 Copyright 1993, 1994, 1995, 1996, 2008, 2009, 2011 Karl Berry.
4 Copyright 1997, 1998, 1999, 2005 Olaf Weber.
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 License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
21 #include <kpathsea/absolute.h>
22 #include <kpathsea/expand.h>
23 #include <kpathsea/fontmap.h>
24 #include <kpathsea/pathsearch.h>
25 #include <kpathsea/tex-glyph.h>
26 #include <kpathsea/tex-make.h>
27 #include <kpathsea/variable.h>
29 /* Routines are in bottom-up order. */
31 /* Support both cmr10.300pk and dpi300/cmr10.pk. (Use the latter
32 instead of dpi300\cmr10.pk since DOS supports /'s, but Unix doesn't
34 #define UNIX_BITMAP_SPEC "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
35 #define DPI_BITMAP_SPEC "dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
37 #define DOS_BITMAP_SPEC "$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
40 /* Look up font $KPATHSEA_NAME at resolution $KPATHSEA_DPI in PATH,
41 with filename suffix EXTENSION. Return file found or NULL. */
44 try_format (kpathsea kpse
, kpse_file_format_type format
)
46 static const_string bitmap_specs
[]
47 = { UNIX_BITMAP_SPEC
, DPI_BITMAP_SPEC
,
56 const_string path
= kpse
->format_info
[format
].path
;
58 path
= kpathsea_init_format (kpse
, format
);
60 /* Set the suffix on the name we'll be searching for. */
61 sfx
= kpse
->format_info
[format
].suffix
;
63 kpathsea_xputenv (kpse
, "KPATHSEA_FORMAT", *sfx
);
65 /* OK, the limits on this for loop are a little hokey, but it saves
66 having to repeat the body. We want to do it once with `must_exist'
67 false to avoid looking on the disk for cmr10.600pk if
68 dpi600/cmr10.pk is in ls-R. (The time spent in the extra variable
69 expansions and db searches is negligible.) */
70 for (must_exist
= false; !ret
&& must_exist
<= true; must_exist
++)
72 for (spec
= bitmap_specs
; !ret
&& *spec
; spec
++)
74 string name
= kpathsea_var_expand (kpse
, *spec
);
75 ret
= kpathsea_path_search (kpse
, path
, name
, must_exist
);
84 /* Look for FONTNAME at resolution DPI in format FORMAT. Search the
85 (entire) PK path first, then the GF path, if we're looking for both.
86 Return any filename found, and (if we succeeded) fill in GLYPH_FILE. */
89 try_size (kpathsea kpse
, const_string fontname
, unsigned dpi
,
90 kpse_file_format_type format
,
91 kpse_glyph_file_type
*glyph_file
)
93 kpse_file_format_type format_found
;
95 boolean try_gf
= format
== kpse_gf_format
|| format
== kpse_any_glyph_format
;
96 boolean try_pk
= format
== kpse_pk_format
|| format
== kpse_any_glyph_format
;
98 kpathsea_xputenv_int (kpse
, "KPATHSEA_DPI", dpi
);
100 /* Look for PK first (since it's more likely to be found), then GF. */
101 ret
= try_pk
? try_format (kpse
, kpse_pk_format
) : NULL
;
102 format_found
= kpse_pk_format
;
104 if (ret
== NULL
&& try_gf
)
106 ret
= try_format (kpse
, kpse_gf_format
);
107 format_found
= kpse_gf_format
;
110 if (ret
!= NULL
&& glyph_file
)
111 { /* Success. Fill in the return info. */
112 glyph_file
->name
= fontname
;
113 glyph_file
->dpi
= dpi
;
114 glyph_file
->format
= format_found
;
120 /* Look for FONTNAME at resolution DPI, then at the resolutions within
121 KPSE_BITMAP_TOLERANCE of DPI. */
124 try_resolution (kpathsea kpse
, const_string fontname
, unsigned dpi
,
125 kpse_file_format_type format
,
126 kpse_glyph_file_type
*glyph_file
)
128 string ret
= try_size (kpse
, fontname
, dpi
, format
, glyph_file
);
132 unsigned tolerance
= KPSE_BITMAP_TOLERANCE (dpi
);
133 /* Cast to unsigned to shut up stupid compilers. */
134 unsigned lower_bound
= (int) (dpi
- tolerance
) < 0
135 ? 0 : (unsigned)(dpi
- tolerance
);
136 unsigned upper_bound
= (unsigned)(dpi
+ tolerance
);
138 /* Prefer scaling up to scaling down, since scaling down can omit
139 character features (Tom did this in dvips). */
140 for (r
= lower_bound
; !ret
&& r
<= upper_bound
; r
++)
142 ret
= try_size (kpse
, fontname
, r
, format
, glyph_file
);
148 /* Look up *FONTNAME_PTR in format FORMAT at DPI in the texfonts.map files
149 that we can find, returning the filename found and GLYPH_FILE. Also
150 set *FONTNAME_PTR to the real name corresponding to the alias found
151 or the first alias, if that is not an alias itself. (This allows
152 mktexpk to only deal with real names.) */
155 try_fontmap (kpathsea kpse
, const_string
*fontname_ptr
, unsigned dpi
,
156 kpse_file_format_type format
,
157 kpse_glyph_file_type
*glyph_file
)
159 const_string
*mapped_names
;
160 const_string fontname
= *fontname_ptr
;
163 mapped_names
= kpathsea_fontmap_lookup (kpse
, fontname
);
165 const_string mapped_name
;
166 const_string first_name
= *mapped_names
;
167 while (!ret
&& (mapped_name
= *mapped_names
++)) {
168 kpathsea_xputenv (kpse
, "KPATHSEA_NAME", mapped_name
);
169 ret
= try_resolution (kpse
, mapped_name
, dpi
, format
, glyph_file
);
172 /* If some alias succeeeded, return that alias. */
173 *fontname_ptr
= xstrdup (mapped_name
);
174 /* Return first alias name, unless that itself is an alias,
175 in which case do nothing. */
176 } else if (!kpathsea_fontmap_lookup (kpse
, first_name
)) {
177 *fontname_ptr
= xstrdup (first_name
);
184 /* Look for FONTNAME in `kpse_fallback_resolutions', omitting DPI if we
185 happen across it. Return NULL if nothing found. Pass GLYPH_FILE
186 along as usual. Assume `kpse_fallback_resolutions' is sorted. */
189 try_fallback_resolutions (kpathsea kpse
,
190 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 (kpse
, 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 kpathsea_find_glyph (kpathsea kpse
,
259 const_string passed_fontname
, unsigned dpi
,
260 kpse_file_format_type format
,
261 kpse_glyph_file_type
*glyph_file
)
264 kpse_glyph_source_type source
;
265 const_string fontname
= passed_fontname
;
267 /* Start the search: try the name we're given. */
268 source
= kpse_glyph_source_normal
;
269 kpathsea_xputenv (kpse
, "KPATHSEA_NAME", fontname
);
270 ret
= try_resolution (kpse
, fontname
, dpi
, format
, glyph_file
);
272 /* Try all the various possibilities in order of preference. */
274 /* Maybe FONTNAME was an alias. */
275 source
= kpse_glyph_source_alias
;
276 ret
= try_fontmap (kpse
, &fontname
, dpi
, format
, glyph_file
);
278 /* If not an alias, try creating it on the fly with mktexpk,
279 unless FONTNAME is absolute or explicitly relative. */
280 if (!ret
&& !kpathsea_absolute_p (kpse
, fontname
, true)) {
281 source
= kpse_glyph_source_maketex
;
282 /* `try_resolution' leaves the envvar set randomly. */
283 kpathsea_xputenv_int (kpse
, "KPATHSEA_DPI", dpi
);
284 ret
= kpathsea_make_tex (kpse
, format
, fontname
);
287 /* If mktex... succeeded, set return struct. Doesn't make sense for
288 `kpse_make_tex' to set it, since it can only succeed or fail,
289 unlike the other routines. */
290 if (ret
&& glyph_file
) {
291 KPSE_GLYPH_FILE_DPI (*glyph_file
) = dpi
;
292 KPSE_GLYPH_FILE_NAME (*glyph_file
) = fontname
;
295 /* If mktex... failed, try any fallback resolutions. */
297 if (kpse
->fallback_resolutions
)
298 ret
= try_fallback_resolutions (kpse
, fontname
, dpi
, format
, glyph_file
);
300 /* We're down to the font of last resort. */
301 if (!ret
&& kpse
->fallback_font
) {
302 const_string name
= kpse
->fallback_font
;
303 source
= kpse_glyph_source_fallback
;
304 kpathsea_xputenv (kpse
, "KPATHSEA_NAME", name
);
306 /* As before, first try it at the given size. */
307 ret
= try_resolution (kpse
, name
, dpi
, format
, glyph_file
);
309 /* The fallback font at the fallback resolutions. */
310 if (!ret
&& kpse
->fallback_resolutions
)
311 ret
= try_fallback_resolutions (kpse
, name
, dpi
, format
, glyph_file
);
316 /* If RET is null, then the caller is not supposed to look at GLYPH_FILE,
317 so it doesn't matter if we assign something incorrect. */
319 KPSE_GLYPH_FILE_SOURCE (*glyph_file
) = source
;
321 /* FIXME: fontname may have been allocated, but (worse) it may also
322 have been assigned to struct that's passed out of this function.
323 if (fontname != passed_fontname)
330 #if defined (KPSE_COMPAT_API)
332 kpse_find_glyph (const_string passed_fontname
, unsigned dpi
,
333 kpse_file_format_type format
,
334 kpse_glyph_file_type
*glyph_file
)
336 return kpathsea_find_glyph (kpse_def
, passed_fontname
, dpi
, format
,
342 /* The tolerances change whether we base things on DPI1 or DPI2. */
345 kpathsea_bitmap_tolerance (kpathsea kpse
, double dpi1
, double dpi2
)
347 unsigned tolerance
= KPSE_BITMAP_TOLERANCE (dpi2
);
348 unsigned lower_bound
= (int) (dpi2
- tolerance
) < 0 ? 0 : dpi2
- tolerance
;
349 unsigned upper_bound
= dpi2
+ tolerance
;
350 (void)kpse
; /* currenty not used */
352 return lower_bound
<= dpi1
&& dpi1
<= upper_bound
;
355 #if defined (KPSE_COMPAT_API)
357 kpse_bitmap_tolerance (double dpi1
, double dpi2
)
359 return kpathsea_bitmap_tolerance (kpse_def
, dpi1
, dpi2
);
367 test_find_glyph (kpathsea kpse
, const_string fontname
, unsigned dpi
)
370 kpse_glyph_file_type ret
;
372 printf ("\nSearch for %s@%u:\n\t", fontname
, dpi
);
374 answer
= kpathsea_find_glyph (kpse
, fontname
, dpi
,
375 kpse_any_glyph_format
, &ret
);
378 string format
= ret
.format
== kpse_pk_format
? "pk" : "gf";
381 printf ("%s\n\t(%s@%u, %s)\n", answer
, ret
.name
, ret
.dpi
, format
);
389 main (int argc
, char **argv
)
391 kpathsea kpse
= xcalloc(1,sizeof(kpathsea_instance
));
392 kpathsea_set_program_name(kpse
, argv
[0], NULL
);
393 test_find_glyph (kpse
, "/usr/local/lib/tex/fonts/cm/cmr10", 300); /* abs. */
394 test_find_glyph (kpse
, "cmr10", 300); /* normal */
395 test_find_glyph (kpse
, "logo10", 300); /* find gf */
396 test_find_glyph (kpse
, "cmr10", 299); /* find 300 */
397 test_find_glyph (kpse
, "circle10", 300); /* in fontmap */
398 test_find_glyph (kpse
, "none", 300); /* do not find */
399 kpse
->kpse_fallback_font
= "cmr10";
400 test_find_glyph (kpse
, "fallback", 300); /* find fallback font cmr10 */
401 kpathsea_init_fallback_resolutions (kpse
, "KPATHSEA_TEST_SIZES");
402 test_find_glyph (kpse
, "fallbackdpi", 759); /* find fallback cmr10@300 */
404 kpathsea_xputenv (kpse
,"GFFONTS", ".");
405 test_find_glyph (kpse
, "cmr10", 300); /* different GFFONTS/TEXFONTS */
415 standalone-compile-command: "gcc -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"