1 /*
2 This file contains simple code to manage access to fonts, insuring that
3 library routines access/load fonts only once
4 */
5
6 #include <../src/sys/classes/draw/impls/x/ximpl.h>
7
8 static PetscErrorCode PetscDrawXiInitFonts(PetscDraw_X *);
9 static PetscErrorCode PetscDrawXiLoadFont(PetscDraw_X *, PetscDrawXiFont *);
10 static PetscErrorCode PetscDrawXiMatchFontSize(PetscDrawXiFont *, int, int);
11
12 /*
13 PetscDrawXiFontFixed - Return a pointer to the selected font.
14
15 Warning: Loads a new font for each window. This should be
16 ok because there will never be many windows and the graphics
17 are not intended to be high performance.
18 */
PetscDrawXiFontFixed(PetscDraw_X * XBWin,int w,int h,PetscDrawXiFont ** outfont)19 PetscErrorCode PetscDrawXiFontFixed(PetscDraw_X *XBWin, int w, int h, PetscDrawXiFont **outfont)
20 {
21 static PetscDrawXiFont *curfont = NULL, *font;
22
23 PetscFunctionBegin;
24 if (!curfont) PetscCall(PetscDrawXiInitFonts(XBWin));
25 PetscCall(PetscNew(&font));
26 PetscCall(PetscDrawXiMatchFontSize(font, w, h));
27 PetscCall(PetscDrawXiLoadFont(XBWin, font));
28
29 curfont = font;
30 *outfont = curfont;
31 PetscFunctionReturn(PETSC_SUCCESS);
32 }
33
34 /* this is set by XListFonts at startup */
35 #define NFONTS 20
36 static struct {
37 int w, h, descent;
38 } nfonts[NFONTS];
39 static int act_nfonts = 0;
40
41 /*
42 These routines determine the font to be used based on the requested size,
43 and load it if necessary
44 */
45
PetscDrawXiLoadFont(PetscDraw_X * XBWin,PetscDrawXiFont * font)46 static PetscErrorCode PetscDrawXiLoadFont(PetscDraw_X *XBWin, PetscDrawXiFont *font)
47 {
48 char font_name[100];
49 XFontStruct *FontInfo;
50 XGCValues values;
51
52 PetscFunctionBegin;
53 PetscCall(PetscSNPrintf(font_name, PETSC_STATIC_ARRAY_LENGTH(font_name), "%dx%d", font->font_w, font->font_h));
54 font->fnt = XLoadFont(XBWin->disp, font_name);
55
56 /* The font->descent may not have been set correctly; get it now that
57 the font has been loaded */
58 FontInfo = XQueryFont(XBWin->disp, font->fnt);
59 font->font_descent = FontInfo->descent;
60 font->font_w = FontInfo->max_bounds.rbearing - FontInfo->min_bounds.lbearing;
61 font->font_h = FontInfo->max_bounds.ascent + FontInfo->max_bounds.descent;
62
63 XFreeFontInfo(NULL, FontInfo, 1);
64
65 /* Set the current font in the CG */
66 values.font = font->fnt;
67 XChangeGC(XBWin->disp, XBWin->gc.set, GCFont, &values);
68 PetscFunctionReturn(PETSC_SUCCESS);
69 }
70
71 /* Code to find fonts and their characteristics */
PetscDrawXiInitFonts(PetscDraw_X * XBWin)72 static PetscErrorCode PetscDrawXiInitFonts(PetscDraw_X *XBWin)
73 {
74 char **names;
75 int cnt, i, j;
76 XFontStruct *info;
77
78 PetscFunctionBegin;
79 /* This just gets the most basic fixed-width fonts */
80 names = XListFontsWithInfo(XBWin->disp, "?x??", NFONTS, &cnt, &info);
81 j = 0;
82 for (i = 0; i < cnt; i++) {
83 names[i][1] = '\0';
84 nfonts[j].w = info[i].max_bounds.width;
85 nfonts[j].h = info[i].ascent + info[i].descent;
86 nfonts[j].descent = info[i].descent;
87 if (nfonts[j].w <= 0 || nfonts[j].h <= 0) continue;
88 j++;
89 if (j >= NFONTS) break;
90 }
91 act_nfonts = j;
92 if (cnt > 0) XFreeFontInfo(names, info, cnt);
93
94 /* If the above fails,try this: */
95 if (!act_nfonts) {
96 /* This just gets the most basic fixed-width fonts */
97 names = XListFontsWithInfo(XBWin->disp, "?x", NFONTS, &cnt, &info);
98 j = 0;
99 for (i = 0; i < cnt; i++) {
100 size_t len;
101
102 PetscCall(PetscStrlen(names[i], &len));
103 if (len != 2) continue;
104 names[i][1] = '\0';
105 nfonts[j].w = info[i].max_bounds.width;
106 /* nfonts[j].w = info[i].max_bounds.lbearing + info[i].max_bounds.rbearing; */
107 nfonts[j].h = info[i].ascent + info[i].descent;
108 nfonts[j].descent = info[i].descent;
109 if (nfonts[j].w <= 0 || nfonts[j].h <= 0) continue;
110 j++;
111 if (j >= NFONTS) break;
112 }
113 act_nfonts = j;
114 XFreeFontInfo(names, info, cnt);
115 }
116 PetscFunctionReturn(PETSC_SUCCESS);
117 }
118
PetscDrawXiMatchFontSize(PetscDrawXiFont * font,int w,int h)119 static PetscErrorCode PetscDrawXiMatchFontSize(PetscDrawXiFont *font, int w, int h)
120 {
121 int i, max, imax, tmp;
122
123 PetscFunctionBegin;
124 for (i = 0; i < act_nfonts; i++) {
125 if (nfonts[i].w == w && nfonts[i].h == h) {
126 font->font_w = w;
127 font->font_h = h;
128 font->font_descent = nfonts[i].descent;
129 PetscFunctionReturn(PETSC_SUCCESS);
130 }
131 }
132
133 /* determine closest fit,per max. norm */
134 imax = 0;
135 max = PetscMax(PetscAbsInt(nfonts[0].w - w), PetscAbsInt(nfonts[0].h - h));
136 for (i = 1; i < act_nfonts; i++) {
137 tmp = PetscMax(PetscAbsInt(nfonts[i].w - w), PetscAbsInt(nfonts[i].h - h));
138 if (tmp < max) {
139 max = tmp;
140 imax = i;
141 }
142 }
143
144 /* should use font with closest match */
145 font->font_w = nfonts[imax].w;
146 font->font_h = nfonts[imax].h;
147 font->font_descent = nfonts[imax].descent;
148 PetscFunctionReturn(PETSC_SUCCESS);
149 }
150