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