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