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