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