font.c revision c166fba9
1f80a6dcdSmrg/*
2f80a6dcdSmrg * font.c
3f80a6dcdSmrg *
4f80a6dcdSmrg * map dvi fonts to X fonts
5f80a6dcdSmrg */
6f80a6dcdSmrg
7f80a6dcdSmrg#include <X11/Xos.h>
8f80a6dcdSmrg#include <X11/IntrinsicP.h>
9f80a6dcdSmrg#include <X11/StringDefs.h>
10f80a6dcdSmrg#include <stdio.h>
11f80a6dcdSmrg#include <stdlib.h>
12f80a6dcdSmrg#include <ctype.h>
13f80a6dcdSmrg#include "DviP.h"
14f80a6dcdSmrg#include "XFontName.h"
15f80a6dcdSmrg
16f80a6dcdSmrgstatic char *
17c166fba9Smrgsavestr (const char *s)
18f80a6dcdSmrg{
19f80a6dcdSmrg	char	*n;
20f80a6dcdSmrg
21f80a6dcdSmrg	if (!s)
2265912f00Smrg		return NULL;
23f80a6dcdSmrg	n = XtMalloc (strlen (s) + 1);
24f80a6dcdSmrg	if (n)
25f80a6dcdSmrg		strcpy (n, s);
26f80a6dcdSmrg	return n;
27f80a6dcdSmrg}
28f80a6dcdSmrg
29f80a6dcdSmrgstatic DviFontList *
30f80a6dcdSmrgLookupFontByPosition (DviWidget dw, int position)
31f80a6dcdSmrg{
32f80a6dcdSmrg	DviFontList	*f;
33f80a6dcdSmrg
34f80a6dcdSmrg	for (f = dw->dvi.fonts; f; f=f->next)
35f80a6dcdSmrg		if (f->dvi_number == position)
36f80a6dcdSmrg			break;
37f80a6dcdSmrg	return f;
38f80a6dcdSmrg}
39f80a6dcdSmrg
40f80a6dcdSmrgstatic DviFontSizeList *
41f80a6dcdSmrgLookupFontSizeBySize (DviWidget dw, DviFontList *f, int size)
42f80a6dcdSmrg{
4365912f00Smrg    DviFontSizeList *fs, *best = NULL;
44f80a6dcdSmrg    int		    bestdist;
45f80a6dcdSmrg    char	    fontNameString[2048];
46f80a6dcdSmrg    XFontName	    fontName;
47f80a6dcdSmrg    unsigned int    fontNameAttributes;
48f80a6dcdSmrg    int		    dist;
49f80a6dcdSmrg
50f80a6dcdSmrg    if (f->scalable)
51f80a6dcdSmrg    {
52f80a6dcdSmrg	for (best = f->sizes; best; best = best->next)
53f80a6dcdSmrg	    if (best->size == size)
54f80a6dcdSmrg		return best;
55f80a6dcdSmrg	best = (DviFontSizeList *) XtMalloc (sizeof *best);
56f80a6dcdSmrg	best->next = f->sizes;
57f80a6dcdSmrg	best->size = size;
58f80a6dcdSmrg	XParseFontName (f->x_name, &fontName, &fontNameAttributes);
59f80a6dcdSmrg	fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
60f80a6dcdSmrg	fontNameAttributes |= FontNameResolutionX;
61f80a6dcdSmrg	fontNameAttributes |= FontNameResolutionY;
62f80a6dcdSmrg	fontNameAttributes |= FontNamePointSize;
63f80a6dcdSmrg	fontName.ResolutionX = dw->dvi.screen_resolution;
64f80a6dcdSmrg	fontName.ResolutionY = dw->dvi.screen_resolution;
65f80a6dcdSmrg	fontName.PointSize = size * 10 / dw->dvi.size_scale;
66f80a6dcdSmrg	XFormatFontName (&fontName, fontNameAttributes, fontNameString);
67f80a6dcdSmrg	best->x_name = savestr (fontNameString);
68f80a6dcdSmrg#ifdef USE_XFT
69f80a6dcdSmrg	/*
70f80a6dcdSmrg	 * Force a match of a core font for adobe-fontspecific
71f80a6dcdSmrg	 * encodings; we dont have a scalable font in
72f80a6dcdSmrg	 * the right encoding
73f80a6dcdSmrg	 */
74f80a6dcdSmrg	best->core = False;
75f80a6dcdSmrg	if (!strcmp (fontName.CharSetRegistry, "adobe") &&
76f80a6dcdSmrg	    !strcmp (fontName.CharSetEncoding, "fontspecific"))
77f80a6dcdSmrg	{
78f80a6dcdSmrg	    best->core = True;
79f80a6dcdSmrg	}
80f80a6dcdSmrg#endif
81f80a6dcdSmrg	best->doesnt_exist = 0;
8265912f00Smrg	best->font = NULL;
83f80a6dcdSmrg	f->sizes = best;
84f80a6dcdSmrg    }
85f80a6dcdSmrg    else
86f80a6dcdSmrg    {
87f80a6dcdSmrg	bestdist = 65536;
88f80a6dcdSmrg    	for (fs = f->sizes; fs; fs=fs->next) {
89f80a6dcdSmrg	    dist = size - fs->size;
90f80a6dcdSmrg	    if (dist < 0)
91f80a6dcdSmrg		dist = -dist * 16;
92f80a6dcdSmrg	    if (dist < bestdist)
93f80a6dcdSmrg	    {
94f80a6dcdSmrg		best = fs;
95f80a6dcdSmrg		bestdist = dist;
96f80a6dcdSmrg	    }
97f80a6dcdSmrg    	}
98f80a6dcdSmrg    }
99f80a6dcdSmrg    return best;
100f80a6dcdSmrg}
101f80a6dcdSmrg
102f80a6dcdSmrgstatic char *
103f80a6dcdSmrgSkipFontNameElement (char *n)
104f80a6dcdSmrg{
105f80a6dcdSmrg	while (*n != '-')
106f80a6dcdSmrg		if (!*++n)
10765912f00Smrg			return NULL;
108f80a6dcdSmrg	return n+1;
109f80a6dcdSmrg}
110f80a6dcdSmrg
111f80a6dcdSmrg# define SizePosition		8
112f80a6dcdSmrg# define EncodingPosition	13
113f80a6dcdSmrg
114f80a6dcdSmrg#ifndef USE_XFT
115f80a6dcdSmrgstatic int
116f80a6dcdSmrgConvertFontNameToSize (char *n)
117f80a6dcdSmrg{
118f80a6dcdSmrg	int	i, size;
119f80a6dcdSmrg
120f80a6dcdSmrg	for (i = 0; i < SizePosition; i++) {
121f80a6dcdSmrg		n = SkipFontNameElement (n);
122f80a6dcdSmrg		if (!n)
123f80a6dcdSmrg			return -1;
124f80a6dcdSmrg	}
125f80a6dcdSmrg	size = atoi (n);
126f80a6dcdSmrg	return size/10;
127f80a6dcdSmrg}
128f80a6dcdSmrg#endif
129f80a6dcdSmrg
130f80a6dcdSmrgstatic char *
131f80a6dcdSmrgConvertFontNameToEncoding (char *n)
132f80a6dcdSmrg{
133f80a6dcdSmrg        int i;
134f80a6dcdSmrg	for (i = 0; i < EncodingPosition; i++) {
135f80a6dcdSmrg		n = SkipFontNameElement (n);
136f80a6dcdSmrg		if (!n)
13765912f00Smrg			return NULL;
138f80a6dcdSmrg	}
139f80a6dcdSmrg	return n;
140f80a6dcdSmrg}
141f80a6dcdSmrg
142f80a6dcdSmrgstatic void
143f80a6dcdSmrgDisposeFontSizes (DviWidget dw, DviFontSizeList *fs)
144f80a6dcdSmrg{
145f80a6dcdSmrg    DviFontSizeList	*next;
146f80a6dcdSmrg
147f80a6dcdSmrg    for (; fs; fs=next) {
148f80a6dcdSmrg	next = fs->next;
149f80a6dcdSmrg	if (fs->x_name)
150f80a6dcdSmrg		XtFree (fs->x_name);
151f80a6dcdSmrg	if (fs->font)
152f80a6dcdSmrg	{
153f80a6dcdSmrg#ifdef USE_XFT
154f80a6dcdSmrg	    XftFontClose (XtDisplay (dw), fs->font);
155f80a6dcdSmrg#else
156f80a6dcdSmrg	    XUnloadFont (XtDisplay (dw), fs->font->fid);
157f80a6dcdSmrg	    XFree ((char *)fs->font);
158f80a6dcdSmrg#endif
159f80a6dcdSmrg	}
160f80a6dcdSmrg	XtFree ((char *) fs);
161f80a6dcdSmrg    }
162f80a6dcdSmrg}
163f80a6dcdSmrg
164f80a6dcdSmrgvoid
165f80a6dcdSmrgResetFonts (DviWidget dw)
166f80a6dcdSmrg{
167f80a6dcdSmrg    DviFontList	*f;
168f80a6dcdSmrg
169f80a6dcdSmrg    for (f = dw->dvi.fonts; f; f = f->next)
170f80a6dcdSmrg    {
171f80a6dcdSmrg	if (f->initialized)
172f80a6dcdSmrg	{
173f80a6dcdSmrg	    DisposeFontSizes (dw, f->sizes);
17465912f00Smrg	    f->sizes = NULL;
175f80a6dcdSmrg	    f->initialized = FALSE;
176f80a6dcdSmrg	    f->scalable = FALSE;
177f80a6dcdSmrg	}
178f80a6dcdSmrg    }
179f80a6dcdSmrg    /*
180f80a6dcdSmrg     * force requery of fonts
181f80a6dcdSmrg     */
18265912f00Smrg    dw->dvi.font = NULL;
183f80a6dcdSmrg    dw->dvi.font_number = -1;
18465912f00Smrg    dw->dvi.cache.font = NULL;
185f80a6dcdSmrg    dw->dvi.cache.font_number = -1;
186f80a6dcdSmrg}
187f80a6dcdSmrg
188f80a6dcdSmrgstatic DviFontSizeList *
189f80a6dcdSmrgInstallFontSizes (DviWidget dw, char *x_name, Boolean *scalablep)
190f80a6dcdSmrg{
191f80a6dcdSmrg#ifndef USE_XFT
192f80a6dcdSmrg    char	    fontNameString[2048];
193f80a6dcdSmrg    char	    **fonts;
194f80a6dcdSmrg    int		    i, count;
195f80a6dcdSmrg    int		    size;
196f80a6dcdSmrg    DviFontSizeList *new;
197f80a6dcdSmrg    XFontName	    fontName;
198f80a6dcdSmrg    unsigned int    fontNameAttributes;
199f80a6dcdSmrg#endif
200f80a6dcdSmrg    DviFontSizeList *sizes;
201f80a6dcdSmrg
20265912f00Smrg    sizes = NULL;
203f80a6dcdSmrg#ifdef USE_XFT
204f80a6dcdSmrg    *scalablep = TRUE;
205f80a6dcdSmrg#else
206f80a6dcdSmrg    *scalablep = FALSE;
207f80a6dcdSmrg    if (!XParseFontName (x_name, &fontName, &fontNameAttributes))
20865912f00Smrg	return NULL;
209f80a6dcdSmrg
210f80a6dcdSmrg    fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize);
211f80a6dcdSmrg    fontNameAttributes |= FontNameResolutionX;
212f80a6dcdSmrg    fontNameAttributes |= FontNameResolutionY;
213f80a6dcdSmrg    fontName.ResolutionX = dw->dvi.screen_resolution;
214f80a6dcdSmrg    fontName.ResolutionY = dw->dvi.screen_resolution;
215f80a6dcdSmrg    XFormatFontName (&fontName, fontNameAttributes, fontNameString);
216f80a6dcdSmrg    fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
217f80a6dcdSmrg    for (i = 0; i < count; i++) {
218f80a6dcdSmrg	size = ConvertFontNameToSize (fonts[i]);
219f80a6dcdSmrg	if (size == 0)
220f80a6dcdSmrg	{
221f80a6dcdSmrg	    DisposeFontSizes (dw, sizes);
222f80a6dcdSmrg	    *scalablep = TRUE;
22365912f00Smrg	    sizes = NULL;
224f80a6dcdSmrg	    break;
225f80a6dcdSmrg	}
226f80a6dcdSmrg	if (size != -1) {
227f80a6dcdSmrg	    new = (DviFontSizeList *) XtMalloc (sizeof *new);
228f80a6dcdSmrg	    new->next = sizes;
229f80a6dcdSmrg	    new->size = size;
230f80a6dcdSmrg	    new->x_name = savestr (fonts[i]);
231f80a6dcdSmrg	    new->doesnt_exist = 0;
23265912f00Smrg	    new->font = NULL;
233f80a6dcdSmrg	    sizes = new;
234f80a6dcdSmrg	}
235f80a6dcdSmrg    }
236f80a6dcdSmrg    XFreeFontNames (fonts);
237f80a6dcdSmrg#endif
238f80a6dcdSmrg    return sizes;
239f80a6dcdSmrg}
240f80a6dcdSmrg
241f80a6dcdSmrgstatic DviFontList *
242c166fba9SmrgInstallFont (DviWidget dw, int position, const char *dvi_name, const char *x_name)
243f80a6dcdSmrg{
244f80a6dcdSmrg    DviFontList	*f;
245c166fba9Smrg    const char	*encoding;
246f80a6dcdSmrg
247f80a6dcdSmrg    f = LookupFontByPosition (dw, position);
248f80a6dcdSmrg    if (f) {
249f80a6dcdSmrg	/*
250f80a6dcdSmrg	 * ignore gratuitous font loading
251f80a6dcdSmrg	 */
252f80a6dcdSmrg	if (!strcmp (f->dvi_name, dvi_name) && !strcmp (f->x_name, x_name))
253f80a6dcdSmrg	    return f;
254f80a6dcdSmrg
255f80a6dcdSmrg	DisposeFontSizes (dw, f->sizes);
256f80a6dcdSmrg	if (f->dvi_name)
257f80a6dcdSmrg	    XtFree (f->dvi_name);
258f80a6dcdSmrg	if (f->x_name)
259f80a6dcdSmrg	    XtFree (f->x_name);
260f80a6dcdSmrg    } else {
261f80a6dcdSmrg	f = (DviFontList *) XtMalloc (sizeof (*f));
262f80a6dcdSmrg	f->next = dw->dvi.fonts;
263f80a6dcdSmrg	dw->dvi.fonts = f;
264f80a6dcdSmrg    }
265f80a6dcdSmrg    f->initialized = FALSE;
266f80a6dcdSmrg    f->dvi_name = savestr (dvi_name);
267f80a6dcdSmrg    f->x_name = savestr (x_name);
268f80a6dcdSmrg    f->dvi_number = position;
26965912f00Smrg    f->sizes = NULL;
270f80a6dcdSmrg    f->scalable = FALSE;
271f80a6dcdSmrg    if (f->x_name) {
272f80a6dcdSmrg	encoding = ConvertFontNameToEncoding (f->x_name);
273f80a6dcdSmrg	f->char_map = DviFindMap (encoding);
274f80a6dcdSmrg    } else
27565912f00Smrg	f->char_map = NULL;
276f80a6dcdSmrg    /*
277f80a6dcdSmrg     * force requery of fonts
278f80a6dcdSmrg     */
27965912f00Smrg    dw->dvi.font = NULL;
280f80a6dcdSmrg    dw->dvi.font_number = -1;
28165912f00Smrg    dw->dvi.cache.font = NULL;
282f80a6dcdSmrg    dw->dvi.cache.font_number = -1;
283f80a6dcdSmrg    return f;
284f80a6dcdSmrg}
285f80a6dcdSmrg
286c166fba9Smrgstatic const char *
287c166fba9SmrgMapDviNameToXName (DviWidget dw, const char *dvi_name)
288f80a6dcdSmrg{
289f80a6dcdSmrg    DviFontMap	*fm;
290f80a6dcdSmrg
291f80a6dcdSmrg    for (fm = dw->dvi.font_map; fm; fm=fm->next)
292f80a6dcdSmrg	if (!strcmp (fm->dvi_name, dvi_name))
293f80a6dcdSmrg	    return fm->x_name;
294f80a6dcdSmrg    ++dvi_name;
295f80a6dcdSmrg    for (fm = dw->dvi.font_map; fm; fm=fm->next)
296f80a6dcdSmrg	if (!strcmp (fm->dvi_name, "R"))
297f80a6dcdSmrg	    return fm->x_name;
298f80a6dcdSmrg    if (dw->dvi.font_map->x_name)
299f80a6dcdSmrg	return dw->dvi.font_map->x_name;
300f80a6dcdSmrg    return "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1";
301f80a6dcdSmrg}
302f80a6dcdSmrg
303f80a6dcdSmrg
304f80a6dcdSmrgvoid
30565912f00SmrgParseFontMap (DviWidget dw)
306f80a6dcdSmrg{
307f80a6dcdSmrg    char		dvi_name[1024];
308f80a6dcdSmrg    char		x_name[2048];
309f80a6dcdSmrg    char		*m, *s;
310f80a6dcdSmrg    DviFontMap	*fm, *new;
311f80a6dcdSmrg
312f80a6dcdSmrg    if (dw->dvi.font_map)
313f80a6dcdSmrg	    DestroyFontMap (dw->dvi.font_map);
31465912f00Smrg    fm = NULL;
315f80a6dcdSmrg    m = dw->dvi.font_map_string;
316f80a6dcdSmrg    while (*m) {
317f80a6dcdSmrg	s = m;
318f80a6dcdSmrg	while (*m && !isspace (*m))
319f80a6dcdSmrg	    ++m;
320f80a6dcdSmrg	strncpy (dvi_name, s, m-s);
321f80a6dcdSmrg	dvi_name[m-s] = '\0';
322f80a6dcdSmrg	while (isspace (*m))
323f80a6dcdSmrg	    ++m;
324f80a6dcdSmrg	s = m;
325f80a6dcdSmrg	while (*m && *m != '\n')
326f80a6dcdSmrg	    ++m;
327f80a6dcdSmrg	strncpy (x_name, s, m-s);
328f80a6dcdSmrg	x_name[m-s] = '\0';
329f80a6dcdSmrg	new = (DviFontMap *) XtMalloc (sizeof *new);
330f80a6dcdSmrg	new->x_name = savestr (x_name);
331f80a6dcdSmrg	new->dvi_name = savestr (dvi_name);
332f80a6dcdSmrg	new->next = fm;
333f80a6dcdSmrg	fm = new;
334f80a6dcdSmrg	++m;
335f80a6dcdSmrg    }
336f80a6dcdSmrg    dw->dvi.font_map = fm;
337f80a6dcdSmrg}
338f80a6dcdSmrg
339f80a6dcdSmrgvoid
34065912f00SmrgDestroyFontMap (DviFontMap *font_map)
341f80a6dcdSmrg{
342f80a6dcdSmrg    DviFontMap	*next;
343f80a6dcdSmrg
344f80a6dcdSmrg    for (; font_map; font_map = next) {
345f80a6dcdSmrg	next = font_map->next;
346f80a6dcdSmrg	if (font_map->x_name)
347f80a6dcdSmrg	    XtFree (font_map->x_name);
348f80a6dcdSmrg	if (font_map->dvi_name)
349f80a6dcdSmrg	    XtFree (font_map->dvi_name);
350f80a6dcdSmrg	XtFree ((char *) font_map);
351f80a6dcdSmrg    }
352f80a6dcdSmrg}
353f80a6dcdSmrg
354f80a6dcdSmrg/*ARGSUSED*/
355f80a6dcdSmrgvoid
356c166fba9SmrgSetFontPosition (DviWidget dw, int position, const char *dvi_name, const char *extra)
357f80a6dcdSmrg{
358c166fba9Smrg    const char	*x_name;
359f80a6dcdSmrg
360f80a6dcdSmrg    x_name = MapDviNameToXName (dw, dvi_name);
361f80a6dcdSmrg    (void) InstallFont (dw, position, dvi_name, x_name);
362f80a6dcdSmrg}
363f80a6dcdSmrg
364f80a6dcdSmrg#ifdef USE_XFT
365f80a6dcdSmrgXftFont *
366f80a6dcdSmrg#else
367f80a6dcdSmrgXFontStruct *
368f80a6dcdSmrg#endif
36965912f00SmrgQueryFont (DviWidget dw, int position, int size)
370f80a6dcdSmrg{
371f80a6dcdSmrg    DviFontList	*f;
372f80a6dcdSmrg    DviFontSizeList	*fs;
373f80a6dcdSmrg
374f80a6dcdSmrg    f = LookupFontByPosition (dw, position);
375f80a6dcdSmrg    if (!f)
376f80a6dcdSmrg	return dw->dvi.default_font;
377f80a6dcdSmrg    if (!f->initialized) {
378f80a6dcdSmrg	f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
379f80a6dcdSmrg	f->initialized = TRUE;
380f80a6dcdSmrg    }
381f80a6dcdSmrg    fs = LookupFontSizeBySize (dw, f, size);
382f80a6dcdSmrg    if (!fs)
383f80a6dcdSmrg	return dw->dvi.default_font;
384f80a6dcdSmrg    if (!fs->font) {
385f80a6dcdSmrg	if (fs->x_name)
386f80a6dcdSmrg	{
387f80a6dcdSmrg#ifdef USE_XFT
388f80a6dcdSmrg	    XftPattern	*pat;
389f80a6dcdSmrg	    XftPattern	*match;
390f80a6dcdSmrg	    XftResult	result;
391f80a6dcdSmrg
392f80a6dcdSmrg	    pat = XftXlfdParse (fs->x_name, False, False);
393f80a6dcdSmrg	    XftPatternAddBool (pat, XFT_CORE, fs->core);
394f80a6dcdSmrg	    match = XftFontMatch (XtDisplay (dw),
395f80a6dcdSmrg				  XScreenNumberOfScreen(dw->core.screen),
396f80a6dcdSmrg				  pat, &result);
397f80a6dcdSmrg	    XftPatternDestroy (pat);
398f80a6dcdSmrg	    if (match)
399f80a6dcdSmrg	    {
400f80a6dcdSmrg		fs->font = XftFontOpenPattern (XtDisplay (dw),
401f80a6dcdSmrg					       match);
402f80a6dcdSmrg		if (!fs->font)
403f80a6dcdSmrg		    XftPatternDestroy (match);
404f80a6dcdSmrg	    }
405f80a6dcdSmrg	    else
406f80a6dcdSmrg		fs->font = 0;
407f80a6dcdSmrg#else
408f80a6dcdSmrg	    fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
409f80a6dcdSmrg#endif
410f80a6dcdSmrg	}
411f80a6dcdSmrg	if (!fs->font)
412f80a6dcdSmrg	    fs->font = dw->dvi.default_font;
413f80a6dcdSmrg    }
414f80a6dcdSmrg    return fs->font;
415f80a6dcdSmrg}
416f80a6dcdSmrg
417f80a6dcdSmrgDviCharNameMap *
41865912f00SmrgQueryFontMap (DviWidget dw, int position)
419f80a6dcdSmrg{
420f80a6dcdSmrg	DviFontList	*f;
421f80a6dcdSmrg
422f80a6dcdSmrg	f = LookupFontByPosition (dw, position);
423f80a6dcdSmrg	if (f)
424f80a6dcdSmrg	    return f->char_map;
425f80a6dcdSmrg	else
42665912f00Smrg	    return NULL;
427f80a6dcdSmrg}
428f80a6dcdSmrg
429f80a6dcdSmrgunsigned char *
430c166fba9SmrgDviCharIsLigature (DviCharNameMap *map, const char *name)
431f80a6dcdSmrg{
432f80a6dcdSmrg    int	    i;
433f80a6dcdSmrg
434f80a6dcdSmrg    for (i = 0; i < DVI_MAX_LIGATURES; i++) {
435f80a6dcdSmrg	if (!map->ligatures[i][0])
436f80a6dcdSmrg	    break;
437f80a6dcdSmrg	if (!strcmp (name, map->ligatures[i][0]))
438f80a6dcdSmrg	    return (unsigned char *) map->ligatures[i][1];
439f80a6dcdSmrg    }
44065912f00Smrg    return NULL;
441f80a6dcdSmrg}
442