1f80a6dcdSmrg/*
2f80a6dcdSmrg * font.c
3f80a6dcdSmrg *
4f80a6dcdSmrg * map dvi fonts to X fonts
5f80a6dcdSmrg */
600994698Smrg#ifdef HAVE_CONFIG_H
700994698Smrg# include "config.h"
800994698Smrg#endif
9f80a6dcdSmrg
10f80a6dcdSmrg#include <X11/Xos.h>
11f80a6dcdSmrg#include <X11/IntrinsicP.h>
12f80a6dcdSmrg#include <X11/StringDefs.h>
13f80a6dcdSmrg#include <stdio.h>
14f80a6dcdSmrg#include <stdlib.h>
15f80a6dcdSmrg#include <ctype.h>
16f80a6dcdSmrg#include "DviP.h"
17f80a6dcdSmrg#include "XFontName.h"
18f80a6dcdSmrg
19f80a6dcdSmrgstatic char *
2000994698Smrgsavestr(const char *s)
21f80a6dcdSmrg{
2200994698Smrg    size_t len;
2300994698Smrg    char * n;
2400994698Smrg
2500994698Smrg    if (!s)
2600994698Smrg        return NULL;
2700994698Smrg    len = strlen(s) + 1;
2800994698Smrg    n = XtMalloc (len);
2900994698Smrg    if (n)
3000994698Smrg        memcpy(n, s, len);
3100994698Smrg    return n;
32f80a6dcdSmrg}
33f80a6dcdSmrg
34f80a6dcdSmrgstatic DviFontList *
3500994698SmrgLookupFontByPosition(DviWidget dw, int position)
36f80a6dcdSmrg{
3700994698Smrg    DviFontList *f;
38f80a6dcdSmrg
3900994698Smrg    for (f = dw->dvi.fonts; f; f = f->next) {
4000994698Smrg        if (f->dvi_number == position)
4100994698Smrg            break;
4200994698Smrg    }
4300994698Smrg    return f;
44f80a6dcdSmrg}
45f80a6dcdSmrg
46f80a6dcdSmrgstatic DviFontSizeList *
4700994698SmrgLookupFontSizeBySize(DviWidget dw, DviFontList *f, int size)
48f80a6dcdSmrg{
4900994698Smrg    DviFontSizeList *best = NULL;
5000994698Smrg
5100994698Smrg    if (f->scalable) {
5200994698Smrg        char            fontNameString[2048];
5300994698Smrg        XFontName       fontName;
5400994698Smrg        unsigned int    fontNameAttributes;
5500994698Smrg
5600994698Smrg        for (best = f->sizes; best; best = best->next) {
5700994698Smrg            if (best->size == size)
5800994698Smrg                return best;
5900994698Smrg        }
6000994698Smrg        best = (DviFontSizeList *) XtMalloc(sizeof *best);
6100994698Smrg        best->next = f->sizes;
6200994698Smrg        best->size = size;
6300994698Smrg        XParseFontName(f->x_name, &fontName, &fontNameAttributes);
6400994698Smrg        fontNameAttributes &= ~(FontNamePixelSize | FontNameAverageWidth);
6500994698Smrg        fontNameAttributes |= FontNameResolutionX;
6600994698Smrg        fontNameAttributes |= FontNameResolutionY;
6700994698Smrg        fontNameAttributes |= FontNamePointSize;
6800994698Smrg        fontName.ResolutionX = dw->dvi.screen_resolution;
6900994698Smrg        fontName.ResolutionY = dw->dvi.screen_resolution;
7000994698Smrg        fontName.PointSize = size * 10 / dw->dvi.size_scale;
7100994698Smrg        XFormatFontName(&fontName, fontNameAttributes, fontNameString);
7200994698Smrg        best->x_name = savestr(fontNameString);
73f80a6dcdSmrg#ifdef USE_XFT
7400994698Smrg        /*
7500994698Smrg         * Force a match of a core font for adobe-fontspecific
7600994698Smrg         * encodings; we don't have a scalable font in
7700994698Smrg         * the right encoding
7800994698Smrg         */
7900994698Smrg        best->core = False;
8000994698Smrg        if (!strcmp(fontName.CharSetRegistry, "adobe") &&
8100994698Smrg            !strcmp(fontName.CharSetEncoding, "fontspecific")) {
8200994698Smrg            best->core = True;
8300994698Smrg        }
84f80a6dcdSmrg#endif
8500994698Smrg        best->doesnt_exist = 0;
8600994698Smrg        best->font = NULL;
8700994698Smrg        f->sizes = best;
88f80a6dcdSmrg    }
8900994698Smrg    else {
9000994698Smrg        int bestdist = 65536;
9100994698Smrg
9200994698Smrg        for (DviFontSizeList * fs = f->sizes; fs; fs = fs->next) {
9300994698Smrg            int dist = size - fs->size;
9400994698Smrg
9500994698Smrg            if (dist < 0)
9600994698Smrg                dist = -dist * 16;
9700994698Smrg            if (dist < bestdist) {
9800994698Smrg                best = fs;
9900994698Smrg                bestdist = dist;
10000994698Smrg            }
10100994698Smrg        }
102f80a6dcdSmrg    }
103f80a6dcdSmrg    return best;
104f80a6dcdSmrg}
105f80a6dcdSmrg
10600994698Smrgstatic const char *
10700994698SmrgSkipFontNameElement(const char *n)
108f80a6dcdSmrg{
10900994698Smrg    while (*n != '-') {
11000994698Smrg        if (!*++n)
11100994698Smrg            return NULL;
11200994698Smrg    }
11300994698Smrg    return n + 1;
114f80a6dcdSmrg}
115f80a6dcdSmrg
11600994698Smrg#define SizePosition		8
11700994698Smrg#define EncodingPosition	13
118f80a6dcdSmrg
119f80a6dcdSmrg#ifndef USE_XFT
120f80a6dcdSmrgstatic int
12100994698SmrgConvertFontNameToSize(const char *n)
122f80a6dcdSmrg{
12300994698Smrg    int i, size;
12400994698Smrg
12500994698Smrg    for (i = 0; i < SizePosition; i++) {
12600994698Smrg        n = SkipFontNameElement(n);
12700994698Smrg        if (!n)
12800994698Smrg            return -1;
12900994698Smrg    }
13000994698Smrg    size = atoi(n);
13100994698Smrg    return size / 10;
132f80a6dcdSmrg}
133f80a6dcdSmrg#endif
134f80a6dcdSmrg
13500994698Smrgstatic const char *
13600994698SmrgConvertFontNameToEncoding(const char *n)
137f80a6dcdSmrg{
13800994698Smrg    for (int i = 0; i < EncodingPosition; i++) {
13900994698Smrg        n = SkipFontNameElement(n);
14000994698Smrg        if (!n)
14100994698Smrg            return NULL;
14200994698Smrg    }
14300994698Smrg    return n;
144f80a6dcdSmrg}
145f80a6dcdSmrg
146f80a6dcdSmrgstatic void
14700994698SmrgDisposeFontSizes(DviWidget dw, DviFontSizeList *fs)
148f80a6dcdSmrg{
14900994698Smrg    DviFontSizeList *next;
15000994698Smrg
15100994698Smrg    for (; fs; fs = next) {
15200994698Smrg        next = fs->next;
15300994698Smrg        if (fs->x_name)
15400994698Smrg            XtFree(fs->x_name);
15500994698Smrg        if (fs->font) {
156f80a6dcdSmrg#ifdef USE_XFT
15700994698Smrg            XftFontClose(XtDisplay(dw), fs->font);
158f80a6dcdSmrg#else
15900994698Smrg            XUnloadFont(XtDisplay(dw), fs->font->fid);
16000994698Smrg            XFree((char *) fs->font);
161f80a6dcdSmrg#endif
16200994698Smrg        }
16300994698Smrg        XtFree((char *) fs);
164f80a6dcdSmrg    }
165f80a6dcdSmrg}
166f80a6dcdSmrg
167f80a6dcdSmrgvoid
16800994698SmrgResetFonts(DviWidget dw)
169f80a6dcdSmrg{
17000994698Smrg    for (DviFontList *f = dw->dvi.fonts; f; f = f->next) {
17100994698Smrg        if (f->initialized) {
17200994698Smrg            DisposeFontSizes(dw, f->sizes);
17300994698Smrg            f->sizes = NULL;
17400994698Smrg            f->initialized = FALSE;
17500994698Smrg            f->scalable = FALSE;
17600994698Smrg        }
177f80a6dcdSmrg    }
178f80a6dcdSmrg    /*
179f80a6dcdSmrg     * force requery of fonts
180f80a6dcdSmrg     */
18165912f00Smrg    dw->dvi.font = NULL;
182f80a6dcdSmrg    dw->dvi.font_number = -1;
18365912f00Smrg    dw->dvi.cache.font = NULL;
184f80a6dcdSmrg    dw->dvi.cache.font_number = -1;
185f80a6dcdSmrg}
186f80a6dcdSmrg
187f80a6dcdSmrgstatic DviFontSizeList *
18800994698SmrgInstallFontSizes(DviWidget dw, const char *x_name, Boolean *scalablep)
189f80a6dcdSmrg{
190f80a6dcdSmrg#ifndef USE_XFT
19100994698Smrg    char fontNameString[2048];
19200994698Smrg    char **fonts;
19300994698Smrg    int count;
19400994698Smrg    XFontName fontName;
19500994698Smrg    unsigned int fontNameAttributes;
196f80a6dcdSmrg#endif
19700994698Smrg    DviFontSizeList *sizes = NULL;
198f80a6dcdSmrg
199f80a6dcdSmrg#ifdef USE_XFT
200f80a6dcdSmrg    *scalablep = TRUE;
201f80a6dcdSmrg#else
202f80a6dcdSmrg    *scalablep = FALSE;
20300994698Smrg    if (!XParseFontName(x_name, &fontName, &fontNameAttributes))
20400994698Smrg        return NULL;
20500994698Smrg
20600994698Smrg    fontNameAttributes &= ~(FontNamePixelSize | FontNamePointSize);
207f80a6dcdSmrg    fontNameAttributes |= FontNameResolutionX;
208f80a6dcdSmrg    fontNameAttributes |= FontNameResolutionY;
209f80a6dcdSmrg    fontName.ResolutionX = dw->dvi.screen_resolution;
210f80a6dcdSmrg    fontName.ResolutionY = dw->dvi.screen_resolution;
21100994698Smrg    XFormatFontName(&fontName, fontNameAttributes, fontNameString);
21200994698Smrg    fonts = XListFonts(XtDisplay(dw), fontNameString, 10000000, &count);
2138c7c3c7eSmrg    for (int i = 0; i < count; i++) {
21400994698Smrg        int size = ConvertFontNameToSize(fonts[i]);
21500994698Smrg
21600994698Smrg        if (size == 0) {
21700994698Smrg            DisposeFontSizes(dw, sizes);
21800994698Smrg            *scalablep = TRUE;
21900994698Smrg            sizes = NULL;
22000994698Smrg            break;
22100994698Smrg        }
22200994698Smrg        if (size != -1) {
22300994698Smrg            DviFontSizeList *new = (DviFontSizeList *) XtMalloc(sizeof *new);
22400994698Smrg
22500994698Smrg            new->next = sizes;
22600994698Smrg            new->size = size;
22700994698Smrg            new->x_name = savestr(fonts[i]);
22800994698Smrg            new->doesnt_exist = 0;
22900994698Smrg            new->font = NULL;
23000994698Smrg            sizes = new;
23100994698Smrg        }
232f80a6dcdSmrg    }
23300994698Smrg    XFreeFontNames(fonts);
234f80a6dcdSmrg#endif
235f80a6dcdSmrg    return sizes;
236f80a6dcdSmrg}
237f80a6dcdSmrg
238f80a6dcdSmrgstatic DviFontList *
23900994698SmrgInstallFont(DviWidget dw, int position, const char *dvi_name,
24000994698Smrg            const char *x_name)
241f80a6dcdSmrg{
24200994698Smrg    DviFontList *f = LookupFontByPosition(dw, position);
243f80a6dcdSmrg
244f80a6dcdSmrg    if (f) {
24500994698Smrg        /*
24600994698Smrg         * ignore gratuitous font loading
24700994698Smrg         */
24800994698Smrg        if (!strcmp(f->dvi_name, dvi_name) && !strcmp(f->x_name, x_name))
24900994698Smrg            return f;
25000994698Smrg
25100994698Smrg        DisposeFontSizes(dw, f->sizes);
25200994698Smrg        if (f->dvi_name)
25300994698Smrg            XtFree(f->dvi_name);
25400994698Smrg        if (f->x_name)
25500994698Smrg            XtFree(f->x_name);
25600994698Smrg    }
25700994698Smrg    else {
25800994698Smrg        f = (DviFontList *) XtMalloc(sizeof(*f));
25900994698Smrg        f->next = dw->dvi.fonts;
26000994698Smrg        dw->dvi.fonts = f;
261f80a6dcdSmrg    }
262f80a6dcdSmrg    f->initialized = FALSE;
26300994698Smrg    f->dvi_name = savestr(dvi_name);
26400994698Smrg    f->x_name = savestr(x_name);
265f80a6dcdSmrg    f->dvi_number = position;
26665912f00Smrg    f->sizes = NULL;
267f80a6dcdSmrg    f->scalable = FALSE;
268f80a6dcdSmrg    if (f->x_name) {
26900994698Smrg        const char *encoding = ConvertFontNameToEncoding(f->x_name);
27000994698Smrg
27100994698Smrg        f->char_map = DviFindMap(encoding);
27200994698Smrg    }
27300994698Smrg    else
27400994698Smrg        f->char_map = NULL;
275f80a6dcdSmrg    /*
276f80a6dcdSmrg     * force requery of fonts
277f80a6dcdSmrg     */
27865912f00Smrg    dw->dvi.font = NULL;
279f80a6dcdSmrg    dw->dvi.font_number = -1;
28065912f00Smrg    dw->dvi.cache.font = NULL;
281f80a6dcdSmrg    dw->dvi.cache.font_number = -1;
282f80a6dcdSmrg    return f;
283f80a6dcdSmrg}
284f80a6dcdSmrg
285c166fba9Smrgstatic const char *
28600994698SmrgMapDviNameToXName(DviWidget dw, const char *dvi_name)
287f80a6dcdSmrg{
28800994698Smrg    DviFontMap *fm;
28900994698Smrg
29000994698Smrg    for (fm = dw->dvi.font_map; fm; fm = fm->next)
29100994698Smrg        if (!strcmp(fm->dvi_name, dvi_name))
29200994698Smrg            return fm->x_name;
293f80a6dcdSmrg    ++dvi_name;
29400994698Smrg    for (fm = dw->dvi.font_map; fm; fm = fm->next)
29500994698Smrg        if (!strcmp(fm->dvi_name, "R"))
29600994698Smrg            return fm->x_name;
297f80a6dcdSmrg    if (dw->dvi.font_map->x_name)
29800994698Smrg        return dw->dvi.font_map->x_name;
299f80a6dcdSmrg    return "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1";
300f80a6dcdSmrg}
301f80a6dcdSmrg
302f80a6dcdSmrgvoid
30300994698SmrgParseFontMap(DviWidget dw)
304f80a6dcdSmrg{
30500994698Smrg    char *m;
30600994698Smrg    DviFontMap *fm;
307f80a6dcdSmrg
308f80a6dcdSmrg    if (dw->dvi.font_map)
30900994698Smrg        DestroyFontMap(dw->dvi.font_map);
31065912f00Smrg    fm = NULL;
311f80a6dcdSmrg    m = dw->dvi.font_map_string;
312f80a6dcdSmrg    while (*m) {
31300994698Smrg        char dvi_name[1024];
31400994698Smrg        char x_name[2048];
31500994698Smrg        char *s = m;
31600994698Smrg
31700994698Smrg        while (*m && !isspace(*m))
31800994698Smrg            ++m;
31900994698Smrg        strncpy(dvi_name, s, m - s);
32000994698Smrg        dvi_name[m - s] = '\0';
32100994698Smrg        while (isspace(*m))
32200994698Smrg            ++m;
32300994698Smrg        s = m;
32400994698Smrg        while (*m && *m != '\n')
32500994698Smrg            ++m;
32600994698Smrg        strncpy(x_name, s, m - s);
32700994698Smrg        x_name[m - s] = '\0';
32800994698Smrg
32900994698Smrg        DviFontMap *new = (DviFontMap *) XtMalloc(sizeof *new);
33000994698Smrg        new->x_name = savestr(x_name);
33100994698Smrg        new->dvi_name = savestr(dvi_name);
33200994698Smrg        new->next = fm;
33300994698Smrg        fm = new;
33400994698Smrg        ++m;
335f80a6dcdSmrg    }
336f80a6dcdSmrg    dw->dvi.font_map = fm;
337f80a6dcdSmrg}
338f80a6dcdSmrg
339f80a6dcdSmrgvoid
34000994698SmrgDestroyFontMap(DviFontMap *font_map)
341f80a6dcdSmrg{
34200994698Smrg    DviFontMap *next;
343f80a6dcdSmrg
344f80a6dcdSmrg    for (; font_map; font_map = next) {
34500994698Smrg        next = font_map->next;
34600994698Smrg        if (font_map->x_name)
34700994698Smrg            XtFree(font_map->x_name);
34800994698Smrg        if (font_map->dvi_name)
34900994698Smrg            XtFree(font_map->dvi_name);
35000994698Smrg        XtFree((char *) font_map);
351f80a6dcdSmrg    }
352f80a6dcdSmrg}
353f80a6dcdSmrg
35400994698Smrg /*ARGSUSED*/ void
35500994698SmrgSetFontPosition(DviWidget dw, int position, const char *dvi_name,
35600994698Smrg                const char *extra)
357f80a6dcdSmrg{
35800994698Smrg    const char *x_name;
359f80a6dcdSmrg
36000994698Smrg    x_name = MapDviNameToXName(dw, dvi_name);
36100994698Smrg    (void) InstallFont(dw, position, dvi_name, x_name);
362f80a6dcdSmrg}
363f80a6dcdSmrg
364f80a6dcdSmrg#ifdef USE_XFT
365f80a6dcdSmrgXftFont *
366f80a6dcdSmrg#else
367f80a6dcdSmrgXFontStruct *
368f80a6dcdSmrg#endif
36900994698SmrgQueryFont(DviWidget dw, int position, int size)
370f80a6dcdSmrg{
37100994698Smrg    DviFontList *f;
37200994698Smrg    DviFontSizeList *fs;
373f80a6dcdSmrg
37400994698Smrg    f = LookupFontByPosition(dw, position);
375f80a6dcdSmrg    if (!f)
37600994698Smrg        return dw->dvi.default_font;
377f80a6dcdSmrg    if (!f->initialized) {
37800994698Smrg        f->sizes = InstallFontSizes(dw, f->x_name, &f->scalable);
37900994698Smrg        f->initialized = TRUE;
380f80a6dcdSmrg    }
38100994698Smrg    fs = LookupFontSizeBySize(dw, f, size);
382f80a6dcdSmrg    if (!fs)
38300994698Smrg        return dw->dvi.default_font;
384f80a6dcdSmrg    if (!fs->font) {
38500994698Smrg        if (fs->x_name) {
386f80a6dcdSmrg#ifdef USE_XFT
38700994698Smrg            XftPattern *pat;
38800994698Smrg            XftPattern *match;
38900994698Smrg            XftResult result;
39000994698Smrg
39100994698Smrg            pat = XftXlfdParse(fs->x_name, False, False);
39200994698Smrg            XftPatternAddBool(pat, XFT_CORE, fs->core);
39300994698Smrg            match = XftFontMatch(XtDisplay(dw),
39400994698Smrg                                 XScreenNumberOfScreen(dw->core.screen),
39500994698Smrg                                 pat, &result);
39600994698Smrg            XftPatternDestroy(pat);
39700994698Smrg            if (match) {
39800994698Smrg                fs->font = XftFontOpenPattern(XtDisplay(dw), match);
39900994698Smrg                if (!fs->font)
40000994698Smrg                    XftPatternDestroy(match);
40100994698Smrg            }
40200994698Smrg            else
40300994698Smrg                fs->font = 0;
404f80a6dcdSmrg#else
40500994698Smrg            fs->font = XLoadQueryFont(XtDisplay(dw), fs->x_name);
406f80a6dcdSmrg#endif
40700994698Smrg        }
40800994698Smrg        if (!fs->font)
40900994698Smrg            fs->font = dw->dvi.default_font;
410f80a6dcdSmrg    }
411f80a6dcdSmrg    return fs->font;
412f80a6dcdSmrg}
413f80a6dcdSmrg
414f80a6dcdSmrgDviCharNameMap *
41500994698SmrgQueryFontMap(DviWidget dw, int position)
416f80a6dcdSmrg{
41700994698Smrg    DviFontList *f = LookupFontByPosition(dw, position);
418f80a6dcdSmrg
41900994698Smrg    if (f)
42000994698Smrg        return f->char_map;
42100994698Smrg    else
42200994698Smrg        return NULL;
423f80a6dcdSmrg}
424f80a6dcdSmrg
425f80a6dcdSmrgunsigned char *
42600994698SmrgDviCharIsLigature(DviCharNameMap *map, const char *name)
427f80a6dcdSmrg{
4288c7c3c7eSmrg    for (int i = 0; i < DVI_MAX_LIGATURES; i++) {
42900994698Smrg        if (!map->ligatures[i][0])
43000994698Smrg            break;
43100994698Smrg        if (!strcmp(name, map->ligatures[i][0]))
43200994698Smrg            return (unsigned char *) map->ligatures[i][1];
433f80a6dcdSmrg    }
43465912f00Smrg    return NULL;
435f80a6dcdSmrg}
436