1 /*
2  * font.c
3  *
4  * map dvi fonts to X fonts
5  */
6 
7 #include <X11/Xos.h>
8 #include <X11/IntrinsicP.h>
9 #include <X11/StringDefs.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include "DviP.h"
14 #include "XFontName.h"
15 
16 static void DisposeFontSizes(DviWidget, DviFontSizeList *);
17 void DestroyFontMap(DviFontMap *);
18 
19 static char *
savestr(const char * s)20 savestr (const char *s)
21 {
22 	char	*n;
23 
24 	if (!s)
25 		return 0;
26 	n = XtMalloc (strlen (s) + 1);
27 	if (n)
28 		strcpy (n, s);
29 	return n;
30 }
31 
32 static DviFontList *
LookupFontByPosition(DviWidget dw,int position)33 LookupFontByPosition (DviWidget dw, int position)
34 {
35 	DviFontList	*f;
36 
37 	for (f = dw->dvi.fonts; f; f = f->next)
38 		if (f->dvi_number == position)
39 			break;
40 	return f;
41 }
42 
43 int
MaxFontPosition(DviWidget dw)44 MaxFontPosition (DviWidget dw)
45 {
46 	DviFontList	*f;
47 	int n = -1;
48 
49 	for (f = dw->dvi.fonts; f; f = f->next)
50 		if (f->dvi_number > n)
51 			n = f->dvi_number;
52 	return n;
53 }
54 
55 static DviFontSizeList *
LookupFontSizeBySize(DviWidget dw,DviFontList * f,int size)56 LookupFontSizeBySize (DviWidget dw, DviFontList *f, int size)
57 {
58 	DviFontSizeList	*fs, *best = 0, *smallest = 0;
59 	int		bestsize = 0;
60 	XFontName	fontName;
61 	unsigned int    fontNameAttributes;
62 	char	    	fontNameString[2048];
63 	int		decipointsize;
64 
65 	if (f->scalable) {
66 		decipointsize = (10*size)/dw->dvi.sizescale;
67 		for (best = f->sizes; best; best = best->next)
68 			if (best->size == decipointsize)
69 				return best;
70 		best = (DviFontSizeList *) XtMalloc(sizeof *best);
71 		best->next = f->sizes;
72 		best->size = decipointsize;
73 		f->sizes = best;
74 		XParseFontName (f->x_name, &fontName, &fontNameAttributes);
75 		fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
76 		fontNameAttributes |= FontNameResolutionX;
77 		fontNameAttributes |= FontNameResolutionY;
78 		fontNameAttributes |= FontNamePointSize;
79 		fontName.ResolutionX = dw->dvi.display_resolution;
80 		fontName.ResolutionY = dw->dvi.display_resolution;
81 		fontName.PointSize = decipointsize;
82 		XFormatFontName (&fontName, fontNameAttributes, fontNameString);
83 		best->x_name = savestr (fontNameString);
84 		best->doesnt_exist = 0;
85 		best->font = 0;
86 		return best;
87 	}
88 	for (fs = f->sizes; fs; fs=fs->next) {
89 		if (dw->dvi.sizescale*fs->size <= 10*size
90 		    && fs->size >= bestsize) {
91 			best = fs;
92 			bestsize = fs->size;
93 		}
94 		if (smallest == 0 || fs->size < smallest->size)
95 			smallest = fs;
96 	}
97 	return best ? best : smallest;
98 }
99 
100 static char *
SkipFontNameElement(char * n)101 SkipFontNameElement (char *n)
102 {
103 	while (*n != '-')
104 		if (!*++n)
105 			return 0;
106 	return n+1;
107 }
108 
109 # define SizePosition		8
110 # define EncodingPosition	13
111 
112 static int
ConvertFontNameToSize(char * n)113 ConvertFontNameToSize (char *n)
114 {
115 	int	i, size;
116 
117 	for (i = 0; i < SizePosition; i++) {
118 		n = SkipFontNameElement (n);
119 		if (!n)
120 			return -1;
121 	}
122 	size = atoi (n);
123 	return size;
124 }
125 
126 static char *
ConvertFontNameToEncoding(char * n)127 ConvertFontNameToEncoding (char *n)
128 {
129         int i;
130 	for (i = 0; i < EncodingPosition; i++) {
131 		n = SkipFontNameElement (n);
132 		if (!n)
133 			return 0;
134 	}
135 	return n;
136 }
137 
138 DviFontSizeList *
InstallFontSizes(DviWidget dw,const char * x_name,Boolean * scalablep)139 InstallFontSizes (DviWidget dw, const char *x_name, Boolean *scalablep)
140 {
141 	char	fontNameString[2048];
142 	char	**fonts;
143 	int	i, count;
144 	int	size;
145 	DviFontSizeList	*sizes, *new_size;
146 	XFontName	fontName;
147 	unsigned int	fontNameAttributes;
148 
149 	*scalablep = FALSE;
150 	if (!XParseFontName ((XFontNameString)x_name, &fontName,
151 			     &fontNameAttributes))
152 		return 0;
153 	fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize
154 				|FontNameAverageWidth);
155 	fontNameAttributes |= FontNameResolutionX;
156 	fontNameAttributes |= FontNameResolutionY;
157 	fontName.ResolutionX = dw->dvi.display_resolution;
158 	fontName.ResolutionY = dw->dvi.display_resolution;
159 	XFormatFontName (&fontName, fontNameAttributes, fontNameString);
160 	fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
161 	sizes = 0;
162 	for (i = 0; i < count; i++) {
163 		size = ConvertFontNameToSize (fonts[i]);
164 		if (size == 0) {
165 			DisposeFontSizes (dw, sizes);
166 			sizes = 0;
167 			*scalablep = TRUE;
168 			break;
169 		}
170 		if (size != -1) {
171 			new_size = (DviFontSizeList *) XtMalloc (sizeof *new_size);
172 			new_size->next = sizes;
173 			new_size->size = size;
174 			new_size->x_name = savestr (fonts[i]);
175 			new_size->doesnt_exist = 0;
176 			new_size->font = 0;
177 			sizes = new_size;
178 		}
179 	}
180 	XFreeFontNames (fonts);
181 	return sizes;
182 }
183 
184 static void
DisposeFontSizes(DviWidget dw,DviFontSizeList * fs)185 DisposeFontSizes (DviWidget dw, DviFontSizeList *fs)
186 {
187 	DviFontSizeList	*next;
188 
189 	for (; fs; fs=next) {
190 		next = fs->next;
191 		if (fs->x_name)
192 			XtFree (fs->x_name);
193 		if (fs->font && fs->font != dw->dvi.default_font) {
194 			XUnloadFont (XtDisplay (dw), fs->font->fid);
195 			XFree ((char *)fs->font);
196 		}
197 		XtFree ((char *) fs);
198 	}
199 }
200 
201 static DviFontList *
InstallFont(DviWidget dw,int position,const char * dvi_name,const char * x_name)202 InstallFont (DviWidget dw, int position,
203 	     const char *dvi_name, const char *x_name)
204 {
205 	DviFontList	*f;
206 	char		*encoding;
207 
208 	if ((f = LookupFontByPosition (dw, position)) != NULL) {
209 		/*
210 		 * ignore gratuitous font loading
211 		 */
212 		if (!strcmp (f->dvi_name, dvi_name) &&
213 		    !strcmp (f->x_name, x_name))
214 			return f;
215 
216 		DisposeFontSizes (dw, f->sizes);
217 		if (f->dvi_name)
218 			XtFree (f->dvi_name);
219 		if (f->x_name)
220 			XtFree (f->x_name);
221 		f->device_font = 0;
222 	} else {
223 		f = (DviFontList *) XtMalloc (sizeof (*f));
224 		f->next = dw->dvi.fonts;
225 		dw->dvi.fonts = f;
226 	}
227 	f->initialized = FALSE;
228 	f->dvi_name = savestr (dvi_name);
229 	f->device_font = device_find_font (dw->dvi.device, dvi_name);
230 	f->x_name = savestr (x_name);
231 	f->dvi_number = position;
232 	f->sizes = 0;
233 	f->scalable = FALSE;
234 	if (f->x_name) {
235 		encoding = ConvertFontNameToEncoding (f->x_name);
236 		f->char_map = DviFindMap (encoding);
237 	} else
238 		f->char_map = 0;
239 	/*
240 	 * force requery of fonts
241 	 */
242 	dw->dvi.font = 0;
243 	dw->dvi.font_number = -1;
244 	dw->dvi.cache.font = 0;
245 	dw->dvi.cache.font_number = -1;
246 	dw->dvi.device_font = 0;
247 	dw->dvi.device_font_number = -1;
248 	return f;
249 }
250 
251 void
ForgetFonts(DviWidget dw)252 ForgetFonts (DviWidget dw)
253 {
254 	DviFontList *f = dw->dvi.fonts;
255 
256 	while (f) {
257 		DviFontList *tem = f;
258 
259 		if (f->sizes)
260 			DisposeFontSizes (dw, f->sizes);
261 		if (f->dvi_name)
262 			XtFree (f->dvi_name);
263 		if (f->x_name)
264 			XtFree (f->x_name);
265 		f = f->next;
266 		XtFree ((char *) tem);
267 	}
268 
269 	/*
270 	 * force requery of fonts
271 	 */
272 	dw->dvi.font = 0;
273 	dw->dvi.font_number = -1;
274 	dw->dvi.cache.font = 0;
275 	dw->dvi.cache.font_number = -1;
276 	dw->dvi.device_font = 0;
277 	dw->dvi.device_font_number = -1;
278 	dw->dvi.fonts = 0;
279 }
280 
281 
282 static char *
MapDviNameToXName(DviWidget dw,const char * dvi_name)283 MapDviNameToXName (DviWidget dw, const char *dvi_name)
284 {
285 	DviFontMap	*fm;
286 
287 	for (fm = dw->dvi.font_map; fm; fm=fm->next)
288 		if (!strcmp (fm->dvi_name, dvi_name))
289 			return fm->x_name;
290 	return 0;
291 }
292 
293 #if 0
294 static char *
295 MapXNameToDviName (DviWidget dw, const char *x_name)
296 {
297 	DviFontMap	*fm;
298 
299 	for (fm = dw->dvi.font_map; fm; fm=fm->next)
300 		if (!strcmp (fm->x_name, x_name))
301 			return fm->dvi_name;
302 	return 0;
303 }
304 #endif
305 
306 void
ParseFontMap(DviWidget dw)307 ParseFontMap (DviWidget dw)
308 {
309 	char		dvi_name[1024];
310 	char		x_name[2048];
311 	char		*m, *s;
312 	DviFontMap	*fm, *new_map;
313 
314 	if (dw->dvi.font_map)
315 		DestroyFontMap (dw->dvi.font_map);
316 	fm = 0;
317 	m = dw->dvi.font_map_string;
318 	while (*m) {
319 		s = m;
320 		while (*m && !isspace (*m))
321 			++m;
322 		strncpy (dvi_name, s, m-s);
323 		dvi_name[m-s] = '\0';
324 		while (isspace (*m))
325 			++m;
326 		s = m;
327 		while (*m && *m != '\n')
328 			++m;
329 		strncpy (x_name, s, m-s);
330 		x_name[m-s] = '\0';
331 		new_map = (DviFontMap *) XtMalloc (sizeof *new_map);
332 		new_map->x_name = savestr (x_name);
333 		new_map->dvi_name = savestr (dvi_name);
334 		new_map->next = fm;
335 		fm = new_map;
336 		++m;
337 	}
338 	dw->dvi.font_map = fm;
339 }
340 
341 void
DestroyFontMap(DviFontMap * font_map)342 DestroyFontMap (DviFontMap *font_map)
343 {
344 	DviFontMap	*next;
345 
346 	for (; font_map; font_map = next) {
347 		next = font_map->next;
348 		if (font_map->x_name)
349 			XtFree (font_map->x_name);
350 		if (font_map->dvi_name)
351 			XtFree (font_map->dvi_name);
352 		XtFree ((char *) font_map);
353 	}
354 }
355 
356 /* ARGSUSED */
357 
358 void
SetFontPosition(DviWidget dw,int position,const char * dvi_name,const char * extra)359 SetFontPosition (DviWidget dw, int position,
360 		 const char *dvi_name, const char *extra)
361 {
362 	char	*x_name;
363 
364 	x_name = MapDviNameToXName (dw, dvi_name);
365 	if (x_name)
366 		(void) InstallFont (dw, position, dvi_name, x_name);
367 
368 	extra = extra;		/* unused; suppress compiler warning */
369 }
370 
371 XFontStruct *
QueryFont(DviWidget dw,int position,int size)372 QueryFont (DviWidget dw, int position, int size)
373 {
374 	DviFontList	*f;
375 	DviFontSizeList	*fs;
376 
377 	f = LookupFontByPosition (dw, position);
378 	if (!f)
379 		return dw->dvi.default_font;
380 	if (!f->initialized) {
381 		f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
382 		f->initialized = TRUE;
383 	}
384 	fs = LookupFontSizeBySize (dw, f, size);
385 	if (!fs)
386 		return dw->dvi.default_font;
387 	if (!fs->font) {
388 		if (fs->x_name)
389 			fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
390 		if (!fs->font)
391 			fs->font = dw->dvi.default_font;
392 	}
393 	return fs->font;
394 }
395 
396 DeviceFont *
QueryDeviceFont(DviWidget dw,int position)397 QueryDeviceFont (DviWidget dw, int position)
398 {
399 	DviFontList	*f;
400 
401 	f = LookupFontByPosition (dw, position);
402 	if (!f)
403 		return 0;
404 	return f->device_font;
405 }
406 
407 DviCharNameMap *
QueryFontMap(DviWidget dw,int position)408 QueryFontMap (DviWidget dw, int position)
409 {
410 	DviFontList	*f;
411 
412 	f = LookupFontByPosition (dw, position);
413 	if (f)
414 	    return f->char_map;
415 	else
416 	    return 0;
417 }
418 
419 #if 0
420 LoadFont (DviWidget dw, int position, int size)
421 {
422 	XFontStruct	*font;
423 
424 	font = QueryFont (dw, position, size);
425 	dw->dvi.font_number = position;
426 	dw->dvi.font_size = size;
427 	dw->dvi.font = font;
428 	XSetFont (XtDisplay (dw), dw->dvi.normal_GC, font->fid);
429 	return;
430 }
431 #endif
432 
433 /*
434 Local Variables:
435 c-indent-level: 8
436 c-continued-statement-offset: 8
437 c-brace-offset: -8
438 c-argdecl-indent: 8
439 c-label-offset: -8
440 c-tab-always-indent: nil
441 End:
442 */
443