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