comparison kpathsea/tex-glyph.c @ 1268:76a0c05089d4

[project @ 1995-04-20 19:15:51 by jwe] Initial revision
author jwe
date Thu, 20 Apr 1995 19:15:51 +0000
parents
children 611d403c7f3d
comparison
equal deleted inserted replaced
1267:69501f98669d 1268:76a0c05089d4
1 /* tex-glyph.c: Search for GF/PK files.
2
3 Copyright (C) 1993, 94 Karl Berry.
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 <kpathsea/config.h>
20
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>
28
29 /* Routines are in bottom-up order. */
30
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
33 support \'s. */
34 #define UNIX_BITMAP_SPEC "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
35 #define DPI_BITMAP_SPEC "dpi$KPATHSEA_DPI/$KPATHSEA_NAME.$KPATHSEA_FORMAT"
36
37 /* Look up FONT_NAME at resolution DPI in PATH, with filename suffix
38 EXTENSION. Return file found or NULL. */
39
40 static string
41 try_format P3C(const_string, font_name, unsigned, dpi,
42 kpse_file_format_type, format)
43 {
44 static const_string bitmap_specs[]
45 = { UNIX_BITMAP_SPEC, DPI_BITMAP_SPEC, NULL };
46 const_string *spec;
47 boolean must_exist;
48 string ret = NULL;
49 const_string path = kpse_format_info[format].path;
50 if (!path)
51 path = kpse_init_format (format);
52
53 /* Set the suffix on the name we'll be searching for. */
54 xputenv ("KPATHSEA_FORMAT", kpse_format_info[format].suffix);
55
56 /* OK, the limits on this for loop are a little hokey, but it saves
57 having to repeat the body. We want to do it once with `must_exist'
58 false to avoid looking on the disk for cmr10.600pk if
59 dpi600/cmr10.pk is in ls-R. (The time spent in the extra variable
60 expansions and db searches is negligible.) */
61 for (must_exist = false; !ret && must_exist <= true; must_exist++)
62 {
63 for (spec = bitmap_specs; !ret && *spec; spec++)
64 {
65 string name = kpse_var_expand (*spec);
66 ret = kpse_path_search (path, name, must_exist);
67 if (name != ret)
68 free (name);
69 }
70 }
71
72 return ret;
73 }
74
75 /* Look for FONT_NAME at resolution DPI in format FORMAT. Search the
76 (entire) PK path first, then the GF path, if we're looking for both.
77 Return any filename found, and (if we succeeded) fill in GLYPH_FILE. */
78
79 static string
80 try_size P4C(const_string, font_name, unsigned, dpi,
81 kpse_file_format_type, format,
82 kpse_glyph_file_type *, glyph_file)
83 {
84 kpse_file_format_type format_found;
85 string ret;
86 boolean try_gf = format == kpse_gf_format || format == kpse_any_glyph_format;
87 boolean try_pk = format == kpse_pk_format || format == kpse_any_glyph_format;
88
89 xputenv_int ("KPATHSEA_DPI", dpi);
90
91 /* Look for PK first (since it's more likely to be found), then GF. */
92 ret = try_pk ? try_format (font_name, dpi, kpse_pk_format) : NULL;
93
94 if (ret != NULL)
95 format_found = kpse_pk_format;
96 else
97 {
98 if (try_gf)
99 {
100 ret = try_format (font_name, dpi, kpse_gf_format);
101 format_found = kpse_gf_format;
102 }
103 }
104
105 if (ret != NULL && glyph_file)
106 { /* Success. Fill in the return info. Discard const. */
107 glyph_file->name = (string) font_name;
108 glyph_file->dpi = dpi;
109 glyph_file->format = format_found;
110 }
111
112 return ret;
113 }
114
115 /* Look for FONT_NAME at resolution DPI, then at the resolutions within
116 KPSE_BITMAP_TOLERANCE of DPI. */
117
118 static string
119 try_resolution P4C(const_string, font_name, unsigned, dpi,
120 kpse_file_format_type, format,
121 kpse_glyph_file_type *, glyph_file)
122 {
123 string ret = try_size (font_name, dpi, format, glyph_file);
124
125 if (!ret)
126 {
127 unsigned r;
128 unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi);
129 unsigned lower_bound = (int) (dpi - tolerance) < 0 ? 0 : dpi - tolerance;
130 unsigned upper_bound = dpi + tolerance;
131
132 /* Prefer scaling up to scaling down, since scaling down can omit
133 character features (Tom did this in dvips). */
134 for (r = lower_bound; !ret && r <= upper_bound; r++)
135 if (r != dpi)
136 ret = try_size (font_name, r, format, glyph_file);
137 }
138
139 return ret;
140 }
141
142 /* Look up FONT_NAME in format FORMAT at DPI in the texfonts.map files
143 that we can find, returning the filename found and GLYPH_FILE. */
144
145 static string
146 try_fontmap P4C(const_string, font_name, unsigned, dpi,
147 kpse_file_format_type, format,
148 kpse_glyph_file_type *, glyph_file)
149 {
150 static hash_table_type fontmap;
151 string *mapped_names;
152 string ret = NULL;
153
154 if (fontmap.size == 0)
155 { /* If we wanted to complicate our lives, we could handle separate
156 maps for GF and PK ones. I don't see that this has any
157 practical utility, though, because if someone wants an alias,
158 most likely the alias should apply to non-glyphs as well as
159 glyphs (let alone to only GF format or PK format). */
160 const_string map_path = kpse_init_format (kpse_any_glyph_format);
161 fontmap = map_create (map_path);
162 }
163
164 mapped_names = map_lookup (fontmap, font_name);
165 if (mapped_names)
166 {
167 string mapped_name;
168 while ((mapped_name = *mapped_names++) && !ret)
169 {
170 xputenv ("KPATHSEA_NAME", mapped_name);
171 ret = try_resolution (mapped_name, dpi, format, glyph_file);
172 }
173 }
174
175 return ret;
176 }
177
178 /* Look for FONT_NAME in `kpse_fallback_resolutions', omitting DPI if we
179 happen across it. Return NULL if nothing found. Pass GLYPH_FILE
180 along as usual. Assume `kpse_fallback_resolutions' is sorted. */
181
182 static string
183 try_fallback_resolutions P4C(const_string, font_name, unsigned, dpi,
184 kpse_file_format_type, format,
185 kpse_glyph_file_type *, glyph_file)
186 {
187 unsigned s;
188 int loc, max_loc;
189 int lower_loc, upper_loc;
190 unsigned lower_diff, upper_diff;
191 unsigned closest_diff = UINT_MAX;
192 string ret = NULL; /* In case the only fallback resolution is DPI. */
193
194 /* First find the fallback size closest to DPI. */
195 for (s = 0; kpse_fallback_resolutions[s] != 0; s++)
196 {
197 unsigned this_diff = abs (kpse_fallback_resolutions[s] - dpi);
198 if (this_diff < closest_diff)
199 {
200 closest_diff = this_diff;
201 loc = s;
202 }
203 }
204 if (s == 0)
205 return ret; /* If nothing in list, quit now. */
206
207 max_loc = s;
208 lower_loc = loc - 1;
209 upper_loc = loc + 1;
210
211 for (;;)
212 {
213 unsigned fallback = kpse_fallback_resolutions[loc];
214 /* Don't bother to try DPI itself again. */
215 if (fallback != dpi)
216 {
217 ret = try_resolution (font_name, fallback, format, glyph_file);
218 if (ret)
219 break;
220 }
221
222 /* That didn't work. How far away are the locs above or below? */
223 lower_diff = lower_loc > -1
224 ? dpi - kpse_fallback_resolutions[lower_loc] : INT_MAX;
225 upper_diff = upper_loc < max_loc
226 ? kpse_fallback_resolutions[upper_loc] - dpi : INT_MAX;
227
228 /* But if we're at the end in both directions, quit. */
229 if (lower_diff == INT_MAX && upper_diff == INT_MAX)
230 break;
231
232 /* Go in whichever direction is closest. */
233 if (lower_diff < upper_diff)
234 {
235 loc = lower_loc;
236 lower_loc--;
237 }
238 else
239 {
240 loc = upper_loc;
241 upper_loc++;
242 }
243 }
244
245 return ret;
246 }
247
248 /* See the .h file for description. This is the entry point. */
249
250 string
251 kpse_find_glyph P4C(const_string, font_name, unsigned, dpi,
252 kpse_file_format_type, format,
253 kpse_glyph_file_type *, glyph_file)
254 {
255 string ret;
256 kpse_glyph_source_type source;
257
258 /* Start the search: try the name we're given. */
259 source = kpse_glyph_source_normal;
260 xputenv ("KPATHSEA_NAME", font_name);
261 ret = try_resolution (font_name, dpi, format, glyph_file);
262
263 /* Try all the various possibilities in order of preference. */
264 if (!ret)
265 {
266 /* Maybe FONT_NAME was an alias. */
267 source = kpse_glyph_source_alias;
268 ret = try_fontmap (font_name, dpi, format, glyph_file);
269
270 /* If not an alias, try creating it on the fly with MakeTeXPK,
271 unless FONT_NAME is absolute or explicitly relative. */
272 if (!ret && !kpse_absolute_p (font_name, true))
273 {
274 source = kpse_glyph_source_maketex;
275 /* `try_resolution' leaves the envvar set randomly. */
276 xputenv_int ("KPATHSEA_DPI", dpi);
277 ret = kpse_make_tex (format, font_name);
278 }
279
280 /* If MakeTeX... succeeded, set return struct. Doesn't make sense for
281 `kpse_make_tex' to set it, since it can only succeed or fail,
282 unlike the other routines. */
283 if (ret)
284 {
285 KPSE_GLYPH_FILE_DPI (*glyph_file) = dpi;
286 /* Have to discard const here. */
287 KPSE_GLYPH_FILE_NAME (*glyph_file) = (string) font_name;
288 }
289
290 /* If MakeTeX... failed, try any fallback resolutions. */
291 else
292 {
293 if (kpse_fallback_resolutions)
294 ret = try_fallback_resolutions(font_name, dpi, format, glyph_file);
295
296 /* We're down to the font of last resort. */
297 if (!ret && kpse_fallback_font)
298 {
299 const_string name = kpse_fallback_font;
300 source = kpse_glyph_source_fallback;
301 xputenv ("KPATHSEA_NAME", name);
302
303 /* As before, first try it at the given size. */
304 ret = try_resolution (name, dpi, format, glyph_file);
305
306 /* The fallback font at the fallback resolutions. */
307 if (!ret && kpse_fallback_resolutions)
308 ret = try_fallback_resolutions (name, dpi, format, glyph_file);
309 }
310 }
311 }
312
313 /* If RET is null, then the caller is not supposed to look at GLYPH_FILE,
314 so it doesn't matter if we assign something incorrect. */
315 KPSE_GLYPH_FILE_SOURCE (*glyph_file) = source;
316
317 return ret;
318 }
319
320 /* The tolerances change whether we base things on DPI1 or DPI2. */
321
322 boolean
323 kpse_bitmap_tolerance P2C(double, dpi1, double, dpi2)
324 {
325 unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi2);
326 unsigned lower_bound = (int) (dpi2 - tolerance) < 0 ? 0 : dpi2 - tolerance;
327 unsigned upper_bound = dpi2 + tolerance;
328
329 return lower_bound <= dpi1 && dpi1 <= upper_bound;
330 }
331
332 #ifdef TEST
333
334 void
335 test_find_glyph (const_string font_name, unsigned dpi)
336 {
337 string answer;
338 kpse_glyph_file_type ret;
339
340 printf ("\nSearch for %s@%u:\n\t", font_name, dpi);
341
342 answer = kpse_find_glyph_format (font_name, dpi,
343 kpse_any_glyph_format, &ret);
344 if (answer)
345 {
346 string format = ret.format == kpse_pk_format ? "pk" : "gf";
347 if (!ret.name)
348 ret.name = "(null)";
349 printf ("%s\n\t(%s@%u, %s)\n", answer, ret.name, ret.dpi, format);
350 }
351 else
352 puts ("(null)");
353 }
354
355
356 int
357 main ()
358 {
359 test_find_glyph ("/usr/local/lib/tex/fonts/cm/cmr10", 300); /* absolute */
360 test_find_glyph ("cmr10", 300); /* normal */
361 test_find_glyph ("logo10", 300); /* find gf */
362 test_find_glyph ("cmr10", 299); /* find 300 */
363 test_find_glyph ("circle10", 300); /* in fontmap */
364 test_find_glyph ("none", 300); /* do not find */
365 kpse_fallback_font = "cmr10";
366 test_find_glyph ("fallback", 300); /* find fallback font cmr10 */
367 kpse_init_fallback_resolutions ("KPATHSEA_TEST_SIZES");
368 test_find_glyph ("fallbackdpi", 759); /* find fallback font cmr10@300 */
369
370 xputenv ("GFFONTS", ".");
371 test_find_glyph ("cmr10", 300); /* different GFFONTS/TEXFONTS */
372
373 return 0;
374 }
375
376 #endif /* TEST */
377
378
379 /*
380 Local variables:
381 test-compile-command: "gcc -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"
382 End:
383 */