xref: /petsc/src/sys/classes/draw/impls/x/xtext.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888) !
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 */
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 
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 */
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 
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