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