xref: /petsc/src/sys/classes/draw/impls/x/xtext.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
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   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(0);
32 }
33 
34 /* this is set by XListFonts at startup */
35 #define NFONTS 20
36 static struct { int w, h, descent; } nfonts[NFONTS];
37 static int act_nfonts = 0;
38 
39 /*
40   These routines determine the font to be used based on the requested size,
41   and load it if necessary
42 */
43 
44 static PetscErrorCode PetscDrawXiLoadFont(PetscDraw_X *XBWin, PetscDrawXiFont *font) {
45   char         font_name[100];
46   XFontStruct *FontInfo;
47   XGCValues    values;
48 
49   PetscFunctionBegin;
50   (void)sprintf(font_name, "%dx%d", font->font_w, font->font_h);
51   font->fnt = XLoadFont(XBWin->disp, font_name);
52 
53   /* The font->descent may not have been set correctly; get it now that
54       the font has been loaded */
55   FontInfo           = XQueryFont(XBWin->disp, font->fnt);
56   font->font_descent = FontInfo->descent;
57   font->font_w       = FontInfo->max_bounds.rbearing - FontInfo->min_bounds.lbearing;
58   font->font_h       = FontInfo->max_bounds.ascent + FontInfo->max_bounds.descent;
59 
60   XFreeFontInfo(NULL, FontInfo, 1);
61 
62   /* Set the current font in the CG */
63   values.font = font->fnt;
64   XChangeGC(XBWin->disp, XBWin->gc.set, GCFont, &values);
65   PetscFunctionReturn(0);
66 }
67 
68 /* Code to find fonts and their characteristics */
69 static PetscErrorCode PetscDrawXiInitFonts(PetscDraw_X *XBWin) {
70   char       **names;
71   int          cnt, i, j;
72   XFontStruct *info;
73 
74   PetscFunctionBegin;
75   /* This just gets the most basic fixed-width fonts */
76   names = XListFontsWithInfo(XBWin->disp, "?x??", NFONTS, &cnt, &info);
77   j     = 0;
78   for (i = 0; i < cnt; i++) {
79     names[i][1]       = '\0';
80     nfonts[j].w       = info[i].max_bounds.width;
81     nfonts[j].h       = info[i].ascent + info[i].descent;
82     nfonts[j].descent = info[i].descent;
83     if (nfonts[j].w <= 0 || nfonts[j].h <= 0) continue;
84     j++;
85     if (j >= NFONTS) break;
86   }
87   act_nfonts = j;
88   if (cnt > 0) XFreeFontInfo(names, info, cnt);
89 
90   /* If the above fails,try this: */
91   if (!act_nfonts) {
92     /* This just gets the most basic fixed-width fonts */
93     names = XListFontsWithInfo(XBWin->disp, "?x", NFONTS, &cnt, &info);
94     j     = 0;
95     for (i = 0; i < cnt; i++) {
96       size_t len;
97 
98       PetscCall(PetscStrlen(names[i], &len));
99       if (len != 2) continue;
100       names[i][1]       = '\0';
101       nfonts[j].w       = info[i].max_bounds.width;
102       /* nfonts[j].w         = info[i].max_bounds.lbearing + info[i].max_bounds.rbearing; */
103       nfonts[j].h       = info[i].ascent + info[i].descent;
104       nfonts[j].descent = info[i].descent;
105       if (nfonts[j].w <= 0 || nfonts[j].h <= 0) continue;
106       j++;
107       if (j >= NFONTS) break;
108     }
109     act_nfonts = j;
110     XFreeFontInfo(names, info, cnt);
111   }
112   PetscFunctionReturn(0);
113 }
114 
115 static PetscErrorCode PetscDrawXiMatchFontSize(PetscDrawXiFont *font, int w, int h) {
116   int i, max, imax, tmp;
117 
118   PetscFunctionBegin;
119   for (i = 0; i < act_nfonts; i++) {
120     if (nfonts[i].w == w && nfonts[i].h == h) {
121       font->font_w       = w;
122       font->font_h       = h;
123       font->font_descent = nfonts[i].descent;
124       PetscFunctionReturn(0);
125     }
126   }
127 
128   /* determine closest fit,per max. norm */
129   imax = 0;
130   max  = PetscMax(PetscAbsInt(nfonts[0].w - w), PetscAbsInt(nfonts[0].h - h));
131   for (i = 1; i < act_nfonts; i++) {
132     tmp = PetscMax(PetscAbsInt(nfonts[i].w - w), PetscAbsInt(nfonts[i].h - h));
133     if (tmp < max) {
134       max  = tmp;
135       imax = i;
136     }
137   }
138 
139   /* should use font with closest match */
140   font->font_w       = nfonts[imax].w;
141   font->font_h       = nfonts[imax].h;
142   font->font_descent = nfonts[imax].descent;
143   PetscFunctionReturn(0);
144 }
145