fontutils.c revision 50027b5b
150027b5bSmrg/* $XTermId: fontutils.c,v 1.712 2022/02/23 00:46:08 tom Exp $ */ 2d522f475Smrg 30bd37d32Smrg/* 450027b5bSmrg * Copyright 1998-2021,2022 by Thomas E. Dickey 50bd37d32Smrg * 60bd37d32Smrg * All Rights Reserved 70bd37d32Smrg * 80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a 90bd37d32Smrg * copy of this software and associated documentation files (the 100bd37d32Smrg * "Software"), to deal in the Software without restriction, including 110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish, 120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to 130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to 140bd37d32Smrg * the following conditions: 150bd37d32Smrg * 160bd37d32Smrg * The above copyright notice and this permission notice shall be included 170bd37d32Smrg * in all copies or substantial portions of the Software. 180bd37d32Smrg * 190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 260bd37d32Smrg * 270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright 280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the 290bd37d32Smrg * sale, use or other dealings in this Software without prior written 300bd37d32Smrg * authorization. 310bd37d32Smrg */ 32d522f475Smrg 33d522f475Smrg/* 34d522f475Smrg * A portion of this module (for FontNameProperties) was adapted from EMU 1.3; 35d522f475Smrg * it constructs font names with specific properties changed, e.g., for bold 36d522f475Smrg * and double-size characters. 37d522f475Smrg */ 38d522f475Smrg 39d522f475Smrg#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field) 40d522f475Smrg 41d522f475Smrg#include <fontutils.h> 42d522f475Smrg#include <X11/Xmu/Drawing.h> 4320d2c4d2Smrg#include <X11/Xmu/CharSet.h> 44d522f475Smrg 45d522f475Smrg#include <main.h> 46d522f475Smrg#include <data.h> 47d522f475Smrg#include <menu.h> 48d522f475Smrg#include <xstrings.h> 49d522f475Smrg#include <xterm.h> 50d522f475Smrg 51d522f475Smrg#include <stdio.h> 52d522f475Smrg#include <ctype.h> 53d522f475Smrg 54d4fba8b9Smrg#define NoFontWarning(data) (data)->warn = fwAlways 55d4fba8b9Smrg 560bd37d32Smrg#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 57d4fba8b9Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((double)((screen)->scale_height * (float) (src))) 580bd37d32Smrg 59d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */ 60d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 61d522f475Smrg (((cs)->rbearing|(cs)->lbearing| \ 62d522f475Smrg (cs)->ascent|(cs)->descent) == 0)) 63d522f475Smrg 64fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 65d522f475Smrg{ \ 66fa3f02f3Smrg cs = 0; \ 67d522f475Smrg if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 68d522f475Smrg if (fs->per_char == NULL) { \ 69d522f475Smrg cs = &fs->min_bounds; \ 70d522f475Smrg } else { \ 71d522f475Smrg cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 72d522f475Smrg } \ 73fa3f02f3Smrg if (CI_NONEXISTCHAR(cs)) cs = 0; \ 74d522f475Smrg } \ 75d522f475Smrg} 76d522f475Smrg 77fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 78d522f475Smrg{ \ 79fa3f02f3Smrg cs = 0; \ 80d522f475Smrg if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 81d522f475Smrg col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 82d522f475Smrg if (fs->per_char == NULL) { \ 83d522f475Smrg cs = &fs->min_bounds; \ 84d522f475Smrg } else { \ 85d522f475Smrg cs = &fs->per_char[((row - fs->min_byte1) * \ 86d522f475Smrg (fs->max_char_or_byte2 - \ 87d522f475Smrg fs->min_char_or_byte2 + 1)) + \ 88d522f475Smrg (col - fs->min_char_or_byte2)]; \ 89d522f475Smrg } \ 90fa3f02f3Smrg if (CI_NONEXISTCHAR(cs)) cs = 0; \ 91d522f475Smrg } \ 92d522f475Smrg} 93d522f475Smrg 949a64e1c5Smrg#define FREE_FNAME(field) \ 959a64e1c5Smrg if (fonts == 0 || myfonts.field != fonts->field) { \ 969a64e1c5Smrg FREE_STRING(myfonts.field); \ 979a64e1c5Smrg myfonts.field = 0; \ 989a64e1c5Smrg } 999a64e1c5Smrg 100d522f475Smrg/* 101d522f475Smrg * A structure to hold the relevant properties from a font 102d522f475Smrg * we need to make a well formed font name for it. 103d522f475Smrg */ 104d522f475Smrgtypedef struct { 105d522f475Smrg /* registry, foundry, family */ 1069a64e1c5Smrg const char *beginning; 107d522f475Smrg /* weight */ 1089a64e1c5Smrg const char *weight; 109d522f475Smrg /* slant */ 1109a64e1c5Smrg const char *slant; 111d522f475Smrg /* wideness */ 1129a64e1c5Smrg const char *wideness; 113d522f475Smrg /* add style */ 1149a64e1c5Smrg const char *add_style; 115d522f475Smrg int pixel_size; 1169a64e1c5Smrg const char *point_size; 117d522f475Smrg int res_x; 118d522f475Smrg int res_y; 1199a64e1c5Smrg const char *spacing; 120d522f475Smrg int average_width; 121d522f475Smrg /* charset registry, charset encoding */ 122d522f475Smrg char *end; 123d522f475Smrg} FontNameProperties; 124d522f475Smrg 125d4fba8b9Smrg#if OPT_WIDE_CHARS && (OPT_RENDERFONT || (OPT_TRACE > 1)) 126d4fba8b9Smrg#define MY_UCS(code,high,wide,name) { code, high, wide, #name } 127d4fba8b9Smrgstatic const struct { 128d4fba8b9Smrg unsigned code, high, wide; 129d4fba8b9Smrg const char *name; 130d4fba8b9Smrg} unicode_boxes[] = { 131d4fba8b9Smrg 132d4fba8b9Smrg MY_UCS(0x2500, 0, 1, box drawings light horizontal), 133d4fba8b9Smrg MY_UCS(0x2502, 1, 0, box drawings light vertical), 134d4fba8b9Smrg MY_UCS(0x250c, 2, 2, box drawings light down and right), 135d4fba8b9Smrg MY_UCS(0x2510, 2, 2, box drawings light down and left), 136d4fba8b9Smrg MY_UCS(0x2514, 2, 2, box drawings light up and right), 137d4fba8b9Smrg MY_UCS(0x2518, 2, 2, box drawings light up and left), 138d4fba8b9Smrg MY_UCS(0x251c, 1, 2, box drawings light vertical and right), 139d4fba8b9Smrg MY_UCS(0x2524, 1, 2, box drawings light vertical and left), 140d4fba8b9Smrg MY_UCS(0x252c, 2, 1, box drawings light down and horizontal), 141d4fba8b9Smrg MY_UCS(0x2534, 2, 1, box drawings light up and horizontal), 142d4fba8b9Smrg MY_UCS(0x253c, 1, 1, box drawings light vertical and horizontal), 143d4fba8b9Smrg { 144d4fba8b9Smrg 0, 0, 0, NULL 145d4fba8b9Smrg } 146d4fba8b9Smrg}; 147d4fba8b9Smrg 148d4fba8b9Smrg#undef MY_UCS 149d4fba8b9Smrg#endif /* OPT_WIDE_CHARS */ 150d4fba8b9Smrg 151dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 152dfb07bc7Smrgstatic Boolean merge_sublist(char ***, char **); 153dfb07bc7Smrg#endif 154dfb07bc7Smrg 155dfb07bc7Smrgstatic void save2FontList(XtermWidget, const char *, XtermFontNames *, 156dfb07bc7Smrg VTFontEnum, const char *, Bool); 157dfb07bc7Smrg 1580bd37d32Smrg#if OPT_RENDERFONT 1590bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int); 1600bd37d32Smrg#endif 1610bd37d32Smrg 162d522f475Smrg#if OPT_SHIFT_FONTS 1630bd37d32Smrgstatic int lookupOneFontSize(XtermWidget, int); 164d522f475Smrg#endif 165d522f475Smrg 166d4fba8b9Smrg#if OPT_TRACE 167d4fba8b9Smrgstatic void 168d4fba8b9Smrgset_font_height(TScreen *screen, VTwin *win, int height) 169d4fba8b9Smrg{ 170d4fba8b9Smrg SetFontHeight(screen, win, height); 171d4fba8b9Smrg TRACE(("SetFontHeight %d\n", win->f_height)); 172d4fba8b9Smrg#undef SetFontHeight 173d4fba8b9Smrg#define SetFontHeight(screen, win, height) set_font_height(screen, win, height) 174d4fba8b9Smrg} 175d4fba8b9Smrg 176d4fba8b9Smrgstatic void 177d4fba8b9Smrgset_font_width(TScreen *screen, VTwin *win, int width) 178d4fba8b9Smrg{ 179d4fba8b9Smrg (void) screen; 180d4fba8b9Smrg SetFontWidth(screen, win, width); 181d4fba8b9Smrg TRACE(("SetFontWidth %d\n", win->f_width)); 182d4fba8b9Smrg#undef SetFontWidth 183c48a5815Smrg#define SetFontWidth(screen, win, width) set_font_width(screen, win, width) 184d4fba8b9Smrg} 185d4fba8b9Smrg#endif 186d4fba8b9Smrg 187fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS 1882eaa94a1Schristosstatic unsigned 1899a64e1c5SmrgcountGlyphs(XFontStruct *fp) 190d522f475Smrg{ 191d522f475Smrg unsigned count = 0; 192d522f475Smrg 193d522f475Smrg if (fp != 0) { 194d522f475Smrg if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 195fa3f02f3Smrg count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1; 196d522f475Smrg } else if (fp->min_char_or_byte2 < 256 197d522f475Smrg && fp->max_char_or_byte2 < 256) { 198d522f475Smrg unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 199d522f475Smrg unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 200d522f475Smrg count = last + 1 - first; 201d522f475Smrg } 202d522f475Smrg } 203d522f475Smrg return count; 204d522f475Smrg} 205fa3f02f3Smrg#endif 206d522f475Smrg 207fa3f02f3Smrg#if OPT_WIDE_CHARS 208d522f475Smrg/* 209d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many 210d522f475Smrg * glyphs as the wide font. The counts should be the same, but settle for 211d522f475Smrg * filtering out the worst of the font mismatches. 212d522f475Smrg */ 213d522f475Smrgstatic Bool 2149a64e1c5SmrgcompatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs) 215d522f475Smrg{ 216d522f475Smrg unsigned count_w = countGlyphs(wfs); 217d522f475Smrg unsigned count_wb = countGlyphs(wbfs); 218d522f475Smrg if (count_w <= 256 || 219d522f475Smrg count_wb <= 256 || 220d522f475Smrg ((count_w / 4) * 3) > count_wb) { 221d522f475Smrg TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 222d522f475Smrg count_w, count_wb)); 223d522f475Smrg return False; 224d522f475Smrg } 225d522f475Smrg return True; 226d522f475Smrg} 227d522f475Smrg#endif /* OPT_WIDE_CHARS */ 228d522f475Smrg 22920d2c4d2Smrg#if OPT_BOX_CHARS 23020d2c4d2Smrgstatic void 23120d2c4d2SmrgsetupPackedFonts(XtermWidget xw) 23220d2c4d2Smrg{ 23320d2c4d2Smrg TScreen *screen = TScreenOf(xw); 23420d2c4d2Smrg Bool value = False; 23520d2c4d2Smrg 23620d2c4d2Smrg#if OPT_RENDERFONT 2370bd37d32Smrg if (xw->work.render_font == True) { 238dfb07bc7Smrg int e; 23920d2c4d2Smrg 240dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 241dfb07bc7Smrg XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number); 242dfb07bc7Smrg if (data != 0) { 243dfb07bc7Smrg if (data->map.mixed) { 244dfb07bc7Smrg screen->allow_packing = True; 245dfb07bc7Smrg break; 246dfb07bc7Smrg } 247dfb07bc7Smrg } 248dfb07bc7Smrg } 24920d2c4d2Smrg } 25020d2c4d2Smrg#endif /* OPT_RENDERFONT */ 25120d2c4d2Smrg 25220d2c4d2Smrg value = screen->allow_packing; 25320d2c4d2Smrg 25420d2c4d2Smrg SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 25520d2c4d2Smrg} 25620d2c4d2Smrg#endif 25720d2c4d2Smrg 258d4fba8b9Smrgtypedef struct _nameList { 259d4fba8b9Smrg struct _nameList *next; 260d4fba8b9Smrg char *name; 261d4fba8b9Smrg} NameList; 262d4fba8b9Smrg 263d4fba8b9Smrgstatic NameList *derived_fonts; 264d4fba8b9Smrg 265d4fba8b9Smrgstatic Boolean 266d4fba8b9Smrgis_derived_font_name(const char *name) 267d4fba8b9Smrg{ 268d4fba8b9Smrg Boolean result = False; 269d4fba8b9Smrg NameList *list; 270d4fba8b9Smrg if (!IsEmpty(name)) { 271d4fba8b9Smrg for (list = derived_fonts; list != 0; list = list->next) { 272d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 273d4fba8b9Smrg result = True; 274d4fba8b9Smrg break; 275d4fba8b9Smrg } 276d4fba8b9Smrg } 277d4fba8b9Smrg } 278d4fba8b9Smrg return result; 279d4fba8b9Smrg} 280d4fba8b9Smrg 281d4fba8b9Smrgvoid 282d4fba8b9SmrgxtermDerivedFont(const char *name) 283d4fba8b9Smrg{ 284d4fba8b9Smrg if (!IsEmpty(name) && !is_derived_font_name(name)) { 285d4fba8b9Smrg NameList *list = TypeCalloc(NameList); 286d4fba8b9Smrg list->name = x_strdup(name); 287d4fba8b9Smrg list->next = derived_fonts; 288d4fba8b9Smrg derived_fonts = list; 289d4fba8b9Smrg } 290d4fba8b9Smrg} 291d4fba8b9Smrg 292d522f475Smrg/* 293d522f475Smrg * Returns the fields from start to stop in a dash- separated string. This 2949a64e1c5Smrg * function will modify the source, putting '\0's in the appropriate place and 295d522f475Smrg * moving the beginning forward to after the '\0' 296d522f475Smrg * 297d522f475Smrg * This will NOT work for the last field (but we won't need it). 298d522f475Smrg */ 299d522f475Smrgstatic char * 300d522f475Smrgn_fields(char **source, int start, int stop) 301d522f475Smrg{ 302d522f475Smrg int i; 303d522f475Smrg char *str, *str1; 304d522f475Smrg 305d522f475Smrg /* 306d522f475Smrg * find the start-1th dash 307d522f475Smrg */ 3089a64e1c5Smrg for (i = start - 1, str = *source; i; i--, str++) { 309d522f475Smrg if ((str = strchr(str, '-')) == 0) 310d522f475Smrg return 0; 3119a64e1c5Smrg } 312d522f475Smrg 313d522f475Smrg /* 314d522f475Smrg * find the stopth dash 315d522f475Smrg */ 3169a64e1c5Smrg for (i = stop - start + 1, str1 = str; i; i--, str1++) { 317d522f475Smrg if ((str1 = strchr(str1, '-')) == 0) 318d522f475Smrg return 0; 3199a64e1c5Smrg } 320d522f475Smrg 321d522f475Smrg /* 322d522f475Smrg * put a \0 at the end of the fields 323d522f475Smrg */ 324d522f475Smrg *(str1 - 1) = '\0'; 325d522f475Smrg 326d522f475Smrg /* 327d522f475Smrg * move source forward 328d522f475Smrg */ 329d522f475Smrg *source = str1; 330d522f475Smrg 331d522f475Smrg return str; 332d522f475Smrg} 333d522f475Smrg 334956cc18dSsnjstatic Boolean 335956cc18dSsnjcheck_fontname(const char *name) 336956cc18dSsnj{ 337956cc18dSsnj Boolean result = True; 338956cc18dSsnj 339492d43a5Smrg if (IsEmpty(name)) { 340956cc18dSsnj TRACE(("fontname missing\n")); 341956cc18dSsnj result = False; 342956cc18dSsnj } 343956cc18dSsnj return result; 344956cc18dSsnj} 345956cc18dSsnj 346d522f475Smrg/* 347d522f475Smrg * Gets the font properties from a given font structure. We use the FONT name 348d522f475Smrg * to find them out, since that seems easier. 349d522f475Smrg * 350d522f475Smrg * Returns a pointer to a static FontNameProperties structure 351d522f475Smrg * or NULL on error. 352d522f475Smrg */ 353d522f475Smrgstatic FontNameProperties * 3549a64e1c5Smrgget_font_name_props(Display *dpy, XFontStruct *fs, char **result) 355d522f475Smrg{ 356d522f475Smrg static FontNameProperties props; 357d522f475Smrg static char *last_name; 358d522f475Smrg 359d4fba8b9Smrg Atom fontatom; 360d4fba8b9Smrg char *name; 361d522f475Smrg char *str; 362d522f475Smrg 363d4fba8b9Smrg if (fs == NULL) 364d4fba8b9Smrg return NULL; 365d4fba8b9Smrg 366d522f475Smrg /* 367d522f475Smrg * first get the full font name 368d522f475Smrg */ 369d4fba8b9Smrg name = 0; 370d4fba8b9Smrg fontatom = XInternAtom(dpy, "FONT", False); 37120d2c4d2Smrg if (fontatom != 0) { 372037a25ddSmrg XFontProp *fp; 373037a25ddSmrg int i; 374037a25ddSmrg 37520d2c4d2Smrg for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 37620d2c4d2Smrg if (fp->name == fontatom) { 37720d2c4d2Smrg name = XGetAtomName(dpy, fp->card32); 37820d2c4d2Smrg break; 37920d2c4d2Smrg } 38020d2c4d2Smrg } 38120d2c4d2Smrg } 382d522f475Smrg 383d522f475Smrg if (name == 0) 384d522f475Smrg return 0; 385d522f475Smrg 386d522f475Smrg /* 387d522f475Smrg * XGetAtomName allocates memory - don't leak 388d522f475Smrg */ 389d4fba8b9Smrg XFree(last_name); 390d522f475Smrg last_name = name; 391d522f475Smrg 392d522f475Smrg if (result != 0) { 393956cc18dSsnj if (!check_fontname(name)) 394d522f475Smrg return 0; 395d4fba8b9Smrg free(*result); 3960bd37d32Smrg *result = x_strdup(name); 397d522f475Smrg } 398d522f475Smrg 399d522f475Smrg /* 400d522f475Smrg * Now split it up into parts and put them in 401d522f475Smrg * their places. Since we are using parts of 402d522f475Smrg * the original string, we must not free the Atom Name 403d522f475Smrg */ 404d522f475Smrg 405d522f475Smrg /* registry, foundry, family */ 406d522f475Smrg if ((props.beginning = n_fields(&name, 1, 3)) == 0) 407d522f475Smrg return 0; 408d522f475Smrg 409d522f475Smrg /* weight is the next */ 410d522f475Smrg if ((props.weight = n_fields(&name, 1, 1)) == 0) 411d522f475Smrg return 0; 412d522f475Smrg 413d522f475Smrg /* slant */ 414d522f475Smrg if ((props.slant = n_fields(&name, 1, 1)) == 0) 415d522f475Smrg return 0; 416d522f475Smrg 417d522f475Smrg /* width */ 418d522f475Smrg if ((props.wideness = n_fields(&name, 1, 1)) == 0) 419d522f475Smrg return 0; 420d522f475Smrg 421d522f475Smrg /* add style */ 422d522f475Smrg if ((props.add_style = n_fields(&name, 1, 1)) == 0) 423d522f475Smrg return 0; 424d522f475Smrg 425d522f475Smrg /* pixel size */ 426d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 427d522f475Smrg return 0; 428d522f475Smrg if ((props.pixel_size = atoi(str)) == 0) 429d522f475Smrg return 0; 430d522f475Smrg 431d522f475Smrg /* point size */ 432d522f475Smrg if ((props.point_size = n_fields(&name, 1, 1)) == 0) 433d522f475Smrg return 0; 434d522f475Smrg 435d522f475Smrg /* res_x */ 436d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 437d522f475Smrg return 0; 438d522f475Smrg if ((props.res_x = atoi(str)) == 0) 439d522f475Smrg return 0; 440d522f475Smrg 441d522f475Smrg /* res_y */ 442d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 443d522f475Smrg return 0; 444d522f475Smrg if ((props.res_y = atoi(str)) == 0) 445d522f475Smrg return 0; 446d522f475Smrg 447d522f475Smrg /* spacing */ 448d522f475Smrg if ((props.spacing = n_fields(&name, 1, 1)) == 0) 449d522f475Smrg return 0; 450d522f475Smrg 451d522f475Smrg /* average width */ 452d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 453d522f475Smrg return 0; 454d522f475Smrg if ((props.average_width = atoi(str)) == 0) 455d522f475Smrg return 0; 456d522f475Smrg 457d522f475Smrg /* the rest: charset registry and charset encoding */ 458d522f475Smrg props.end = name; 459d522f475Smrg 460d522f475Smrg return &props; 461d522f475Smrg} 462d522f475Smrg 463d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1) 464d522f475Smrg 465d522f475Smrgstatic void 466956cc18dSsnjalloca_fontname(char **result, size_t next) 467d522f475Smrg{ 468956cc18dSsnj size_t last = (*result != 0) ? strlen(*result) : 0; 469956cc18dSsnj size_t have = (*result != 0) ? ALLOCHUNK(last) : 0; 470956cc18dSsnj size_t want = last + next + 2; 471d522f475Smrg 472d522f475Smrg if (want >= have) { 47350027b5bSmrg char *save = *result; 474d522f475Smrg want = ALLOCHUNK(want); 475d522f475Smrg if (last != 0) { 476d522f475Smrg *result = TypeRealloc(char, want, *result); 4779a64e1c5Smrg if (*result == 0) 4789a64e1c5Smrg free(save); 479d522f475Smrg } else { 48050027b5bSmrg if ((*result = TypeMallocN(char, want)) != 0) { 48150027b5bSmrg free(save); 482d522f475Smrg **result = '\0'; 48350027b5bSmrg } 484d522f475Smrg } 485d522f475Smrg } 486d522f475Smrg} 487d522f475Smrg 488d522f475Smrgstatic void 48920d2c4d2Smrgappend_fontname_str(char **result, const char *value) 490d522f475Smrg{ 491d522f475Smrg if (value == 0) 492d522f475Smrg value = "*"; 493d522f475Smrg alloca_fontname(result, strlen(value)); 494d522f475Smrg if (*result != 0) { 495d522f475Smrg if (**result != '\0') 496d522f475Smrg strcat(*result, "-"); 497d522f475Smrg strcat(*result, value); 498d522f475Smrg } 499d522f475Smrg} 500d522f475Smrg 501d522f475Smrgstatic void 502d522f475Smrgappend_fontname_num(char **result, int value) 503d522f475Smrg{ 504d522f475Smrg if (value < 0) { 505d522f475Smrg append_fontname_str(result, "*"); 506d522f475Smrg } else { 507d522f475Smrg char temp[100]; 508d522f475Smrg sprintf(temp, "%d", value); 509d522f475Smrg append_fontname_str(result, temp); 510d522f475Smrg } 511d522f475Smrg} 512d522f475Smrg 513d522f475Smrg/* 514d522f475Smrg * Take the given font props and try to make a well formed font name specifying 515d522f475Smrg * the same base font and size and everything, but with different weight/width 516d522f475Smrg * according to the parameters. The return value is allocated, should be freed 517d522f475Smrg * by the caller. 518d522f475Smrg */ 519d522f475Smrgstatic char * 5209a64e1c5Smrgderive_font_name(FontNameProperties *props, 52120d2c4d2Smrg const char *use_weight, 522d522f475Smrg int use_average_width, 52320d2c4d2Smrg const char *use_encoding) 524d522f475Smrg{ 525d522f475Smrg char *result = 0; 526d522f475Smrg 527d522f475Smrg append_fontname_str(&result, props->beginning); 528d522f475Smrg append_fontname_str(&result, use_weight); 529d522f475Smrg append_fontname_str(&result, props->slant); 530d522f475Smrg append_fontname_str(&result, 0); 531d522f475Smrg append_fontname_str(&result, 0); 532d522f475Smrg append_fontname_num(&result, props->pixel_size); 533d522f475Smrg append_fontname_str(&result, props->point_size); 534d522f475Smrg append_fontname_num(&result, props->res_x); 535d522f475Smrg append_fontname_num(&result, props->res_y); 536d522f475Smrg append_fontname_str(&result, props->spacing); 537d522f475Smrg append_fontname_num(&result, use_average_width); 538d522f475Smrg append_fontname_str(&result, use_encoding); 539d522f475Smrg 540d4fba8b9Smrg xtermDerivedFont(result); 541d522f475Smrg return result; 542d522f475Smrg} 543d522f475Smrg 544d522f475Smrgstatic char * 5459a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width) 546d522f475Smrg{ 547d522f475Smrg return derive_font_name(props, "bold", use_average_width, props->end); 548d522f475Smrg} 549d522f475Smrg 5509a64e1c5Smrg#if OPT_WIDE_ATTRS 5519a64e1c5Smrgstatic char * 552dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant) 5539a64e1c5Smrg{ 5549a64e1c5Smrg FontNameProperties myprops = *props; 555dfb07bc7Smrg myprops.slant = slant; 556dfb07bc7Smrg return derive_font_name(&myprops, props->weight, myprops.average_width, props->end); 557dfb07bc7Smrg} 558dfb07bc7Smrg 559dfb07bc7Smrgstatic Boolean 560dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data) 561dfb07bc7Smrg{ 562dfb07bc7Smrg static const char *slant[] = 563dfb07bc7Smrg { 564dfb07bc7Smrg "o", 565dfb07bc7Smrg "i" 566dfb07bc7Smrg }; 567dfb07bc7Smrg Cardinal pass; 568dfb07bc7Smrg Boolean result = False; 569dfb07bc7Smrg 570d4fba8b9Smrg NoFontWarning(data); 571dfb07bc7Smrg for (pass = 0; pass < XtNumber(slant); ++pass) { 572d4fba8b9Smrg char *name; 573dfb07bc7Smrg if ((name = italic_font_name(fp, slant[pass])) != 0) { 574dfb07bc7Smrg TRACE(("open_italic_font %s %s\n", 575dfb07bc7Smrg whichFontEnum((VTFontEnum) n), name)); 576dfb07bc7Smrg if (xtermOpenFont(xw, name, data, False)) { 577dfb07bc7Smrg result = (data->fs != 0); 578dfb07bc7Smrg#if OPT_REPORT_FONTS 579dfb07bc7Smrg if (resource.reportFonts) { 580dfb07bc7Smrg printf("opened italic version of %s:\n\t%s\n", 581d4fba8b9Smrg whichFontEnum((VTFontEnum) n), 582dfb07bc7Smrg name); 583dfb07bc7Smrg } 584dfb07bc7Smrg#endif 585dfb07bc7Smrg } 586dfb07bc7Smrg free(name); 587dfb07bc7Smrg if (result) 588dfb07bc7Smrg break; 589dfb07bc7Smrg } 590dfb07bc7Smrg } 591dfb07bc7Smrg#if OPT_TRACE 592dfb07bc7Smrg if (result) { 593dfb07bc7Smrg XFontStruct *fs = data->fs; 594dfb07bc7Smrg if (fs != 0) { 595dfb07bc7Smrg TRACE(("...actual size %dx%d (ascent %d, descent %d)\n", 596dfb07bc7Smrg fs->ascent + 597dfb07bc7Smrg fs->descent, 598dfb07bc7Smrg fs->max_bounds.width, 599dfb07bc7Smrg fs->ascent, 600dfb07bc7Smrg fs->descent)); 601dfb07bc7Smrg } 602dfb07bc7Smrg } 603dfb07bc7Smrg#endif 604dfb07bc7Smrg return result; 6059a64e1c5Smrg} 6069a64e1c5Smrg#endif 6079a64e1c5Smrg 608d522f475Smrg#if OPT_WIDE_CHARS 609d522f475Smrg#define derive_wide_font(props, weight) \ 610d522f475Smrg derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 611d522f475Smrg 612d522f475Smrgstatic char * 6139a64e1c5Smrgwide_font_name(FontNameProperties *props) 614d522f475Smrg{ 615d522f475Smrg return derive_wide_font(props, "medium"); 616d522f475Smrg} 617d522f475Smrg 618d522f475Smrgstatic char * 6199a64e1c5Smrgwidebold_font_name(FontNameProperties *props) 620d522f475Smrg{ 621d522f475Smrg return derive_wide_font(props, "bold"); 622d522f475Smrg} 623d522f475Smrg#endif /* OPT_WIDE_CHARS */ 624d522f475Smrg 625d522f475Smrg#if OPT_DEC_CHRSET 626d522f475Smrg/* 627d522f475Smrg * Take the given font props and try to make a well formed font name specifying 628d522f475Smrg * the same base font but changed depending on the given attributes and chrset. 629d522f475Smrg * 630d522f475Smrg * For double width fonts, we just double the X-resolution, for double height 631d522f475Smrg * fonts we double the pixel-size and Y-resolution 632d522f475Smrg */ 633d522f475Smrgchar * 634d4fba8b9SmrgxtermSpecialFont(XTermDraw * params) 635d522f475Smrg{ 636d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 637d522f475Smrg#if OPT_TRACE 638d522f475Smrg static char old_spacing[80]; 639d522f475Smrg static FontNameProperties old_props; 640d522f475Smrg#endif 641d522f475Smrg FontNameProperties *props; 642d522f475Smrg char *result = 0; 64320d2c4d2Smrg const char *weight; 644d522f475Smrg int pixel_size; 645d522f475Smrg int res_x; 646d522f475Smrg int res_y; 647d522f475Smrg 648dfb07bc7Smrg props = get_font_name_props(screen->display, 649d4fba8b9Smrg GetNormalFont(screen, fNorm)->fs, 0); 650d522f475Smrg if (props == 0) 651d522f475Smrg return result; 652d522f475Smrg 653d522f475Smrg pixel_size = props->pixel_size; 654d522f475Smrg res_x = props->res_x; 655d522f475Smrg res_y = props->res_y; 656d4fba8b9Smrg if (params->attr_flags & BOLD) 657d522f475Smrg weight = "bold"; 658d522f475Smrg else 659d522f475Smrg weight = props->weight; 660d522f475Smrg 661d4fba8b9Smrg if (CSET_DOUBLE(params->this_chrset)) 662d522f475Smrg res_x *= 2; 663d522f475Smrg 664d4fba8b9Smrg if (params->this_chrset == CSET_DHL_TOP 665d4fba8b9Smrg || params->this_chrset == CSET_DHL_BOT) { 666d522f475Smrg res_y *= 2; 667d522f475Smrg pixel_size *= 2; 668d522f475Smrg } 669d522f475Smrg#if OPT_TRACE 670d522f475Smrg if (old_props.res_x != res_x 671d522f475Smrg || old_props.res_x != res_y 672d522f475Smrg || old_props.pixel_size != pixel_size 673d522f475Smrg || strcmp(old_props.spacing, props->spacing)) { 6749a64e1c5Smrg TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n", 675d4fba8b9Smrg params->attr_flags, params->draw_flags, params->this_chrset)); 676d522f475Smrg TRACE(("res_x = %d\n", res_x)); 677d522f475Smrg TRACE(("res_y = %d\n", res_y)); 678d522f475Smrg TRACE(("point_size = %s\n", props->point_size)); 679d522f475Smrg TRACE(("pixel_size = %d\n", pixel_size)); 680d522f475Smrg TRACE(("spacing = %s\n", props->spacing)); 681d522f475Smrg old_props.res_x = res_x; 682037a25ddSmrg old_props.res_y = res_y; 683d522f475Smrg old_props.pixel_size = pixel_size; 6840bd37d32Smrg old_props.spacing = old_spacing; 6850bd37d32Smrg sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 686d522f475Smrg } 687d522f475Smrg#endif 688d522f475Smrg 689d522f475Smrg append_fontname_str(&result, props->beginning); 690d522f475Smrg append_fontname_str(&result, weight); 691d522f475Smrg append_fontname_str(&result, props->slant); 692d522f475Smrg append_fontname_str(&result, props->wideness); 693d522f475Smrg append_fontname_str(&result, props->add_style); 694d522f475Smrg append_fontname_num(&result, pixel_size); 695d522f475Smrg append_fontname_str(&result, props->point_size); 696d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x); 697d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y); 698d522f475Smrg append_fontname_str(&result, props->spacing); 699d522f475Smrg append_fontname_str(&result, 0); 700d522f475Smrg append_fontname_str(&result, props->end); 701d522f475Smrg 702d4fba8b9Smrg xtermDerivedFont(result); 703d522f475Smrg return result; 704d522f475Smrg} 705d522f475Smrg#endif /* OPT_DEC_CHRSET */ 706d522f475Smrg 707d522f475Smrg/* 708d522f475Smrg * Case-independent comparison for font-names, including wildcards. 709d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 710d522f475Smrg * to use it). 711d522f475Smrg */ 712d522f475Smrgstatic Bool 713492d43a5Smrgsame_font_name(const char *pattern, const char *match) 714d522f475Smrg{ 715956cc18dSsnj Bool result = False; 716956cc18dSsnj 717956cc18dSsnj if (pattern && match) { 718956cc18dSsnj while (*pattern && *match) { 719956cc18dSsnj if (*pattern == *match) { 720956cc18dSsnj pattern++; 721956cc18dSsnj match++; 722956cc18dSsnj } else if (*pattern == '*' || *match == '*') { 723956cc18dSsnj if (same_font_name(pattern + 1, match)) { 724956cc18dSsnj return True; 725956cc18dSsnj } else if (same_font_name(pattern, match + 1)) { 726956cc18dSsnj return True; 727956cc18dSsnj } else { 728956cc18dSsnj return False; 729956cc18dSsnj } 730d522f475Smrg } else { 731956cc18dSsnj int p = x_toupper(*pattern++); 732956cc18dSsnj int m = x_toupper(*match++); 733956cc18dSsnj if (p != m) 734956cc18dSsnj return False; 735d522f475Smrg } 736d522f475Smrg } 737956cc18dSsnj result = (*pattern == *match); /* both should be NUL */ 738d522f475Smrg } 739956cc18dSsnj return result; 740d522f475Smrg} 741d522f475Smrg 742d522f475Smrg/* 743d522f475Smrg * Double-check the fontname that we asked for versus what the font server 744d522f475Smrg * actually gave us. The larger fixed fonts do not always have a matching bold 745d522f475Smrg * font, and the font server may try to scale another font or otherwise 746d522f475Smrg * substitute a mismatched font. 747d522f475Smrg * 748d522f475Smrg * If we cannot get what we requested, we will fallback to the original 749d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel 750d522f475Smrg * offset. 751d522f475Smrg */ 752d522f475Smrgstatic int 7539a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested) 754d522f475Smrg{ 7550bd37d32Smrg char *actual = 0; 756d522f475Smrg int got; 757d522f475Smrg 7580bd37d32Smrg if (get_font_name_props(dpy, fs, &actual) == 0) 759d522f475Smrg got = 0; 760d522f475Smrg else 761d522f475Smrg got = same_font_name(requested, actual); 7620bd37d32Smrg free(actual); 763d522f475Smrg return got; 764d522f475Smrg} 765d522f475Smrg 7669a64e1c5Smrg/* 7679a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able 7689a64e1c5Smrg * to check for missing glyphs in a comparable manner. 7699a64e1c5Smrg */ 7709a64e1c5Smrgstatic int 7719a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold) 7729a64e1c5Smrg{ 7739a64e1c5Smrg#define DATA "comparable_metrics: " 7749a64e1c5Smrg int result = 0; 7759a64e1c5Smrg 776dfb07bc7Smrg if (normal == 0 || bold == 0) { 777dfb07bc7Smrg ; 778dfb07bc7Smrg } else if (normal->all_chars_exist) { 7799a64e1c5Smrg if (bold->all_chars_exist) { 7809a64e1c5Smrg result = 1; 7819a64e1c5Smrg } else { 7829a64e1c5Smrg TRACE((DATA "all chars exist in normal font, but not in bold\n")); 7839a64e1c5Smrg } 7849a64e1c5Smrg } else if (normal->per_char != 0) { 7859a64e1c5Smrg if (bold->per_char != 0) { 7869a64e1c5Smrg result = 1; 7879a64e1c5Smrg } else { 7889a64e1c5Smrg TRACE((DATA "normal font has per-char metrics, but not bold\n")); 7899a64e1c5Smrg } 7909a64e1c5Smrg } else { 7919a64e1c5Smrg TRACE((DATA "normal font is not very good!\n")); 7929a64e1c5Smrg result = 1; /* give in (we're not going in reverse) */ 7939a64e1c5Smrg } 7949a64e1c5Smrg return result; 7959a64e1c5Smrg#undef DATA 7969a64e1c5Smrg} 7979a64e1c5Smrg 798d522f475Smrg/* 799d522f475Smrg * If the font server tries to adjust another font, it may not adjust it 800d522f475Smrg * properly. Check that the bounding boxes are compatible. Otherwise we'll 801d522f475Smrg * leave trash on the display when we mix normal and bold fonts. 802d522f475Smrg */ 803d522f475Smrgstatic int 8049a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs) 805d522f475Smrg{ 806956cc18dSsnj TScreen *screen = TScreenOf(xw); 807dfb07bc7Smrg int result = 0; 808dfb07bc7Smrg 809dfb07bc7Smrg if (nfs != 0 && bfs != 0) { 810dfb07bc7Smrg TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 811dfb07bc7Smrg nfs->ascent + nfs->descent, 812dfb07bc7Smrg bfs->ascent + bfs->descent, 813dfb07bc7Smrg nfs->min_bounds.width, bfs->min_bounds.width, 814dfb07bc7Smrg nfs->max_bounds.width, bfs->max_bounds.width)); 815dfb07bc7Smrg result = screen->free_bold_box 816dfb07bc7Smrg || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 817dfb07bc7Smrg && (nfs->min_bounds.width == bfs->min_bounds.width 818dfb07bc7Smrg || nfs->min_bounds.width == bfs->min_bounds.width + 1) 819dfb07bc7Smrg && (nfs->max_bounds.width == bfs->max_bounds.width 820dfb07bc7Smrg || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 821dfb07bc7Smrg } 822dfb07bc7Smrg return result; 823d522f475Smrg} 824d522f475Smrg 825d522f475Smrg/* 826d522f475Smrg * Check if the font looks like it has fixed width 827d522f475Smrg */ 828d522f475Smrgstatic int 8299a64e1c5Smrgis_fixed_font(XFontStruct *fs) 830d522f475Smrg{ 831d522f475Smrg if (fs) 832d522f475Smrg return (fs->min_bounds.width == fs->max_bounds.width); 833d522f475Smrg return 1; 834d522f475Smrg} 835d522f475Smrg 836d4fba8b9Smrgstatic int 837d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b) 838d4fba8b9Smrg{ 839d4fba8b9Smrg int result = 0; 840d4fba8b9Smrg if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width) 841d4fba8b9Smrg result = 1; 842d4fba8b9Smrg return result; 843d4fba8b9Smrg} 844d4fba8b9Smrg 845d522f475Smrg/* 846d522f475Smrg * Check if the font looks like a double width font (i.e. contains 847d522f475Smrg * characters of width X and 2X 848d522f475Smrg */ 849d522f475Smrg#if OPT_WIDE_CHARS 850d522f475Smrgstatic int 8519a64e1c5Smrgis_double_width_font(XFontStruct *fs) 852d522f475Smrg{ 853d4fba8b9Smrg return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width)); 854d522f475Smrg} 855d522f475Smrg#else 856d522f475Smrg#define is_double_width_font(fs) 0 857d522f475Smrg#endif 858d522f475Smrg 859d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 860d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890" 861d522f475Smrg 862d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */ 863d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 864d522f475Smrg "\xe5\x9b\x9b\xe4\xba\x94" \ 865d522f475Smrg "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 866d522f475Smrg "\xe4\xb9\x9d\xef\xa6\xb2" 867d522f475Smrg 868d522f475Smrg/* '1234567890' in Korean script in UTF-8 */ 869d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 870d522f475Smrg "\xec\x82\xac\xec\x98\xa4" \ 871d522f475Smrg "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 872d522f475Smrg "\xea\xb5\xac\xec\x98\x81" 873d522f475Smrg 874d522f475Smrg#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 875d522f475Smrg#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 876d522f475Smrg#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 877d522f475Smrg#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 878d522f475Smrg 879d522f475Smrgstatic Bool 8809a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font) 881d522f475Smrg{ 882d522f475Smrg XGlyphInfo gi1, gi2; 883d522f475Smrg FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 8840bd37d32Smrg String fwstr = FULL_WIDTH_TEST_STRING; 8850bd37d32Smrg String hwstr = HALF_WIDTH_TEST_STRING; 886d522f475Smrg 887d522f475Smrg /* Some Korean fonts don't have Chinese characters at all. */ 888d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 889d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 890d522f475Smrg return False; /* Not a CJK font */ 891d522f475Smrg else /* a Korean font without CJK Ideographs */ 892d522f475Smrg fwstr = FULL_WIDTH_TEST_STRING2; 893d522f475Smrg } 894d522f475Smrg 895d522f475Smrg XftTextExtents32(dpy, font, &c1, 1, &gi1); 896d522f475Smrg XftTextExtents32(dpy, font, &c2, 1, &gi2); 897d522f475Smrg if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 898d522f475Smrg return False; 899d522f475Smrg 9000bd37d32Smrg XftTextExtentsUtf8(dpy, 9010bd37d32Smrg font, 9020bd37d32Smrg (_Xconst FcChar8 *) hwstr, 9030bd37d32Smrg (int) strlen(hwstr), 9040bd37d32Smrg &gi1); 9050bd37d32Smrg XftTextExtentsUtf8(dpy, 9060bd37d32Smrg font, 9070bd37d32Smrg (_Xconst FcChar8 *) fwstr, 9080bd37d32Smrg (int) strlen(fwstr), 9090bd37d32Smrg &gi2); 910d522f475Smrg 911d522f475Smrg /* 912d522f475Smrg * fontconfig and Xft prior to 2.2(?) set the width of half-width 913d522f475Smrg * characters identical to that of full-width character in CJK double-width 914d522f475Smrg * (bi-width / monospace) font even though the former is half as wide as 915d522f475Smrg * the latter. This was fixed sometime before the release of fontconfig 916d522f475Smrg * 2.2 in early 2003. See 917d522f475Smrg * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 918d522f475Smrg * In the meantime, we have to check both possibilities. 919d522f475Smrg */ 920d522f475Smrg return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 921d522f475Smrg} 922d522f475Smrg#else 923d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0 924d522f475Smrg#endif 925d522f475Smrg 926d522f475Smrg#define EmptyFont(fs) (fs != 0 \ 927d522f475Smrg && ((fs)->ascent + (fs)->descent == 0 \ 928d522f475Smrg || (fs)->max_bounds.width == 0)) 929d522f475Smrg 930d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 931d522f475Smrg * (fs)->max_bounds.width) 932d522f475Smrg 933d522f475Smrgconst VTFontNames * 93420d2c4d2SmrgxtermFontName(const char *normal) 935d522f475Smrg{ 936d522f475Smrg static VTFontNames data; 9379a64e1c5Smrg FREE_STRING(data.f_n); 938d522f475Smrg memset(&data, 0, sizeof(data)); 939dfb07bc7Smrg if (normal) 940dfb07bc7Smrg data.f_n = x_strdup(normal); 941dfb07bc7Smrg return &data; 942dfb07bc7Smrg} 943dfb07bc7Smrg 944dfb07bc7Smrgconst VTFontNames * 945dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw) 946dfb07bc7Smrg{ 947dfb07bc7Smrg static VTFontNames data; 948dfb07bc7Smrg memset(&data, 0, sizeof(data)); 949dfb07bc7Smrg data.f_n = DefaultFontN(xw); 950dfb07bc7Smrg data.f_b = DefaultFontB(xw); 951dfb07bc7Smrg#if OPT_WIDE_CHARS 952dfb07bc7Smrg data.f_w = DefaultFontW(xw); 953dfb07bc7Smrg data.f_wb = DefaultFontWB(xw); 954dfb07bc7Smrg#endif 955d522f475Smrg return &data; 956d522f475Smrg} 957d522f475Smrg 958d522f475Smrgstatic void 959fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 960d522f475Smrg{ 961d522f475Smrg if (name != 0) { 9629a64e1c5Smrg String last = screen->menu_font_names[fontnum][which]; 963d522f475Smrg if (last != 0) { 964d522f475Smrg if (strcmp(last, name)) { 9659a64e1c5Smrg FREE_STRING(last); 966d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 967d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 968d522f475Smrg } 969d522f475Smrg } else { 970d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 971d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 972d522f475Smrg } 973d522f475Smrg } 974d522f475Smrg} 975d522f475Smrg 976dfb07bc7Smrgstatic void 977d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name) 978dfb07bc7Smrg{ 979d4fba8b9Smrg static NameList *reported; 980d4fba8b9Smrg NameList *list; 981dfb07bc7Smrg 982dfb07bc7Smrg switch (xw->misc.fontWarnings) { 983dfb07bc7Smrg case fwNever: 984dfb07bc7Smrg return; 985dfb07bc7Smrg case fwResource: 986d4fba8b9Smrg if (is_derived_font_name(name)) 987d4fba8b9Smrg return; 988dfb07bc7Smrg break; 989dfb07bc7Smrg case fwAlways: 990dfb07bc7Smrg break; 991dfb07bc7Smrg } 992d4fba8b9Smrg for (list = reported; list != 0; list = list->next) { 993d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 994d4fba8b9Smrg return; 995d4fba8b9Smrg } 996d4fba8b9Smrg } 997d4fba8b9Smrg if ((list = TypeMalloc(NameList)) != 0) { 998d4fba8b9Smrg list->name = x_strdup(name); 999d4fba8b9Smrg list->next = reported; 1000d4fba8b9Smrg reported = list; 1001d4fba8b9Smrg } 1002d4fba8b9Smrg xtermWarning("cannot %s%s%s %sfont \"%s\"\n", 1003d4fba8b9Smrg who, *tag ? " " : "", tag, 1004d4fba8b9Smrg is_derived_font_name(name) ? "derived " : "", 1005d4fba8b9Smrg name); 1006dfb07bc7Smrg} 1007dfb07bc7Smrg 1008d4fba8b9Smrg#if OPT_RENDERFONT 1009d4fba8b9Smrgstatic void 1010d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name) 1011d4fba8b9Smrg{ 1012d4fba8b9Smrg switch (xw->misc.fontWarnings) { 1013d4fba8b9Smrg case fwNever: 1014d4fba8b9Smrg return; 1015d4fba8b9Smrg case fwResource: 1016d4fba8b9Smrg /* these combinations of wide/bold/italic are all "derived" */ 1017d4fba8b9Smrg return; 1018d4fba8b9Smrg case fwAlways: 1019d4fba8b9Smrg break; 1020d4fba8b9Smrg } 1021d4fba8b9Smrg xtermWarning("did not find a usable %s TrueType font\n", name); 1022d4fba8b9Smrg} 1023d4fba8b9Smrg#endif 1024d4fba8b9Smrg 10258f44fb3bSmrgXFontStruct * 10268f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name) 10278f44fb3bSmrg{ 10288f44fb3bSmrg XFontStruct *result = NULL; 10298f44fb3bSmrg size_t have = strlen(name); 10308f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 10318f44fb3bSmrg ; /* just ignore it */ 10328f44fb3bSmrg } else { 10338f44fb3bSmrg TScreen *screen = TScreenOf(xw); 10348f44fb3bSmrg result = XLoadQueryFont(screen->display, name); 10358f44fb3bSmrg } 10368f44fb3bSmrg return result; 10378f44fb3bSmrg} 10388f44fb3bSmrg 1039d522f475Smrg/* 1040d522f475Smrg * Open the given font and verify that it is non-empty. Return a null on 1041d522f475Smrg * failure. 1042d522f475Smrg */ 1043d522f475SmrgBool 1044956cc18dSsnjxtermOpenFont(XtermWidget xw, 1045956cc18dSsnj const char *name, 1046956cc18dSsnj XTermFonts * result, 1047956cc18dSsnj Bool force) 1048d522f475Smrg{ 1049d522f475Smrg Bool code = False; 1050d522f475Smrg 1051d4fba8b9Smrg TRACE(("xtermOpenFont %d:%d '%s'\n", 1052d4fba8b9Smrg result->warn, xw->misc.fontWarnings, NonNull(name))); 1053492d43a5Smrg if (!IsEmpty(name)) { 10548f44fb3bSmrg if ((result->fs = xtermLoadQueryFont(xw, name)) != 0) { 1055956cc18dSsnj code = True; 1056956cc18dSsnj if (EmptyFont(result->fs)) { 1057dfb07bc7Smrg xtermCloseFont(xw, result); 1058956cc18dSsnj code = False; 1059956cc18dSsnj } else { 1060956cc18dSsnj result->fn = x_strdup(name); 1061956cc18dSsnj } 106220d2c4d2Smrg } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 1063dfb07bc7Smrg if (result->warn <= xw->misc.fontWarnings 1064956cc18dSsnj#if OPT_RENDERFONT 1065956cc18dSsnj && !UsingRenderFont(xw) 1066956cc18dSsnj#endif 1067956cc18dSsnj ) { 1068dfb07bc7Smrg cannotFont(xw, "load", "", name); 1069956cc18dSsnj } else { 1070492d43a5Smrg TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 1071956cc18dSsnj } 1072956cc18dSsnj if (force) { 1073d4fba8b9Smrg NoFontWarning(result); 1074dfb07bc7Smrg code = xtermOpenFont(xw, DEFFONT, result, True); 1075956cc18dSsnj } 1076d522f475Smrg } 1077d522f475Smrg } 1078d4fba8b9Smrg NoFontWarning(result); 1079d522f475Smrg return code; 1080d522f475Smrg} 1081d522f475Smrg 1082d522f475Smrg/* 1083956cc18dSsnj * Close the font and free the font info. 1084d522f475Smrg */ 1085dfb07bc7Smrgvoid 1086d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt) 1087d522f475Smrg{ 1088d522f475Smrg if (fnt != 0 && fnt->fs != 0) { 1089d522f475Smrg TScreen *screen = TScreenOf(xw); 1090d522f475Smrg 1091d522f475Smrg clrCgsFonts(xw, WhichVWin(screen), fnt); 1092d522f475Smrg XFreeFont(screen->display, fnt->fs); 1093d522f475Smrg xtermFreeFontInfo(fnt); 1094d522f475Smrg } 1095d522f475Smrg} 1096d522f475Smrg 1097037a25ddSmrg/* 1098037a25ddSmrg * Close and free the font (as well as any aliases). 1099037a25ddSmrg */ 1100037a25ddSmrgstatic void 1101037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which) 1102037a25ddSmrg{ 1103037a25ddSmrg XFontStruct *thisFont = fnts[which].fs; 1104037a25ddSmrg 1105037a25ddSmrg if (thisFont != 0) { 1106037a25ddSmrg int k; 1107037a25ddSmrg 1108037a25ddSmrg xtermCloseFont(xw, &fnts[which]); 1109037a25ddSmrg for (k = 0; k < fMAX; ++k) { 1110037a25ddSmrg if (k != which) { 1111037a25ddSmrg if (thisFont == fnts[k].fs) { 1112037a25ddSmrg xtermFreeFontInfo(&fnts[k]); 1113037a25ddSmrg } 1114037a25ddSmrg } 1115037a25ddSmrg } 1116037a25ddSmrg } 1117037a25ddSmrg} 1118037a25ddSmrg 1119d522f475Smrg/* 1120d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer. 1121d522f475Smrg */ 1122d522f475Smrgvoid 1123d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 1124d522f475Smrg{ 1125037a25ddSmrg int j; 1126d522f475Smrg 1127d522f475Smrg for (j = 0; j < fMAX; ++j) { 1128037a25ddSmrg xtermCloseFont2(xw, fnts, j); 1129d522f475Smrg } 1130d522f475Smrg} 1131d522f475Smrg 1132d522f475Smrg/* 1133d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but 1134d522f475Smrg * ensuring that the names are reallocated to simplify freeing. 1135d522f475Smrg */ 1136d522f475Smrgvoid 1137d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 1138d522f475Smrg{ 1139d522f475Smrg xtermFreeFontInfo(target); 1140d522f475Smrg target->chrset = source->chrset; 1141d522f475Smrg target->flags = source->flags; 1142d522f475Smrg target->fn = x_strdup(source->fn); 1143d522f475Smrg target->fs = source->fs; 1144dfb07bc7Smrg target->warn = source->warn; 1145d522f475Smrg} 1146d522f475Smrg 1147d522f475Smrgvoid 1148d522f475SmrgxtermFreeFontInfo(XTermFonts * target) 1149d522f475Smrg{ 1150d522f475Smrg target->chrset = 0; 1151d522f475Smrg target->flags = 0; 1152d4fba8b9Smrg FreeAndNull(target->fn); 1153d522f475Smrg target->fs = 0; 1154d522f475Smrg} 1155d522f475Smrg 1156fa3f02f3Smrg#if OPT_REPORT_FONTS 1157fa3f02f3Smrgstatic void 1158fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs) 1159fa3f02f3Smrg{ 1160fa3f02f3Smrg printf("\t\t%s:\n", tag); 1161fa3f02f3Smrg printf("\t\t\tlbearing: %d\n", cs->lbearing); 1162fa3f02f3Smrg printf("\t\t\trbearing: %d\n", cs->rbearing); 1163fa3f02f3Smrg printf("\t\t\twidth: %d\n", cs->width); 1164fa3f02f3Smrg printf("\t\t\tascent: %d\n", cs->ascent); 1165fa3f02f3Smrg printf("\t\t\tdescent: %d\n", cs->descent); 1166fa3f02f3Smrg} 1167fa3f02f3Smrg 1168fa3f02f3Smrgstatic void 1169fa3f02f3SmrgreportOneVTFont(const char *tag, 1170fa3f02f3Smrg XTermFonts * fnt) 1171fa3f02f3Smrg{ 1172dfb07bc7Smrg if (!IsEmpty(fnt->fn) && fnt->fs != 0) { 1173fa3f02f3Smrg XFontStruct *fs = fnt->fs; 1174fa3f02f3Smrg unsigned first_char = 0; 1175fa3f02f3Smrg unsigned last_char = 0; 1176fa3f02f3Smrg 1177fa3f02f3Smrg if (fs->max_byte1 == 0) { 1178fa3f02f3Smrg first_char = fs->min_char_or_byte2; 1179fa3f02f3Smrg last_char = fs->max_char_or_byte2; 1180fa3f02f3Smrg } else { 1181fa3f02f3Smrg first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1182fa3f02f3Smrg last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1183fa3f02f3Smrg } 1184fa3f02f3Smrg 1185fa3f02f3Smrg printf("\t%s: %s\n", tag, NonNull(fnt->fn)); 1186fa3f02f3Smrg printf("\t\tall chars: %s\n", fs->all_chars_exist ? "yes" : "no"); 1187fa3f02f3Smrg printf("\t\tdefault char: %d\n", fs->default_char); 1188fa3f02f3Smrg printf("\t\tdirection: %d\n", fs->direction); 1189fa3f02f3Smrg printf("\t\tascent: %d\n", fs->ascent); 1190fa3f02f3Smrg printf("\t\tdescent: %d\n", fs->descent); 1191fa3f02f3Smrg printf("\t\tfirst char: %u\n", first_char); 1192fa3f02f3Smrg printf("\t\tlast char: %u\n", last_char); 1193fa3f02f3Smrg printf("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 11949a64e1c5Smrg if (FontLacksMetrics(fnt)) { 11959a64e1c5Smrg printf("\t\tmissing-chars: ?\n"); 11969a64e1c5Smrg printf("\t\tpresent-chars: ?\n"); 11979a64e1c5Smrg } else { 11989a64e1c5Smrg unsigned missing = 0; 1199037a25ddSmrg unsigned ch; 12009a64e1c5Smrg for (ch = first_char; ch <= last_char; ++ch) { 12019a64e1c5Smrg if (xtermMissingChar(ch, fnt)) { 12029a64e1c5Smrg ++missing; 12039a64e1c5Smrg } 12049a64e1c5Smrg } 12059a64e1c5Smrg printf("\t\tmissing-chars: %u\n", missing); 12069a64e1c5Smrg printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 12079a64e1c5Smrg } 1208fa3f02f3Smrg printf("\t\tmin_byte1: %d\n", fs->min_byte1); 1209fa3f02f3Smrg printf("\t\tmax_byte1: %d\n", fs->max_byte1); 1210fa3f02f3Smrg printf("\t\tproperties: %d\n", fs->n_properties); 1211fa3f02f3Smrg reportXCharStruct("min_bounds", &(fs->min_bounds)); 1212fa3f02f3Smrg reportXCharStruct("max_bounds", &(fs->max_bounds)); 1213fa3f02f3Smrg /* TODO: report fs->properties and fs->per_char */ 1214fa3f02f3Smrg } 1215fa3f02f3Smrg} 1216fa3f02f3Smrg 1217fa3f02f3Smrgstatic void 1218fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum) 1219fa3f02f3Smrg{ 1220fa3f02f3Smrg if (resource.reportFonts) { 1221fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 1222fa3f02f3Smrg 1223fa3f02f3Smrg if (fontnum) { 1224fa3f02f3Smrg printf("Loaded VTFonts(font%d)\n", fontnum); 1225fa3f02f3Smrg } else { 1226fa3f02f3Smrg printf("Loaded VTFonts(default)\n"); 1227fa3f02f3Smrg } 1228dfb07bc7Smrg 1229d4fba8b9Smrg reportOneVTFont("fNorm", GetNormalFont(screen, fNorm)); 1230d4fba8b9Smrg reportOneVTFont("fBold", GetNormalFont(screen, fBold)); 1231fa3f02f3Smrg#if OPT_WIDE_CHARS 1232d4fba8b9Smrg reportOneVTFont("fWide", GetNormalFont(screen, fWide)); 1233d4fba8b9Smrg reportOneVTFont("fWBold", GetNormalFont(screen, fWBold)); 1234fa3f02f3Smrg#endif 1235fa3f02f3Smrg } 1236fa3f02f3Smrg} 1237fa3f02f3Smrg#endif 1238fa3f02f3Smrg 12399a64e1c5Smrgvoid 1240d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc) 12419a64e1c5Smrg{ 12429a64e1c5Smrg TScreen *screen = TScreenOf(xw); 12439a64e1c5Smrg VTwin *win = WhichVWin(screen); 1244d4fba8b9Smrg Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground); 1245d4fba8b9Smrg Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background); 1246dfb07bc7Smrg 12479a64e1c5Smrg setCgsFore(xw, win, gcNorm, new_normal); 12489a64e1c5Smrg setCgsBack(xw, win, gcNorm, new_revers); 1249dfb07bc7Smrg setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm)); 12509a64e1c5Smrg 12519a64e1c5Smrg copyCgs(xw, win, gcBold, gcNorm); 1252d4fba8b9Smrg setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold); 12539a64e1c5Smrg 12549a64e1c5Smrg setCgsFore(xw, win, gcNormReverse, new_revers); 12559a64e1c5Smrg setCgsBack(xw, win, gcNormReverse, new_normal); 1256dfb07bc7Smrg setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm)); 12579a64e1c5Smrg 12589a64e1c5Smrg copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1259d4fba8b9Smrg setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold); 12609a64e1c5Smrg 12619a64e1c5Smrg if_OPT_WIDE_CHARS(screen, { 1262dfb07bc7Smrg XTermFonts *wide_xx = myfunc(screen, fWide); 1263dfb07bc7Smrg XTermFonts *bold_xx = myfunc(screen, fWBold); 1264dfb07bc7Smrg if (wide_xx->fs != 0 1265dfb07bc7Smrg && bold_xx->fs != 0) { 12669a64e1c5Smrg setCgsFore(xw, win, gcWide, new_normal); 12679a64e1c5Smrg setCgsBack(xw, win, gcWide, new_revers); 1268dfb07bc7Smrg setCgsFont(xw, win, gcWide, wide_xx); 12699a64e1c5Smrg 12709a64e1c5Smrg copyCgs(xw, win, gcWBold, gcWide); 1271dfb07bc7Smrg setCgsFont(xw, win, gcWBold, bold_xx); 12729a64e1c5Smrg 12739a64e1c5Smrg setCgsFore(xw, win, gcWideReverse, new_revers); 12749a64e1c5Smrg setCgsBack(xw, win, gcWideReverse, new_normal); 1275dfb07bc7Smrg setCgsFont(xw, win, gcWideReverse, wide_xx); 12769a64e1c5Smrg 12779a64e1c5Smrg copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1278dfb07bc7Smrg setCgsFont(xw, win, gcWBoldReverse, bold_xx); 12799a64e1c5Smrg } 12809a64e1c5Smrg }); 12819a64e1c5Smrg} 12829a64e1c5Smrg 1283d4fba8b9Smrg#if OPT_WIDE_ATTRS 1284d4fba8b9Smrgunsigned 1285d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs) 1286d4fba8b9Smrg{ 1287c48a5815Smrg TScreen *screen = TScreenOf(xw); 1288c48a5815Smrg 128950027b5bSmrg (void) screen; 1290c48a5815Smrg if (UseItalicFont(screen)) { 1291c48a5815Smrg if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) { 1292c48a5815Smrg xtermLoadItalics(xw); 1293c48a5815Smrg xtermUpdateFontGCs(xw, getItalicFont); 1294c48a5815Smrg } else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) { 1295c48a5815Smrg xtermUpdateFontGCs(xw, getNormalFont); 1296c48a5815Smrg } 1297d4fba8b9Smrg } 1298d4fba8b9Smrg return new_attrs; 1299d4fba8b9Smrg} 1300d4fba8b9Smrg#endif 1301d4fba8b9Smrg 1302d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS 13039a64e1c5Smrgstatic void 13049a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp) 13059a64e1c5Smrg{ 13069a64e1c5Smrg if (fp->fs != 0) { 13079a64e1c5Smrg if (FontLacksMetrics(fp)) { 13089a64e1c5Smrg TRACE(("%s font lacks metrics\n", name)); 13099a64e1c5Smrg } else if (FontIsIncomplete(fp)) { 13109a64e1c5Smrg TRACE(("%s font is incomplete\n", name)); 13119a64e1c5Smrg } else { 13129a64e1c5Smrg TRACE(("%s font is complete\n", name)); 13139a64e1c5Smrg } 13149a64e1c5Smrg } else { 13159a64e1c5Smrg TRACE(("%s font is missing\n", name)); 13169a64e1c5Smrg } 13179a64e1c5Smrg} 13189a64e1c5Smrg#endif 13199a64e1c5Smrg 1320dfb07bc7Smrgstatic Bool 1321dfb07bc7SmrgloadNormFP(XtermWidget xw, 1322dfb07bc7Smrg char **nameOutP, 1323dfb07bc7Smrg XTermFonts * infoOut, 1324dfb07bc7Smrg int fontnum) 1325dfb07bc7Smrg{ 1326dfb07bc7Smrg Bool status = True; 1327dfb07bc7Smrg 1328dfb07bc7Smrg TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP))); 1329dfb07bc7Smrg 1330dfb07bc7Smrg if (!xtermOpenFont(xw, 1331dfb07bc7Smrg *nameOutP, 1332dfb07bc7Smrg infoOut, 1333dfb07bc7Smrg (fontnum == fontMenu_default))) { 1334dfb07bc7Smrg /* 1335dfb07bc7Smrg * If we are opening the default font, and it happens to be missing, 1336dfb07bc7Smrg * force that to the compiled-in default font, e.g., "fixed". If we 1337dfb07bc7Smrg * cannot open the font, disable it from the menu. 1338dfb07bc7Smrg */ 1339dfb07bc7Smrg if (fontnum != fontMenu_fontsel) { 1340dfb07bc7Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1341dfb07bc7Smrg } 1342dfb07bc7Smrg status = False; 1343dfb07bc7Smrg } 1344dfb07bc7Smrg return status; 1345dfb07bc7Smrg} 1346dfb07bc7Smrg 1347dfb07bc7Smrgstatic Bool 1348dfb07bc7SmrgloadBoldFP(XtermWidget xw, 1349dfb07bc7Smrg char **nameOutP, 1350dfb07bc7Smrg XTermFonts * infoOut, 1351dfb07bc7Smrg const char *nameRef, 1352dfb07bc7Smrg XTermFonts * infoRef, 1353dfb07bc7Smrg int fontnum) 1354dfb07bc7Smrg{ 1355dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1356dfb07bc7Smrg Bool status = True; 1357dfb07bc7Smrg 1358dfb07bc7Smrg TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP))); 1359dfb07bc7Smrg 1360dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1361dfb07bc7Smrg FontNameProperties *fp; 1362dfb07bc7Smrg char *normal = x_strdup(nameRef); 1363dfb07bc7Smrg 1364dfb07bc7Smrg fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1365dfb07bc7Smrg if (fp != 0) { 1366d4fba8b9Smrg NoFontWarning(infoOut); 1367dfb07bc7Smrg *nameOutP = bold_font_name(fp, fp->average_width); 1368dfb07bc7Smrg if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1369dfb07bc7Smrg free(*nameOutP); 1370dfb07bc7Smrg *nameOutP = bold_font_name(fp, -1); 1371dfb07bc7Smrg xtermOpenFont(xw, *nameOutP, infoOut, False); 1372dfb07bc7Smrg } 1373dfb07bc7Smrg TRACE(("...derived bold '%s'\n", NonNull(*nameOutP))); 1374dfb07bc7Smrg } 1375dfb07bc7Smrg if (fp == 0 || infoOut->fs == 0) { 1376dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1377dfb07bc7Smrg TRACE(("...cannot load a matching bold font\n")); 1378dfb07bc7Smrg } else if (comparable_metrics(infoRef->fs, infoOut->fs) 1379dfb07bc7Smrg && same_font_size(xw, infoRef->fs, infoOut->fs) 1380dfb07bc7Smrg && got_bold_font(screen->display, infoOut->fs, *nameOutP)) { 1381dfb07bc7Smrg TRACE(("...got a matching bold font\n")); 1382dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1383dfb07bc7Smrg } else { 1384dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1385dfb07bc7Smrg *infoOut = *infoRef; 1386dfb07bc7Smrg TRACE(("...did not get a matching bold font\n")); 1387dfb07bc7Smrg } 1388dfb07bc7Smrg free(normal); 1389dfb07bc7Smrg } else if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1390dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1391dfb07bc7Smrg TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP))); 1392dfb07bc7Smrg } else { 1393dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1394dfb07bc7Smrg } 1395dfb07bc7Smrg 1396dfb07bc7Smrg /* 1397dfb07bc7Smrg * Most of the time this call to load the font will succeed, even if 1398dfb07bc7Smrg * there is no wide font : the X server doubles the width of the 1399dfb07bc7Smrg * normal font, or similar. 1400dfb07bc7Smrg * 1401dfb07bc7Smrg * But if it did fail for some reason, then nevermind. 1402dfb07bc7Smrg */ 1403dfb07bc7Smrg if (EmptyFont(infoOut->fs)) 1404dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1405dfb07bc7Smrg 1406dfb07bc7Smrg if (!same_font_size(xw, infoRef->fs, infoOut->fs) 1407dfb07bc7Smrg && (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) { 1408dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold fonts\n")); 1409dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1410dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1411dfb07bc7Smrg } 1412dfb07bc7Smrg 1413dfb07bc7Smrg return status; 1414dfb07bc7Smrg} 1415dfb07bc7Smrg 1416dfb07bc7Smrg#if OPT_WIDE_CHARS 1417dfb07bc7Smrgstatic Bool 1418dfb07bc7SmrgloadWideFP(XtermWidget xw, 1419dfb07bc7Smrg char **nameOutP, 1420dfb07bc7Smrg XTermFonts * infoOut, 1421dfb07bc7Smrg const char *nameRef, 1422dfb07bc7Smrg XTermFonts * infoRef, 1423dfb07bc7Smrg int fontnum) 1424dfb07bc7Smrg{ 1425dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1426dfb07bc7Smrg Bool status = True; 1427dfb07bc7Smrg 1428dfb07bc7Smrg TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP))); 1429dfb07bc7Smrg 1430d4fba8b9Smrg if (!check_fontname(*nameOutP) 1431d4fba8b9Smrg && (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) { 1432dfb07bc7Smrg char *normal = x_strdup(nameRef); 1433d4fba8b9Smrg FontNameProperties *fp = get_font_name_props(screen->display, 1434d4fba8b9Smrg infoRef->fs, &normal); 1435dfb07bc7Smrg if (fp != 0) { 1436dfb07bc7Smrg *nameOutP = wide_font_name(fp); 1437d4fba8b9Smrg NoFontWarning(infoOut); 1438dfb07bc7Smrg } 1439dfb07bc7Smrg free(normal); 1440dfb07bc7Smrg } 1441dfb07bc7Smrg 1442dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1443d4fba8b9Smrg if (xtermOpenFont(xw, *nameOutP, infoOut, False) 1444d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1445d4fba8b9Smrg && EmptyFont(infoOut->fs)) { 1446d4fba8b9Smrg xtermCloseFont2(xw, infoOut - fWide, fWide); 1447d4fba8b9Smrg } 1448d4fba8b9Smrg if (infoOut->fs == 0) { 1449dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1450d4fba8b9Smrg } else { 1451d4fba8b9Smrg TRACE(("...%s wide %s\n", 1452d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1453d4fba8b9Smrg NonNull(*nameOutP))); 1454d4fba8b9Smrg cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1455dfb07bc7Smrg } 1456dfb07bc7Smrg } else { 1457dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1458dfb07bc7Smrg } 1459c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width 1460c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width 1461c48a5815Smrg xw->work.force_wideFont = False; 1462c48a5815Smrg if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) { 1463c48a5815Smrg TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs))); 1464c48a5815Smrg TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs))); 1465c48a5815Smrg TRACE(("...actual width %d\n", MaxWidthOf(infoOut->fs))); 1466c48a5815Smrg xw->work.force_wideFont = True; 1467c48a5815Smrg } 1468dfb07bc7Smrg return status; 1469dfb07bc7Smrg} 1470dfb07bc7Smrg 1471dfb07bc7Smrgstatic Bool 1472dfb07bc7SmrgloadWBoldFP(XtermWidget xw, 1473dfb07bc7Smrg char **nameOutP, 1474dfb07bc7Smrg XTermFonts * infoOut, 1475dfb07bc7Smrg const char *wideNameRef, XTermFonts * wideInfoRef, 1476dfb07bc7Smrg const char *boldNameRef, XTermFonts * boldInfoRef, 1477dfb07bc7Smrg int fontnum) 1478dfb07bc7Smrg{ 1479dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1480dfb07bc7Smrg Bool status = True; 1481dfb07bc7Smrg char *bold = NULL; 1482dfb07bc7Smrg 1483dfb07bc7Smrg TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP))); 1484dfb07bc7Smrg 1485dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1486dfb07bc7Smrg FontNameProperties *fp; 1487dfb07bc7Smrg fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold); 1488dfb07bc7Smrg if (fp != 0) { 1489dfb07bc7Smrg *nameOutP = widebold_font_name(fp); 1490d4fba8b9Smrg NoFontWarning(infoOut); 1491dfb07bc7Smrg } 1492dfb07bc7Smrg } 1493dfb07bc7Smrg 1494dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1495dfb07bc7Smrg 1496dfb07bc7Smrg if (xtermOpenFont(xw, *nameOutP, infoOut, False) 1497d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1498dfb07bc7Smrg && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) { 1499dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1500dfb07bc7Smrg } 1501dfb07bc7Smrg 1502dfb07bc7Smrg if (infoOut->fs == 0) { 1503d4fba8b9Smrg if (is_derived_font_name(*nameOutP)) 1504dfb07bc7Smrg free(*nameOutP); 1505dfb07bc7Smrg if (IsEmpty(wideNameRef)) { 1506dfb07bc7Smrg *nameOutP = x_strdup(boldNameRef); 1507dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1508dfb07bc7Smrg TRACE(("...cannot load wide-bold, use bold %s\n", 1509dfb07bc7Smrg NonNull(boldNameRef))); 1510dfb07bc7Smrg } else { 1511dfb07bc7Smrg *nameOutP = x_strdup(wideNameRef); 1512dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1513dfb07bc7Smrg TRACE(("...cannot load wide-bold, use wide %s\n", 1514dfb07bc7Smrg NonNull(wideNameRef))); 1515dfb07bc7Smrg } 1516dfb07bc7Smrg } else { 1517dfb07bc7Smrg TRACE(("...%s wide/bold %s\n", 1518d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1519dfb07bc7Smrg NonNull(*nameOutP))); 1520dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fWBold, *nameOutP); 1521dfb07bc7Smrg } 1522dfb07bc7Smrg } else if (is_double_width_font(boldInfoRef->fs)) { 1523dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1524dfb07bc7Smrg TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef))); 1525dfb07bc7Smrg } else { 1526dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1527dfb07bc7Smrg TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef))); 1528dfb07bc7Smrg } 1529dfb07bc7Smrg 1530dfb07bc7Smrg free(bold); 1531dfb07bc7Smrg 1532dfb07bc7Smrg if (EmptyFont(infoOut->fs)) { 1533dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1534dfb07bc7Smrg } else { 1535dfb07bc7Smrg if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs) 1536dfb07bc7Smrg || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs) 1537dfb07bc7Smrg && is_fixed_font(wideInfoRef->fs) 1538dfb07bc7Smrg && is_fixed_font(infoOut->fs)))) { 1539dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1540dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1541dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1542dfb07bc7Smrg } 1543dfb07bc7Smrg } 1544dfb07bc7Smrg 1545dfb07bc7Smrg return status; 1546dfb07bc7Smrg} 1547dfb07bc7Smrg#endif 1548dfb07bc7Smrg 1549d522f475Smrgint 1550d522f475SmrgxtermLoadFont(XtermWidget xw, 1551d522f475Smrg const VTFontNames * fonts, 1552d522f475Smrg Bool doresize, 1553d522f475Smrg int fontnum) 1554d522f475Smrg{ 1555956cc18dSsnj TScreen *screen = TScreenOf(xw); 1556d522f475Smrg VTwin *win = WhichVWin(screen); 1557d522f475Smrg 1558d522f475Smrg VTFontNames myfonts; 1559d522f475Smrg XTermFonts fnts[fMAX]; 1560d522f475Smrg char *tmpname = NULL; 1561956cc18dSsnj Boolean proportional = False; 1562d522f475Smrg 1563d522f475Smrg memset(&myfonts, 0, sizeof(myfonts)); 1564d522f475Smrg memset(fnts, 0, sizeof(fnts)); 1565d522f475Smrg 1566d522f475Smrg if (fonts != 0) 1567d522f475Smrg myfonts = *fonts; 1568956cc18dSsnj if (!check_fontname(myfonts.f_n)) 1569d522f475Smrg return 0; 1570d522f475Smrg 1571d522f475Smrg if (fontnum == fontMenu_fontescape 1572d522f475Smrg && myfonts.f_n != screen->MenuFontName(fontnum)) { 1573d522f475Smrg if ((tmpname = x_strdup(myfonts.f_n)) == 0) 1574d522f475Smrg return 0; 1575d522f475Smrg } 1576d522f475Smrg 1577d522f475Smrg TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n)); 1578d522f475Smrg releaseWindowGCs(xw, win); 1579d522f475Smrg 1580956cc18dSsnj#define DbgResource(name, field, index) \ 1581956cc18dSsnj TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1582956cc18dSsnj fontnum, \ 1583dfb07bc7Smrg (fnts[index].warn == fwResource) ? "*" : " ", \ 1584492d43a5Smrg NonNull(myfonts.field))) 1585956cc18dSsnj DbgResource("normal", f_n, fNorm); 1586956cc18dSsnj DbgResource("bold ", f_b, fBold); 1587d522f475Smrg#if OPT_WIDE_CHARS 1588956cc18dSsnj DbgResource("wide ", f_w, fWide); 1589956cc18dSsnj DbgResource("w/bold", f_wb, fWBold); 1590d522f475Smrg#endif 1591d522f475Smrg 1592dfb07bc7Smrg if (!loadNormFP(xw, 1593dfb07bc7Smrg &myfonts.f_n, 1594dfb07bc7Smrg &fnts[fNorm], 1595dfb07bc7Smrg fontnum)) 1596d522f475Smrg goto bad; 1597d522f475Smrg 1598dfb07bc7Smrg if (!loadBoldFP(xw, 1599dfb07bc7Smrg &myfonts.f_b, 1600dfb07bc7Smrg &fnts[fBold], 1601dfb07bc7Smrg myfonts.f_n, 1602dfb07bc7Smrg &fnts[fNorm], 1603dfb07bc7Smrg fontnum)) 1604dfb07bc7Smrg goto bad; 1605d522f475Smrg 1606d522f475Smrg /* 1607d522f475Smrg * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1608d522f475Smrg * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1609d522f475Smrg * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1610d522f475Smrg */ 1611d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1612d522f475Smrg 1613dfb07bc7Smrg if (!loadWideFP(xw, 1614dfb07bc7Smrg &myfonts.f_w, 1615dfb07bc7Smrg &fnts[fWide], 1616dfb07bc7Smrg myfonts.f_n, 1617dfb07bc7Smrg &fnts[fNorm], 1618dfb07bc7Smrg fontnum)) 1619dfb07bc7Smrg goto bad; 1620dfb07bc7Smrg 1621dfb07bc7Smrg if (!loadWBoldFP(xw, 1622dfb07bc7Smrg &myfonts.f_wb, 1623dfb07bc7Smrg &fnts[fWBold], 1624dfb07bc7Smrg myfonts.f_w, 1625dfb07bc7Smrg &fnts[fWide], 1626dfb07bc7Smrg myfonts.f_b, 1627dfb07bc7Smrg &fnts[fBold], 1628dfb07bc7Smrg fontnum)) 1629dfb07bc7Smrg goto bad; 1630d522f475Smrg 1631d522f475Smrg }); 1632d522f475Smrg 1633d522f475Smrg /* 1634d522f475Smrg * Normal/bold fonts should be the same width. Also, the min/max 1635d522f475Smrg * values should be the same. 1636d522f475Smrg */ 1637d4fba8b9Smrg if (fnts[fNorm].fs != 0 1638d4fba8b9Smrg && fnts[fBold].fs != 0 1639d4fba8b9Smrg && (!is_fixed_font(fnts[fNorm].fs) 1640d4fba8b9Smrg || !is_fixed_font(fnts[fBold].fs) 1641d4fba8b9Smrg || differing_widths(fnts[fNorm].fs, fnts[fBold].fs))) { 1642d522f475Smrg TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1643d522f475Smrg fnts[fNorm].fs->min_bounds.width, 1644d522f475Smrg fnts[fNorm].fs->max_bounds.width, 1645d522f475Smrg fnts[fBold].fs->min_bounds.width, 1646d522f475Smrg fnts[fBold].fs->max_bounds.width)); 1647d522f475Smrg proportional = True; 1648d522f475Smrg } 1649d522f475Smrg 1650d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1651d522f475Smrg if (fnts[fWide].fs != 0 1652d522f475Smrg && fnts[fWBold].fs != 0 1653d522f475Smrg && (!is_fixed_font(fnts[fWide].fs) 1654d522f475Smrg || !is_fixed_font(fnts[fWBold].fs) 1655d4fba8b9Smrg || differing_widths(fnts[fWide].fs, fnts[fWBold].fs))) { 1656d522f475Smrg TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1657d522f475Smrg fnts[fWide].fs->min_bounds.width, 1658d522f475Smrg fnts[fWide].fs->max_bounds.width, 1659d522f475Smrg fnts[fWBold].fs->min_bounds.width, 1660d522f475Smrg fnts[fWBold].fs->max_bounds.width)); 1661d522f475Smrg proportional = True; 1662d522f475Smrg } 1663d522f475Smrg }); 1664d522f475Smrg 1665d522f475Smrg /* TODO : enforce that the width of the wide font is 2* the width 1666d522f475Smrg of the narrow font */ 1667d522f475Smrg 1668d522f475Smrg /* 1669d522f475Smrg * If we're switching fonts, free the old ones. Otherwise we'll leak 1670d522f475Smrg * the memory that is associated with the old fonts. The 1671d522f475Smrg * XLoadQueryFont call allocates a new XFontStruct. 1672d522f475Smrg */ 1673d522f475Smrg xtermCloseFonts(xw, screen->fnts); 16749a64e1c5Smrg#if OPT_WIDE_ATTRS 16759a64e1c5Smrg xtermCloseFonts(xw, screen->ifnts); 16769a64e1c5Smrg screen->ifnts_ok = False; 16779a64e1c5Smrg#endif 1678d522f475Smrg 1679d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fNorm), &fnts[fNorm]); 1680d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fBold), &fnts[fBold]); 1681d522f475Smrg#if OPT_WIDE_CHARS 1682d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]); 1683d522f475Smrg if (fnts[fWBold].fs == NULL) 1684d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]); 1685d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fWBold), &fnts[fWBold]); 1686d522f475Smrg#endif 1687d522f475Smrg 1688d4fba8b9Smrg xtermUpdateFontGCs(xw, getNormalFont); 1689d522f475Smrg 169020d2c4d2Smrg#if OPT_BOX_CHARS 169120d2c4d2Smrg screen->allow_packing = proportional; 169220d2c4d2Smrg setupPackedFonts(xw); 169320d2c4d2Smrg#endif 169420d2c4d2Smrg screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1695d4fba8b9Smrg screen->fnt_boxes = 1; 1696d522f475Smrg 1697d522f475Smrg#if OPT_BOX_CHARS 1698d522f475Smrg /* 16999a64e1c5Smrg * xterm uses character positions 1-31 of a font for the line-drawing 1700d522f475Smrg * characters. Check that they are all present. The null character 1701d522f475Smrg * (0) is special, and is not used. 1702d522f475Smrg */ 1703d522f475Smrg#if OPT_RENDERFONT 1704d522f475Smrg if (UsingRenderFont(xw)) { 1705d522f475Smrg /* 1706d522f475Smrg * FIXME: we shouldn't even be here if we're using Xft. 1707d522f475Smrg */ 1708d4fba8b9Smrg screen->fnt_boxes = 0; 1709d522f475Smrg TRACE(("assume Xft missing line-drawing chars\n")); 1710d522f475Smrg } else 1711d522f475Smrg#endif 1712d522f475Smrg { 1713d522f475Smrg unsigned ch; 1714d522f475Smrg 17159a64e1c5Smrg#if OPT_TRACE 17169a64e1c5Smrg#define TRACE_MISS(index) show_font_misses(#index, &fnts[index]) 17179a64e1c5Smrg TRACE_MISS(fNorm); 17189a64e1c5Smrg TRACE_MISS(fBold); 17199a64e1c5Smrg#if OPT_WIDE_CHARS 17209a64e1c5Smrg TRACE_MISS(fWide); 17219a64e1c5Smrg TRACE_MISS(fWBold); 17229a64e1c5Smrg#endif 17239a64e1c5Smrg#endif 1724fa3f02f3Smrg 1725d522f475Smrg#if OPT_WIDE_CHARS 1726d4fba8b9Smrg if (screen->utf8_mode || screen->unicode_font) { 1727d4fba8b9Smrg UIntSet(screen->fnt_boxes, 2); 1728d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1729d4fba8b9Smrg unsigned n = dec2ucs(screen, ch); 1730d4fba8b9Smrg if ((n != UCS_REPL) 1731d4fba8b9Smrg && (n != ch) 1732d4fba8b9Smrg && (screen->fnt_boxes & 2)) { 1733d4fba8b9Smrg if (xtermMissingChar(n, &fnts[fNorm]) || 1734d4fba8b9Smrg xtermMissingChar(n, &fnts[fBold])) { 1735d4fba8b9Smrg UIntClr(screen->fnt_boxes, 2); 1736d4fba8b9Smrg TRACE(("missing graphics character #%d, U+%04X\n", 1737d4fba8b9Smrg ch, n)); 1738d4fba8b9Smrg break; 1739d4fba8b9Smrg } 1740d4fba8b9Smrg } 1741d522f475Smrg } 1742d4fba8b9Smrg } 1743d522f475Smrg#endif 1744d4fba8b9Smrg 1745d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1746d4fba8b9Smrg if (xtermMissingChar(ch, &fnts[fNorm])) { 1747d4fba8b9Smrg TRACE(("missing normal char #%d\n", ch)); 1748d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1749d522f475Smrg break; 1750d522f475Smrg } 1751d4fba8b9Smrg if (xtermMissingChar(ch, &fnts[fBold])) { 1752d4fba8b9Smrg TRACE(("missing bold char #%d\n", ch)); 1753d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1754d522f475Smrg break; 1755d522f475Smrg } 1756d522f475Smrg } 1757d4fba8b9Smrg 1758d4fba8b9Smrg TRACE(("Will %suse internal line-drawing characters (mode %d)\n", 1759d4fba8b9Smrg screen->fnt_boxes ? "not " : "", 1760d4fba8b9Smrg screen->fnt_boxes)); 1761d522f475Smrg } 1762d522f475Smrg#endif 1763d522f475Smrg 1764d522f475Smrg if (screen->always_bold_mode) { 1765d522f475Smrg screen->enbolden = screen->bold_mode; 1766d522f475Smrg } else { 1767d522f475Smrg screen->enbolden = screen->bold_mode 1768d522f475Smrg && ((fnts[fNorm].fs == fnts[fBold].fs) 1769dfb07bc7Smrg || same_font_name(myfonts.f_n, myfonts.f_b)); 1770d522f475Smrg } 1771d522f475Smrg TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1772d522f475Smrg screen->enbolden ? "" : "not ")); 1773d522f475Smrg 1774d522f475Smrg set_menu_font(False); 1775d522f475Smrg screen->menu_font_number = fontnum; 1776d522f475Smrg set_menu_font(True); 1777d522f475Smrg if (tmpname) { /* if setting escape or sel */ 1778d522f475Smrg if (screen->MenuFontName(fontnum)) 17799a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontnum)); 1780d522f475Smrg screen->MenuFontName(fontnum) = tmpname; 1781d522f475Smrg if (fontnum == fontMenu_fontescape) { 178294644356Smrg update_font_escape(); 1783d522f475Smrg } 1784d522f475Smrg#if OPT_SHIFT_FONTS 1785d522f475Smrg screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs); 1786d522f475Smrg#endif 1787d522f475Smrg } 1788d522f475Smrg set_cursor_gcs(xw); 1789d522f475Smrg xtermUpdateFontInfo(xw, doresize); 1790d522f475Smrg TRACE(("Success Cgs - xtermLoadFont\n")); 1791fa3f02f3Smrg#if OPT_REPORT_FONTS 1792fa3f02f3Smrg reportVTFontInfo(xw, fontnum); 17939a64e1c5Smrg#endif 17949a64e1c5Smrg FREE_FNAME(f_n); 17959a64e1c5Smrg FREE_FNAME(f_b); 17969a64e1c5Smrg#if OPT_WIDE_CHARS 17979a64e1c5Smrg FREE_FNAME(f_w); 17989a64e1c5Smrg FREE_FNAME(f_wb); 17999a64e1c5Smrg#endif 18009a64e1c5Smrg if (fnts[fNorm].fn == fnts[fBold].fn) { 18019a64e1c5Smrg free(fnts[fNorm].fn); 18029a64e1c5Smrg } else { 18039a64e1c5Smrg free(fnts[fNorm].fn); 18049a64e1c5Smrg free(fnts[fBold].fn); 18059a64e1c5Smrg } 18069a64e1c5Smrg#if OPT_WIDE_CHARS 18079a64e1c5Smrg free(fnts[fWide].fn); 18089a64e1c5Smrg free(fnts[fWBold].fn); 1809fa3f02f3Smrg#endif 1810dfb07bc7Smrg xtermSetWinSize(xw); 1811d522f475Smrg return 1; 1812d522f475Smrg 1813d522f475Smrg bad: 1814d4fba8b9Smrg free(tmpname); 18150bd37d32Smrg 18160bd37d32Smrg#if OPT_RENDERFONT 181794644356Smrg if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) { 18189a64e1c5Smrg int old_fontnum = screen->menu_font_number; 18199a64e1c5Smrg#if OPT_TOOLBAR 18209a64e1c5Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, True); 18219a64e1c5Smrg#endif 18229a64e1c5Smrg Bell(xw, XkbBI_MinorError, 0); 18239a64e1c5Smrg myfonts.f_n = screen->MenuFontName(old_fontnum); 18249a64e1c5Smrg return xtermLoadFont(xw, &myfonts, doresize, old_fontnum); 18259a64e1c5Smrg } else if (x_strcasecmp(myfonts.f_n, DEFFONT)) { 18260bd37d32Smrg int code; 18270bd37d32Smrg 1828dfb07bc7Smrg myfonts.f_n = x_strdup(DEFFONT); 18290bd37d32Smrg TRACE(("...recovering for TrueType fonts\n")); 18300bd37d32Smrg code = xtermLoadFont(xw, &myfonts, doresize, fontnum); 18310bd37d32Smrg if (code) { 183294644356Smrg if (fontnum != fontMenu_fontsel) { 183394644356Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, 183494644356Smrg UsingRenderFont(xw)); 183594644356Smrg } 18360bd37d32Smrg TRACE(("...recovered size %dx%d\n", 18370bd37d32Smrg FontHeight(screen), 18380bd37d32Smrg FontWidth(screen))); 18390bd37d32Smrg } 18400bd37d32Smrg return code; 18410bd37d32Smrg } 18420bd37d32Smrg#endif 18430bd37d32Smrg 1844d522f475Smrg releaseWindowGCs(xw, win); 1845d522f475Smrg 1846d522f475Smrg xtermCloseFonts(xw, fnts); 1847d522f475Smrg TRACE(("Fail Cgs - xtermLoadFont\n")); 1848d522f475Smrg return 0; 1849d522f475Smrg} 1850d522f475Smrg 18519a64e1c5Smrg#if OPT_WIDE_ATTRS 18529a64e1c5Smrg/* 18539a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts. 18549a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font. 18559a64e1c5Smrg */ 18569a64e1c5Smrgvoid 18579a64e1c5SmrgxtermLoadItalics(XtermWidget xw) 18589a64e1c5Smrg{ 18599a64e1c5Smrg TScreen *screen = TScreenOf(xw); 18609a64e1c5Smrg 1861c48a5815Smrg if (UseItalicFont(screen) && !screen->ifnts_ok) { 1862037a25ddSmrg int n; 1863dfb07bc7Smrg FontNameProperties *fp; 1864dfb07bc7Smrg XTermFonts *data; 1865037a25ddSmrg 18669a64e1c5Smrg screen->ifnts_ok = True; 18679a64e1c5Smrg for (n = 0; n < fMAX; ++n) { 1868dfb07bc7Smrg switch (n) { 1869dfb07bc7Smrg case fNorm: 1870dfb07bc7Smrg /* FALLTHRU */ 1871dfb07bc7Smrg case fBold: 1872dfb07bc7Smrg /* FALLTHRU */ 1873dfb07bc7Smrg#if OPT_WIDE_CHARS 1874dfb07bc7Smrg case fWide: 1875dfb07bc7Smrg /* FALLTHRU */ 1876dfb07bc7Smrg case fWBold: 1877dfb07bc7Smrg#endif 1878dfb07bc7Smrg /* FALLTHRU */ 1879dfb07bc7Smrg data = getItalicFont(screen, n); 1880037a25ddSmrg 1881dfb07bc7Smrg /* 1882dfb07bc7Smrg * FIXME - need to handle font-leaks 1883dfb07bc7Smrg */ 1884dfb07bc7Smrg data->fs = 0; 1885dfb07bc7Smrg if (getNormalFont(screen, n)->fs != 0 && 1886dfb07bc7Smrg (fp = get_font_name_props(screen->display, 1887dfb07bc7Smrg getNormalFont(screen, n)->fs, 1888dfb07bc7Smrg 0)) != 0) { 1889dfb07bc7Smrg if (!open_italic_font(xw, n, fp, data)) { 1890dfb07bc7Smrg if (n > 0) { 1891dfb07bc7Smrg xtermCopyFontInfo(data, 1892dfb07bc7Smrg getItalicFont(screen, n - 1)); 1893dfb07bc7Smrg } else { 1894dfb07bc7Smrg xtermOpenFont(xw, 1895dfb07bc7Smrg getNormalFont(screen, n)->fn, 1896dfb07bc7Smrg data, False); 18979a64e1c5Smrg } 18989a64e1c5Smrg } 18999a64e1c5Smrg } 1900dfb07bc7Smrg break; 19019a64e1c5Smrg } 19029a64e1c5Smrg } 19039a64e1c5Smrg } 19049a64e1c5Smrg} 19059a64e1c5Smrg#endif 19069a64e1c5Smrg 1907d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1908d522f475Smrg/* 1909d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action. 1910d522f475Smrg */ 1911dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \ 1912492d43a5Smrg if (IsEmpty(dst.name)) { \ 1913dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \ 19149a64e1c5Smrg dst.name = x_strdup(src.name); \ 1915d522f475Smrg } else { \ 1916dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1917dfb07bc7Smrg } 1918dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \ 1919dfb07bc7Smrg if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \ 1920dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \ 1921dfb07bc7Smrg } else { \ 1922dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \ 1923d522f475Smrg } 1924d522f475Smrg 1925dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \ 1926e39b573cSmrg if (IsEmpty(dst.name)) { \ 1927e39b573cSmrg TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1928e39b573cSmrg dst.name = x_strdup(""); \ 1929e39b573cSmrg } else { \ 1930dfb07bc7Smrg TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1931e39b573cSmrg } 1932e39b573cSmrg 19339a64e1c5Smrg#define FREE_MENU_FONTS(dst) \ 19349a64e1c5Smrg TRACE(("FREE_MENU_FONTS " #dst "\n")); \ 19359a64e1c5Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 19369a64e1c5Smrg for (m = 0; m < fMAX; ++m) { \ 19379a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 19389a64e1c5Smrg dst.menu_font_names[n][m] = 0; \ 19399a64e1c5Smrg } \ 19409a64e1c5Smrg } 19419a64e1c5Smrg 1942dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \ 1943d522f475Smrg TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1944d522f475Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1945d522f475Smrg for (m = 0; m < fMAX; ++m) { \ 19469a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 1947492d43a5Smrg dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1948d522f475Smrg } \ 194994644356Smrg TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \ 1950e39b573cSmrg } 1951e39b573cSmrg 19529a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \ 1953dfb07bc7Smrg TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \ 19549a64e1c5Smrg xtermCopyVTFontNames(&target.default_font, &source.default_font) 19559a64e1c5Smrg 1956dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \ 1957dfb07bc7Smrg TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \ 1958dfb07bc7Smrg xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11) 1959dfb07bc7Smrg 1960dfb07bc7Smrgstatic void 1961dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source) 1962dfb07bc7Smrg{ 1963dfb07bc7Smrg#define COPY_IT(name,field) \ 1964dfb07bc7Smrg TRACE((".. "#name" = %s\n", NonNull(source->field))); \ 1965dfb07bc7Smrg free(target->field); \ 1966dfb07bc7Smrg target->field = x_strdup(source->field) 1967dfb07bc7Smrg 1968dfb07bc7Smrg TRACE(("xtermCopyVTFontNames\n")); 1969dfb07bc7Smrg 1970dfb07bc7Smrg COPY_IT(font, f_n); 1971dfb07bc7Smrg COPY_IT(boldFont, f_b); 1972dfb07bc7Smrg 1973dfb07bc7Smrg#if OPT_WIDE_CHARS 1974dfb07bc7Smrg COPY_IT(wideFont, f_w); 1975dfb07bc7Smrg COPY_IT(wideBoldFont, f_wb); 1976dfb07bc7Smrg#endif 1977dfb07bc7Smrg#undef COPY_IT 1978dfb07bc7Smrg} 1979dfb07bc7Smrg 19809a64e1c5Smrgstatic void 1981dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source) 19829a64e1c5Smrg{ 1983dfb07bc7Smrg#define COPY_IT(name,field) \ 1984dfb07bc7Smrg copyFontList(&(target->field), source->field); \ 1985dfb07bc7Smrg TRACE_ARGV(".. " #name, source->field) 1986dfb07bc7Smrg 1987dfb07bc7Smrg (void) xw; 1988dfb07bc7Smrg TRACE(("xtermCopyFontLists %s ->%s\n", 1989dfb07bc7Smrg whichFontList(xw, source), 1990dfb07bc7Smrg whichFontList(xw, target))); 1991dfb07bc7Smrg 1992dfb07bc7Smrg COPY_IT(font, list_n); 1993dfb07bc7Smrg COPY_IT(fontBold, list_b); 1994dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 1995dfb07bc7Smrg COPY_IT(fontItal, list_i); 1996d4fba8b9Smrg COPY_IT(fontBtal, list_bi); 1997dfb07bc7Smrg#endif 19989a64e1c5Smrg#if OPT_WIDE_CHARS 1999dfb07bc7Smrg COPY_IT(wideFont, list_w); 2000dfb07bc7Smrg COPY_IT(wideBoldFont, list_wb); 2001dfb07bc7Smrg COPY_IT(wideItalFont, list_wi); 2002d4fba8b9Smrg COPY_IT(wideBtalFont, list_wbi); 20039a64e1c5Smrg#endif 2004dfb07bc7Smrg#undef COPY_IT 20059a64e1c5Smrg} 20069a64e1c5Smrg 2007e39b573cSmrgvoid 2008e39b573cSmrgxtermSaveVTFonts(XtermWidget xw) 2009e39b573cSmrg{ 2010e39b573cSmrg TScreen *screen = TScreenOf(xw); 2011e39b573cSmrg Cardinal n, m; 2012e39b573cSmrg 2013e39b573cSmrg if (!screen->savedVTFonts) { 2014e39b573cSmrg 2015e39b573cSmrg screen->savedVTFonts = True; 2016e39b573cSmrg TRACE(("xtermSaveVTFonts saving original\n")); 20179a64e1c5Smrg COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc); 2018dfb07bc7Smrg COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work); 2019dfb07bc7Smrg COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 2020e39b573cSmrg } 2021e39b573cSmrg} 2022e39b573cSmrg 2023e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 2024e39b573cSmrg#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 2025e39b573cSmrg 2026e39b573cSmrgstatic Boolean 2027e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b) 2028e39b573cSmrg{ 2029e39b573cSmrg Boolean result = True; 2030e39b573cSmrg 2031e39b573cSmrg if (!SAME_MEMBER(default_font.f_n) 2032e39b573cSmrg || !SAME_MEMBER(default_font.f_b) 20330bd37d32Smrg#if OPT_WIDE_CHARS 2034e39b573cSmrg || !SAME_MEMBER(default_font.f_w) 20350bd37d32Smrg || !SAME_MEMBER(default_font.f_wb) 20360bd37d32Smrg#endif 20370bd37d32Smrg ) { 2038e39b573cSmrg TRACE(("sameSubResources: default_font differs\n")); 2039e39b573cSmrg result = False; 2040e39b573cSmrg } else { 2041037a25ddSmrg int n; 2042037a25ddSmrg 2043e39b573cSmrg for (n = 0; n < NMENUFONTS; ++n) { 2044e39b573cSmrg if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 2045e39b573cSmrg TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 2046e39b573cSmrg result = False; 2047e39b573cSmrg break; 2048e39b573cSmrg } 2049d522f475Smrg } 2050e39b573cSmrg } 2051e39b573cSmrg 2052e39b573cSmrg return result; 2053e39b573cSmrg} 2054d522f475Smrg 2055d522f475Smrg/* 2056d522f475Smrg * Load the "VT" font names from the given subresource name/class. These 2057d522f475Smrg * correspond to the VT100 resources. 2058d522f475Smrg */ 2059d522f475Smrgstatic Bool 206020d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 2061d522f475Smrg{ 2062e39b573cSmrg SubResourceRec subresourceRec; 2063e39b573cSmrg SubResourceRec referenceRec; 2064d522f475Smrg 2065d522f475Smrg /* 2066d522f475Smrg * These are duplicates of the VT100 font resources, but with a special 2067d522f475Smrg * application/classname passed in to distinguish them. 2068d522f475Smrg */ 2069d522f475Smrg static XtResource font_resources[] = 2070d522f475Smrg { 2071d522f475Smrg Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 2072d522f475Smrg Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 2073d522f475Smrg#if OPT_WIDE_CHARS 2074d522f475Smrg Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 2075d522f475Smrg Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 2076d522f475Smrg#endif 2077d522f475Smrg Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 2078d522f475Smrg Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 2079d522f475Smrg Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 2080d522f475Smrg Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 2081d522f475Smrg Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 2082d522f475Smrg Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 2083d4fba8b9Smrg Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL), 2084d522f475Smrg }; 2085d522f475Smrg Cardinal n, m; 2086d522f475Smrg Bool status = True; 2087956cc18dSsnj TScreen *screen = TScreenOf(xw); 2088d522f475Smrg 2089e39b573cSmrg TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 2090e39b573cSmrg NonNull(myName), NonNull(myClass))); 2091d522f475Smrg 2092e39b573cSmrg xtermSaveVTFonts(xw); 2093d522f475Smrg 2094492d43a5Smrg if (IsEmpty(myName)) { 2095d522f475Smrg TRACE(("xtermLoadVTFonts restoring original\n")); 20969a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts); 2097dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts); 20989a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2099dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 2100d522f475Smrg } else { 2101d522f475Smrg TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 2102d522f475Smrg 2103e39b573cSmrg memset(&referenceRec, 0, sizeof(referenceRec)); 2104d522f475Smrg memset(&subresourceRec, 0, sizeof(subresourceRec)); 2105956cc18dSsnj XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 2106d522f475Smrg myName, myClass, 2107d522f475Smrg font_resources, 2108d522f475Smrg (Cardinal) XtNumber(font_resources), 2109d522f475Smrg NULL, (Cardinal) 0); 2110d522f475Smrg 2111e39b573cSmrg /* 2112e39b573cSmrg * XtGetSubresources returns no status, so we compare the returned 2113e39b573cSmrg * data against a zero'd struct to see if any data is returned. 2114e39b573cSmrg */ 2115e39b573cSmrg if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 2116e39b573cSmrg && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 2117e39b573cSmrg 2118e39b573cSmrg screen->mergedVTFonts = True; 2119d522f475Smrg 21209a64e1c5Smrg /* 21219a64e1c5Smrg * To make it simple, reallocate the strings returned by 21229a64e1c5Smrg * XtGetSubresources. We can free our own strings, but not theirs. 21239a64e1c5Smrg */ 21249a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_n); 21259a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_b); 21269a64e1c5Smrg#if OPT_WIDE_CHARS 21279a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_w); 21289a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_wb); 21299a64e1c5Smrg#endif 21309a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 21319a64e1c5Smrg ALLOC_STRING(subresourceRec.MenuFontName(n)); 21329a64e1c5Smrg } 21339a64e1c5Smrg 2134dfb07bc7Smrg /* 2135dfb07bc7Smrg * Now, save the string to a font-list for consistency 2136dfb07bc7Smrg */ 2137dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \ 2138dfb07bc7Smrg save2FontList(xw, "cached", \ 2139dfb07bc7Smrg &(subresourceRec.fonts), \ 2140dfb07bc7Smrg which, \ 2141dfb07bc7Smrg subresourceRec.default_font.field, False) 2142dfb07bc7Smrg 2143dfb07bc7Smrg ALLOC_SUBLIST(fNorm, f_n); 2144dfb07bc7Smrg ALLOC_SUBLIST(fBold, f_b); 2145dfb07bc7Smrg#if OPT_WIDE_CHARS 2146dfb07bc7Smrg ALLOC_SUBLIST(fWide, f_w); 2147dfb07bc7Smrg ALLOC_SUBLIST(fWBold, f_wb); 2148dfb07bc7Smrg#endif 2149dfb07bc7Smrg 2150d522f475Smrg /* 2151d522f475Smrg * If a particular resource value was not found, use the original. 2152d522f475Smrg */ 2153dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n); 2154dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b); 2155dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_n); 2156dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_b); 2157d522f475Smrg#if OPT_WIDE_CHARS 2158dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w); 2159dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb); 2160dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_w); 2161dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_wb); 2162d522f475Smrg#endif 21639a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2164dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n)); 21659a64e1c5Smrg } 2166d522f475Smrg 2167d522f475Smrg /* 2168d522f475Smrg * Finally, copy the subresource data to the widget. 2169d522f475Smrg */ 21709a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, subresourceRec); 2171dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, subresourceRec); 21729a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2173dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, subresourceRec); 21749a64e1c5Smrg 21759a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontMenu_default)); 21769a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fBold]); 2177dfb07bc7Smrg screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw)); 2178dfb07bc7Smrg screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw)); 2179d522f475Smrg#if OPT_WIDE_CHARS 21809a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWide]); 21819a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWBold]); 2182dfb07bc7Smrg screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw)); 2183dfb07bc7Smrg screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw)); 2184d522f475Smrg#endif 21859a64e1c5Smrg /* 21869a64e1c5Smrg * And remove our copies of strings. 21879a64e1c5Smrg */ 21889a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_n); 21899a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_b); 21909a64e1c5Smrg#if OPT_WIDE_CHARS 21919a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_w); 21929a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_wb); 21939a64e1c5Smrg#endif 21949a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 21959a64e1c5Smrg FREE_STRING(subresourceRec.MenuFontName(n)); 21969a64e1c5Smrg } 2197d522f475Smrg } else { 2198d522f475Smrg TRACE(("...no resources found\n")); 2199d522f475Smrg status = False; 2200d522f475Smrg } 2201d522f475Smrg } 2202dfb07bc7Smrg TRACE((".. xtermLoadVTFonts: %d\n", status)); 2203d522f475Smrg return status; 2204d522f475Smrg} 2205d522f475Smrg 2206d522f475Smrg#if OPT_WIDE_CHARS 2207d522f475Smrgstatic Bool 22089a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk) 2209d522f475Smrg{ 2210d522f475Smrg Bool result = False; 2211d522f475Smrg 2212d522f475Smrg (void) tag; 2213d522f475Smrg if (okFont(fp)) { 2214d522f475Smrg unsigned count = countGlyphs(fp); 2215d522f475Smrg TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 2216d522f475Smrg result = (count > 256) ? True : False; 2217d522f475Smrg } else { 2218d522f475Smrg result = nullOk; 2219d522f475Smrg } 2220d522f475Smrg return result; 2221d522f475Smrg} 2222d522f475Smrg 2223d522f475Smrg/* 2224d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts. 2225d522f475Smrg * 2226d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not 2227d522f475Smrg * been setup, so we pass nullOk=True to isWideFont(). 2228d522f475Smrg * 2229d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry 2230d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide. 2231d522f475Smrg */ 2232d522f475SmrgBool 2233d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk) 2234d522f475Smrg{ 2235956cc18dSsnj TScreen *screen = TScreenOf(xw); 2236d522f475Smrg Bool result; 2237d522f475Smrg 2238d4fba8b9Smrg if (EmptyFont(GetNormalFont(screen, fWide)->fs)) { 2239d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2240d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk)); 2241d522f475Smrg } else { 2242d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk) 2243d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fWBold)->fs, 2244dfb07bc7Smrg "wide-bold", nullOk)); 2245d522f475Smrg if (result && !screen->utf8_latin1) { 2246d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2247d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, 2248dfb07bc7Smrg "bold", nullOk)); 2249d522f475Smrg } 2250d522f475Smrg } 2251d522f475Smrg if (!result) { 2252d522f475Smrg TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 2253e39b573cSmrg result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 2254d522f475Smrg } 2255d522f475Smrg TRACE(("xtermLoadWideFonts:%d\n", result)); 2256d522f475Smrg return result; 2257d522f475Smrg} 2258d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2259d522f475Smrg 2260d522f475Smrg/* 2261d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts. 2262d522f475Smrg */ 2263d522f475SmrgBool 2264956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw) 2265d522f475Smrg{ 2266d522f475Smrg Bool result; 2267956cc18dSsnj result = xtermLoadVTFonts(xw, NULL, NULL); 2268d522f475Smrg TRACE(("xtermLoadDefaultFonts:%d\n", result)); 2269d522f475Smrg return result; 2270d522f475Smrg} 2271d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 2272d522f475Smrg 2273d522f475Smrg#if OPT_LOAD_VTFONTS 2274d522f475Smrgvoid 2275d522f475SmrgHandleLoadVTFonts(Widget w, 22769a64e1c5Smrg XEvent *event GCC_UNUSED, 2277d4fba8b9Smrg String *params, 2278d4fba8b9Smrg Cardinal *param_count) 2279d522f475Smrg{ 2280956cc18dSsnj XtermWidget xw; 2281956cc18dSsnj 2282956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2283037a25ddSmrg static char empty[] = ""; /* appease strict compilers */ 2284037a25ddSmrg 2285956cc18dSsnj TScreen *screen = TScreenOf(xw); 2286492d43a5Smrg char name_buf[80]; 2287492d43a5Smrg String name = (String) ((*param_count > 0) ? params[0] : empty); 228894644356Smrg char *myName = MyStackAlloc(strlen(name) + 1, name_buf); 2289d522f475Smrg 2290d522f475Smrg TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 229194644356Smrg if (myName != 0) { 2292037a25ddSmrg char class_buf[80]; 229394644356Smrg String convert = (String) ((*param_count > 1) ? params[1] : myName); 229494644356Smrg char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf); 229594644356Smrg 229694644356Smrg strcpy(myName, name); 229794644356Smrg if (myClass != 0) { 229894644356Smrg strcpy(myClass, convert); 229994644356Smrg if (*param_count == 1) 230094644356Smrg myClass[0] = x_toupper(myClass[0]); 230194644356Smrg 230294644356Smrg if (xtermLoadVTFonts(xw, myName, myClass)) { 2303037a25ddSmrg int n; 230494644356Smrg /* 230594644356Smrg * When switching fonts, try to preserve the font-menu 230694644356Smrg * selection, since it is less surprising to do that (if 230794644356Smrg * the font-switching can be undone) than to switch to 230894644356Smrg * "Default". 230994644356Smrg */ 231094644356Smrg int font_number = screen->menu_font_number; 231194644356Smrg if (font_number > fontMenu_lastBuiltin) 231294644356Smrg font_number = fontMenu_lastBuiltin; 231394644356Smrg for (n = 0; n < NMENUFONTS; ++n) { 231494644356Smrg screen->menu_font_sizes[n] = 0; 231594644356Smrg } 2316dfb07bc7Smrg if (font_number == fontMenu_default) { 2317dfb07bc7Smrg SetVTFont(xw, font_number, True, defaultVTFontNames(xw)); 2318dfb07bc7Smrg } else { 2319dfb07bc7Smrg SetVTFont(xw, font_number, True, NULL); 2320dfb07bc7Smrg } 232194644356Smrg } 232294644356Smrg MyStackFree(myClass, class_buf); 23239a64e1c5Smrg } 232494644356Smrg MyStackFree(myName, name_buf); 2325d522f475Smrg } 2326d522f475Smrg } 2327d522f475Smrg} 2328d522f475Smrg#endif /* OPT_LOAD_VTFONTS */ 2329d522f475Smrg 2330d522f475Smrg/* 2331d522f475Smrg * Set the limits for the box that outlines the cursor. 2332d522f475Smrg */ 2333d522f475Smrgvoid 2334fa3f02f3SmrgxtermSetCursorBox(TScreen *screen) 2335d522f475Smrg{ 2336d522f475Smrg static XPoint VTbox[NBOX]; 2337d522f475Smrg XPoint *vp; 23382eaa94a1Schristos int fw = FontWidth(screen) - 1; 23392eaa94a1Schristos int fh = FontHeight(screen) - 1; 23400bd37d32Smrg int ww = isCursorBar(screen) ? 1 : fw; 23410bd37d32Smrg int hh = isCursorUnderline(screen) ? 1 : fh; 2342d522f475Smrg 2343d522f475Smrg vp = &VTbox[1]; 23440bd37d32Smrg (vp++)->x = (short) ww; 23452eaa94a1Schristos (vp++)->y = (short) hh; 23460bd37d32Smrg (vp++)->x = (short) -ww; 23472eaa94a1Schristos vp->y = (short) -hh; 23482eaa94a1Schristos 2349d522f475Smrg screen->box = VTbox; 2350d522f475Smrg} 2351d522f475Smrg 2352d4fba8b9Smrg#if OPT_RENDERFONT 2353d4fba8b9Smrg 2354d4fba8b9Smrg#define CACHE_XFT(dst,src) if (src.font != 0) {\ 2355d4fba8b9Smrg int err = checkXftWidth(xw, &(dst[fontnum]), &src);\ 2356d4fba8b9Smrg TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\ 2357d522f475Smrg #dst,\ 2358d4fba8b9Smrg fontnum,\ 2359d4fba8b9Smrg src.font->height,\ 2360d4fba8b9Smrg src.font->ascent,\ 2361d4fba8b9Smrg src.font->descent,\ 2362d4fba8b9Smrg ((src.font->ascent + src.font->descent) > src.font->height ? "*" : ""),\ 2363d4fba8b9Smrg src.font->max_advance_width,\ 2364956cc18dSsnj dst[fontnum].map.min_width,\ 2365d4fba8b9Smrg dst[fontnum].map.mixed ? " mixed" : "",\ 2366d4fba8b9Smrg err ? " ERROR" : ""));\ 2367d4fba8b9Smrg if (err) {\ 2368d4fba8b9Smrg xtermCloseXft(screen, &src);\ 2369d4fba8b9Smrg memset((&dst[fontnum]), 0, sizeof(dst[fontnum]));\ 2370d4fba8b9Smrg failed += err;\ 2371d4fba8b9Smrg }\ 2372d522f475Smrg } 2373d522f475Smrg 2374dfb07bc7Smrg#if OPT_REPORT_FONTS 237520d2c4d2Smrgstatic FcChar32 23769a64e1c5SmrgxtermXftFirstChar(XftFont *xft) 237720d2c4d2Smrg{ 237820d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 237920d2c4d2Smrg FcChar32 next; 238020d2c4d2Smrg FcChar32 first; 238120d2c4d2Smrg int i; 238220d2c4d2Smrg 238320d2c4d2Smrg first = FcCharSetFirstPage(xft->charset, map, &next); 23849a64e1c5Smrg for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { 238520d2c4d2Smrg if (map[i]) { 238620d2c4d2Smrg FcChar32 bits = map[i]; 2387fa3f02f3Smrg first += (FcChar32) i *32; 238820d2c4d2Smrg while (!(bits & 0x1)) { 238920d2c4d2Smrg bits >>= 1; 239020d2c4d2Smrg first++; 239120d2c4d2Smrg } 239220d2c4d2Smrg break; 239320d2c4d2Smrg } 23949a64e1c5Smrg } 239520d2c4d2Smrg return first; 239620d2c4d2Smrg} 239720d2c4d2Smrg 239820d2c4d2Smrgstatic FcChar32 23999a64e1c5SmrgxtermXftLastChar(XftFont *xft) 240020d2c4d2Smrg{ 240120d2c4d2Smrg FcChar32 this, last, next; 240220d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 240320d2c4d2Smrg int i; 240420d2c4d2Smrg last = FcCharSetFirstPage(xft->charset, map, &next); 240520d2c4d2Smrg while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 240620d2c4d2Smrg last = this; 2407fa3f02f3Smrg last &= (FcChar32) ~ 0xff; 24089a64e1c5Smrg for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) { 240920d2c4d2Smrg if (map[i]) { 241020d2c4d2Smrg FcChar32 bits = map[i]; 2411fa3f02f3Smrg last += (FcChar32) i *32 + 31; 241220d2c4d2Smrg while (!(bits & 0x80000000)) { 241320d2c4d2Smrg last--; 241420d2c4d2Smrg bits <<= 1; 241520d2c4d2Smrg } 241620d2c4d2Smrg break; 241720d2c4d2Smrg } 24189a64e1c5Smrg } 2419dfb07bc7Smrg return (FcChar32) last; 242020d2c4d2Smrg} 2421dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 242220d2c4d2Smrg 2423d4fba8b9Smrg#if OPT_TRACE 2424d4fba8b9Smrg 2425d4fba8b9Smrg#if !OPT_WIDE_CHARS 2426d4fba8b9Smrgstatic Char * 2427d4fba8b9SmrgconvertToUTF8(Char *buffer, int c) 2428d4fba8b9Smrg{ 2429d4fba8b9Smrg buffer[0] = (Char) c; 2430d4fba8b9Smrg buffer[1] = 0; 2431d4fba8b9Smrg return buffer; 2432d4fba8b9Smrg} 2433d4fba8b9Smrg#endif 2434d4fba8b9Smrg 243520d2c4d2Smrgstatic void 24369a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data) 243720d2c4d2Smrg{ 243820d2c4d2Smrg XftFont *xft = data->font; 243920d2c4d2Smrg TScreen *screen = TScreenOf(xw); 244020d2c4d2Smrg VTwin *win = WhichVWin(screen); 244120d2c4d2Smrg 244220d2c4d2Smrg FcChar32 c; 244320d2c4d2Smrg FcChar32 first = xtermXftFirstChar(xft); 244420d2c4d2Smrg FcChar32 last = xtermXftLastChar(xft); 2445d4fba8b9Smrg FcChar32 dump; 244620d2c4d2Smrg unsigned count = 0; 2447d4fba8b9Smrg unsigned too_high = 0; 2448d4fba8b9Smrg unsigned too_wide = 0; 2449d4fba8b9Smrg Boolean skip = False; 2450d4fba8b9Smrg 2451d4fba8b9Smrg TRACE(("dumpXft " TRACE_L "\n")); 2452d4fba8b9Smrg TRACE(("\tdata range U+%04X..U+%04X\n", first, last)); 2453d4fba8b9Smrg TRACE(("\tcode\tcells\tdimensions\n")); 2454d4fba8b9Smrg#if OPT_TRACE < 2 2455d4fba8b9Smrg dump = 255; 2456d4fba8b9Smrg#else 2457d4fba8b9Smrg dump = last; 2458d4fba8b9Smrg#endif 245920d2c4d2Smrg for (c = first; c <= last; ++c) { 246020d2c4d2Smrg if (FcCharSetHasChar(xft->charset, c)) { 2461c48a5815Smrg int width = CharWidth(screen, c); 246220d2c4d2Smrg XGlyphInfo extents; 2463d4fba8b9Smrg Boolean big_x; 2464d4fba8b9Smrg Boolean big_y; 246520d2c4d2Smrg 246620d2c4d2Smrg XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2467d4fba8b9Smrg big_x = (extents.width > win->f_width); 2468d4fba8b9Smrg big_y = (extents.height > win->f_height); 2469d4fba8b9Smrg 2470d4fba8b9Smrg if (c <= dump) { 2471d4fba8b9Smrg Char buffer[80]; 2472d4fba8b9Smrg 2473d4fba8b9Smrg *convertToUTF8(buffer, c) = '\0'; 2474d4fba8b9Smrg TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n", 2475d4fba8b9Smrg (big_y ? "y" : ""), 2476d4fba8b9Smrg (big_x ? "x" : ""), 2477d4fba8b9Smrg c, width, 2478d4fba8b9Smrg ((double) extents.height) / win->f_height, 2479d4fba8b9Smrg ((double) extents.width) / win->f_width, 2480d4fba8b9Smrg buffer)); 2481d4fba8b9Smrg } else if (!skip) { 2482d4fba8b9Smrg skip = True; 2483d4fba8b9Smrg TRACE(("\t...skipping\n")); 2484d4fba8b9Smrg } 2485d4fba8b9Smrg if (big_y) 2486d4fba8b9Smrg ++too_high; 2487d4fba8b9Smrg if (big_x) 2488d4fba8b9Smrg ++too_wide; 248920d2c4d2Smrg ++count; 249020d2c4d2Smrg } 249120d2c4d2Smrg } 2492d4fba8b9Smrg TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide)); 249320d2c4d2Smrg} 249420d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data) 249520d2c4d2Smrg#else 249620d2c4d2Smrg#define DUMP_XFT(xw, data) /* nothing */ 249720d2c4d2Smrg#endif 249820d2c4d2Smrg 2499d4fba8b9Smrg/* 2500d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a 2501d4fba8b9Smrg * problem with web browsers. As of 2018/12 (4 years later), Xft does not work 2502d4fba8b9Smrg * with that. Even with this workaround, fontconfig has at least one bug which 2503d4fba8b9Smrg * causes it to crash (Debian #917034). 2504d4fba8b9Smrg */ 2505d4fba8b9Smrg#ifdef FC_COLOR 2506d4fba8b9Smrg#define GetFcBool(pattern, what) \ 2507d4fba8b9Smrg (FcPatternGetBool(pattern, what, 0, &fcbogus) == FcResultMatch) 2508d4fba8b9Smrg 2509d4fba8b9Smrgstatic Boolean 2510d4fba8b9SmrgisBogusXft(XftFont *font) 2511d4fba8b9Smrg{ 2512d4fba8b9Smrg Boolean result = False; 2513d4fba8b9Smrg if (font != 0) { 2514d4fba8b9Smrg FcBool fcbogus; 2515d4fba8b9Smrg if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) { 2516d4fba8b9Smrg TRACE(("...matched color-bitmap font\n")); 2517d4fba8b9Smrg result = True; 2518d4fba8b9Smrg } else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) { 2519d4fba8b9Smrg TRACE(("...matched non-outline font\n")); 2520d4fba8b9Smrg /* This is legal for regular bitmap fonts - fontconfig attempts to 2521d4fba8b9Smrg * find a match - but problematic for misencoded color-bitmap fonts. 2522d4fba8b9Smrg */ 2523d4fba8b9Smrg } 2524d4fba8b9Smrg } 2525d4fba8b9Smrg return result; 2526d4fba8b9Smrg} 2527d4fba8b9Smrg#endif 2528d4fba8b9Smrg 2529d4fba8b9Smrg#if OPT_BOX_CHARS 2530956cc18dSsnjstatic void 2531d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state) 2532d4fba8b9Smrg{ 2533d4fba8b9Smrg TRACE(("setBrokenBoxChars %s\n", BtoS(state))); 2534d4fba8b9Smrg term->work.broken_box_chars = (Boolean) state; 2535d4fba8b9Smrg TScreenOf(xw)->broken_box_chars = (Boolean) state; 2536d4fba8b9Smrg update_font_boxchars(); 2537d4fba8b9Smrg} 2538d4fba8b9Smrg 2539d4fba8b9Smrg#else 2540d4fba8b9Smrg#define setBrokenBoxChars(xw, state) /* nothing */ 2541d4fba8b9Smrg#endif 2542d4fba8b9Smrg 2543d4fba8b9Smrgstatic Boolean 2544d4fba8b9SmrgcheckedXftWidth(Display *dpy, 2545d4fba8b9Smrg XTermXftFonts *source, 2546d4fba8b9Smrg unsigned limit, 2547d4fba8b9Smrg Dimension *width, 2548d4fba8b9Smrg FcChar32 c) 2549d4fba8b9Smrg{ 2550d4fba8b9Smrg Boolean result = False; 2551d4fba8b9Smrg 2552d4fba8b9Smrg if (FcCharSetHasChar(source->font->charset, c)) { 2553d4fba8b9Smrg XGlyphInfo extents; 2554d4fba8b9Smrg 2555d4fba8b9Smrg result = True; 2556d4fba8b9Smrg XftTextExtents32(dpy, source->font, &c, 1, &extents); 2557d4fba8b9Smrg if (*width < extents.width && extents.width <= limit) { 2558d4fba8b9Smrg *width = extents.width; 2559d4fba8b9Smrg } 2560d4fba8b9Smrg } 2561d4fba8b9Smrg return result; 2562d4fba8b9Smrg} 2563d4fba8b9Smrg 2564d4fba8b9Smrgstatic int 2565d4fba8b9SmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *target, XTermXftFonts *source) 2566956cc18dSsnj{ 2567956cc18dSsnj FcChar32 c; 2568d4fba8b9Smrg FcChar32 last = xtermXftLastChar(source->font); 2569d4fba8b9Smrg Dimension limit = (Dimension) source->font->max_advance_width; 2570956cc18dSsnj Dimension width = 0; 2571d4fba8b9Smrg Dimension width2 = 0; 2572d4fba8b9Smrg int failed = 0; 2573d4fba8b9Smrg#if OPT_WIDE_CHARS 2574d4fba8b9Smrg Cardinal n; 2575d4fba8b9Smrg#endif 2576956cc18dSsnj 2577d4fba8b9Smrg target->font = source->font; 2578d4fba8b9Smrg target->pattern = source->pattern; 2579d4fba8b9Smrg target->map.min_width = 0; 2580d4fba8b9Smrg target->map.max_width = limit; 2581d4fba8b9Smrg 2582d4fba8b9Smrg#if OPT_WIDE_CHARS 2583d4fba8b9Smrg /* 2584d4fba8b9Smrg * Check if the line-drawing characters are all provided in the font. 2585d4fba8b9Smrg * If so, take that into account for the cell-widths. 2586d4fba8b9Smrg */ 2587d4fba8b9Smrg for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) { 2588d4fba8b9Smrg if (!checkedXftWidth(XtDisplay(xw), 2589d4fba8b9Smrg source, 2590d4fba8b9Smrg limit, 2591d4fba8b9Smrg &width2, unicode_boxes[n].code)) { 2592d4fba8b9Smrg width2 = 0; 2593d4fba8b9Smrg TRACE(("font omits U+%04X line-drawing symbol\n", 2594d4fba8b9Smrg unicode_boxes[n].code)); 2595d4fba8b9Smrg break; 2596d4fba8b9Smrg } 2597d4fba8b9Smrg } 2598d4fba8b9Smrg#else 2599d4fba8b9Smrg (void) width2; 2600d4fba8b9Smrg#endif 2601d4fba8b9Smrg 2602d4fba8b9Smrg if (width2 > 0) { 2603d4fba8b9Smrg Dimension check = (Dimension) (limit + 1) / 2; 2604d4fba8b9Smrg TRACE(("font provides VT100-style line-drawing\n")); 2605d4fba8b9Smrg /* 2606d4fba8b9Smrg * The "VT100 line-drawing" characters happen to be all "ambiguous 2607d4fba8b9Smrg * width" in Unicode's scheme. That means that they could be twice as 2608d4fba8b9Smrg * wide as the Latin-1 characters. 2609d4fba8b9Smrg */ 2610d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n)) 2611d4fba8b9Smrg if (width2 > FC_ERR(check)) { 2612d4fba8b9Smrg TRACE(("line-drawing characters appear to be double-width (ignore)\n")); 2613d4fba8b9Smrg setBrokenBoxChars(xw, True); 2614d4fba8b9Smrg } else if (width2 > width) { 2615d4fba8b9Smrg width = width2; 2616d4fba8b9Smrg } 2617d4fba8b9Smrg } else { 2618d4fba8b9Smrg TRACE(("font does NOT provide VT100-style line-drawing\n")); 2619d4fba8b9Smrg setBrokenBoxChars(xw, True); 2620d4fba8b9Smrg } 2621956cc18dSsnj 262220d2c4d2Smrg /* 2623d4fba8b9Smrg * For each printable code, ask what its width is. Given the maximum width 2624d4fba8b9Smrg * for those, we have a reasonable estimate of the single-column width. 262520d2c4d2Smrg * 262620d2c4d2Smrg * Ignore control characters - their extent information is misleading. 262720d2c4d2Smrg */ 2628956cc18dSsnj for (c = 32; c < 256; ++c) { 2629c48a5815Smrg if (CharWidth(TScreenOf(xw), c) <= 0) 263020d2c4d2Smrg continue; 2631d4fba8b9Smrg if (FcCharSetHasChar(source->font->charset, c)) { 2632d4fba8b9Smrg (void) checkedXftWidth(XtDisplay(xw), 2633d4fba8b9Smrg source, 2634d4fba8b9Smrg target->map.max_width, 2635d4fba8b9Smrg &width, c); 2636d4fba8b9Smrg } 2637d4fba8b9Smrg } 2638956cc18dSsnj 2639d4fba8b9Smrg /* 2640d4fba8b9Smrg * Sometimes someone uses a symbol font which has no useful ASCII or 2641d4fba8b9Smrg * Latin-1 characters. Allow that, in case they did it intentionally. 2642d4fba8b9Smrg */ 2643d4fba8b9Smrg if (width == 0) { 2644d4fba8b9Smrg failed = 1; 2645d4fba8b9Smrg if (last >= 256) { 2646d4fba8b9Smrg width = target->map.max_width; 2647956cc18dSsnj } 2648956cc18dSsnj } 2649d4fba8b9Smrg target->map.min_width = width; 2650d4fba8b9Smrg target->map.mixed = (target->map.max_width >= (target->map.min_width + 1)); 2651d4fba8b9Smrg return failed; 2652956cc18dSsnj} 2653956cc18dSsnj 2654dfb07bc7Smrg#if OPT_REPORT_FONTS 2655fa3f02f3Smrgstatic void 2656fa3f02f3SmrgreportXftFonts(XtermWidget xw, 26579a64e1c5Smrg XftFont *fp, 2658fa3f02f3Smrg const char *name, 2659fa3f02f3Smrg const char *tag, 26609a64e1c5Smrg XftPattern *match) 2661fa3f02f3Smrg{ 2662fa3f02f3Smrg if (resource.reportFonts) { 2663fa3f02f3Smrg char buffer[1024]; 2664fa3f02f3Smrg FcChar32 first_char = xtermXftFirstChar(fp); 2665fa3f02f3Smrg FcChar32 last_char = xtermXftLastChar(fp); 2666fa3f02f3Smrg FcChar32 ch; 2667fa3f02f3Smrg unsigned missing = 0; 2668fa3f02f3Smrg 266994644356Smrg printf("Loaded XftFonts(%s[%s])\n", name, tag); 2670fa3f02f3Smrg 2671fa3f02f3Smrg for (ch = first_char; ch <= last_char; ++ch) { 2672fa3f02f3Smrg if (xtermXftMissing(xw, fp, ch)) { 2673fa3f02f3Smrg ++missing; 2674fa3f02f3Smrg } 2675fa3f02f3Smrg } 2676fa3f02f3Smrg printf("\t\tfirst char: %u\n", first_char); 2677fa3f02f3Smrg printf("\t\tlast char: %u\n", last_char); 2678fa3f02f3Smrg printf("\t\tmissing-chars: %u\n", missing); 2679fa3f02f3Smrg printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing); 2680fa3f02f3Smrg 2681fa3f02f3Smrg if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 2682fa3f02f3Smrg char *target; 2683fa3f02f3Smrg char *source = buffer; 2684fa3f02f3Smrg while ((target = strtok(source, ":")) != 0) { 2685fa3f02f3Smrg printf("\t%s\n", target); 2686fa3f02f3Smrg source = 0; 2687fa3f02f3Smrg } 2688fa3f02f3Smrg } 2689d4fba8b9Smrg fflush(stdout); 2690fa3f02f3Smrg } 2691fa3f02f3Smrg} 2692dfb07bc7Smrg#else 2693dfb07bc7Smrg#define reportXftFonts(xw, result, name, tag, match) /* empty */ 2694dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 2695fa3f02f3Smrg 2696d4fba8b9Smrg/* 2697d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to 2698d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does 2699d4fba8b9Smrg * this. That is, closing a font-file may leave the data in Xft's cache, while 2700d4fba8b9Smrg * opening a file may free the data used for the match. 2701d4fba8b9Smrg * 2702d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data 2703d4fba8b9Smrg * if it may have been seen before. 2704d4fba8b9Smrg */ 2705d4fba8b9SmrgBoolean 2706d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font) 2707d4fba8b9Smrg{ 2708d4fba8b9Smrg Boolean result = False; 2709d4fba8b9Smrg if (font != 0) { 2710d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2711d4fba8b9Smrg ListXftFonts *p; 2712d4fba8b9Smrg for (p = screen->list_xft_fonts; p != 0; p = p->next) { 2713d4fba8b9Smrg if (p->font == font) { 2714d4fba8b9Smrg result = True; 2715d4fba8b9Smrg break; 2716d4fba8b9Smrg } 2717d4fba8b9Smrg } 2718d4fba8b9Smrg if (!result) { 2719d4fba8b9Smrg p = TypeXtMalloc(ListXftFonts); 2720d4fba8b9Smrg if (p != 0) { 2721d4fba8b9Smrg p->font = font; 2722d4fba8b9Smrg p->next = screen->list_xft_fonts; 2723d4fba8b9Smrg screen->list_xft_fonts = p; 2724d4fba8b9Smrg } 2725d4fba8b9Smrg } 2726d4fba8b9Smrg } 2727d4fba8b9Smrg return result; 2728d4fba8b9Smrg} 2729d4fba8b9Smrg 2730d4fba8b9Smrg/* 2731d4fba8b9Smrg * Drop an entry from the cache, and close the font. 2732d4fba8b9Smrg */ 2733d4fba8b9Smrgvoid 2734d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font) 2735d4fba8b9Smrg{ 2736d4fba8b9Smrg if (font != 0) { 2737d4fba8b9Smrg ListXftFonts *p, *q; 2738d4fba8b9Smrg 2739d4fba8b9Smrg for (p = screen->list_xft_fonts, q = 0; p != 0; q = p, p = p->next) { 2740d4fba8b9Smrg if (p->font == font) { 2741d4fba8b9Smrg XftFontClose(screen->display, font); 2742d4fba8b9Smrg if (q != 0) { 2743d4fba8b9Smrg q->next = p->next; 2744d4fba8b9Smrg } else { 2745d4fba8b9Smrg screen->list_xft_fonts = p->next; 2746d4fba8b9Smrg } 2747d4fba8b9Smrg free(p); 2748d4fba8b9Smrg break; 2749d4fba8b9Smrg } 2750d4fba8b9Smrg } 2751d4fba8b9Smrg } 2752d4fba8b9Smrg} 2753d4fba8b9Smrg 2754d522f475Smrgstatic XftFont * 27559a64e1c5SmrgxtermOpenXft(XtermWidget xw, const char *name, XftPattern *pat, const char *tag) 2756d522f475Smrg{ 2757956cc18dSsnj TScreen *screen = TScreenOf(xw); 2758956cc18dSsnj Display *dpy = screen->display; 2759d522f475Smrg XftResult status; 2760d522f475Smrg XftFont *result = 0; 2761d522f475Smrg 2762d4fba8b9Smrg TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag)); 2763d522f475Smrg if (pat != 0) { 2764d4fba8b9Smrg XftPattern *match; 2765d4fba8b9Smrg 2766d4fba8b9Smrg FcConfigSubstitute(NULL, pat, FcMatchPattern); 2767d4fba8b9Smrg XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat); 2768d4fba8b9Smrg 2769d4fba8b9Smrg match = FcFontMatch(NULL, pat, &status); 2770d522f475Smrg if (match != 0) { 2771d4fba8b9Smrg Boolean maybeReopened = False; 2772d522f475Smrg result = XftFontOpenPattern(dpy, match); 2773d4fba8b9Smrg#ifdef FC_COLOR 2774d4fba8b9Smrg if (result != 0) { 2775d4fba8b9Smrg if (isBogusXft(result)) { 2776d4fba8b9Smrg XftFontClose(dpy, result); 2777d4fba8b9Smrg result = 0; 2778d4fba8b9Smrg maybeReopened = True; 2779d4fba8b9Smrg } 2780d4fba8b9Smrg } 2781d4fba8b9Smrg#endif 2782d522f475Smrg if (result != 0) { 2783d522f475Smrg TRACE(("...matched %s font\n", tag)); 2784d4fba8b9Smrg if (!maybeXftCache(xw, result)) { 2785d4fba8b9Smrg reportXftFonts(xw, result, name, tag, match); 2786d4fba8b9Smrg } 2787d522f475Smrg } else { 2788d4fba8b9Smrg TRACE(("...could not open %s font\n", tag)); 2789d4fba8b9Smrg if (!maybeReopened) 2790d4fba8b9Smrg XftPatternDestroy(match); 2791956cc18dSsnj if (xw->misc.fontWarnings >= fwAlways) { 2792dfb07bc7Smrg cannotFont(xw, "open", tag, name); 2793956cc18dSsnj } 2794d522f475Smrg } 2795d522f475Smrg } else { 2796d522f475Smrg TRACE(("...did not match %s font\n", tag)); 2797956cc18dSsnj if (xw->misc.fontWarnings >= fwResource) { 2798dfb07bc7Smrg cannotFont(xw, "match", tag, name); 2799956cc18dSsnj } 2800d522f475Smrg } 2801d522f475Smrg } 2802d522f475Smrg return result; 2803d522f475Smrg} 2804d522f475Smrg 2805d522f475Smrg#if OPT_SHIFT_FONTS 2806d522f475Smrg/* 2807d522f475Smrg * Don't make a dependency on the math library for a single function. 2808d522f475Smrg * (Newton Raphson). 2809d522f475Smrg */ 2810d522f475Smrgstatic double 28110bd37d32SmrgdimSquareRoot(double value) 2812d522f475Smrg{ 2813d522f475Smrg double result = 0.0; 2814d522f475Smrg if (value > 0.0) { 2815d522f475Smrg int n; 2816d522f475Smrg double older = value; 2817d522f475Smrg for (n = 0; n < 10; ++n) { 2818d522f475Smrg double delta = (older * older - value) / (2.0 * older); 2819d522f475Smrg double newer = older - delta; 2820d522f475Smrg older = newer; 2821d522f475Smrg result = newer; 2822d522f475Smrg if (delta > -0.001 && delta < 0.001) 2823d522f475Smrg break; 2824d522f475Smrg } 2825d522f475Smrg } 2826d522f475Smrg return result; 2827d522f475Smrg} 2828d522f475Smrg#endif 2829d522f475Smrg 2830d4fba8b9Smrg#ifdef DEBUG_XFT 2831d4fba8b9Smrgstatic void 2832d4fba8b9Smrgtrace_xft_glyph(TScreen *screen, XftFont *font, FT_Face face, int code, const char *name) 2833d4fba8b9Smrg{ 2834d4fba8b9Smrg if (!XftGlyphExists(screen->display, font, code)) { 2835d4fba8b9Smrg TRACE(("Xft glyph U+%04X missing :%s\n", code, name)); 2836d4fba8b9Smrg } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 2837d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 2838d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 2839d4fba8b9Smrg code, 2840d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 2841d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 2842d4fba8b9Smrg name)); 2843d4fba8b9Smrg } 2844d4fba8b9Smrg} 2845d4fba8b9Smrg 2846d4fba8b9Smrg#if OPT_WIDE_CHARS 2847d4fba8b9Smrgstatic void 2848d4fba8b9Smrgtrace_xft_line_drawing(TScreen *screen, XftFont *font, FT_Face face) 2849d4fba8b9Smrg{ 2850d4fba8b9Smrg int n; 2851d4fba8b9Smrg for (n = 0; unicode_boxes[n].code != 0; ++n) { 2852d4fba8b9Smrg trace_xft_glyph(screen, font, face, unicode_boxes[n].code, 2853d4fba8b9Smrg unicode_boxes[n].name); 2854d4fba8b9Smrg } 2855d4fba8b9Smrg} 2856d4fba8b9Smrg#else 2857d4fba8b9Smrg#define trace_xft_line_drawing(screen, font, face) /* nothing */ 2858d4fba8b9Smrg#endif 2859d4fba8b9Smrg#endif /* DEBUG_XFT */ 2860d4fba8b9Smrg 2861d4fba8b9Smrg/* 2862d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box. If so, 2863d4fba8b9Smrg * they're not useful. 2864d4fba8b9Smrg */ 2865d4fba8b9Smrg#if OPT_BOX_CHARS 2866d4fba8b9Smrgstatic void 2867d4fba8b9Smrglinedrawing_gaps(XtermWidget xw, XftFont *font) 2868d4fba8b9Smrg{ 2869d4fba8b9Smrg Boolean broken; 2870d4fba8b9Smrg 2871d4fba8b9Smrg#if OPT_WIDE_CHARS 2872d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2873d4fba8b9Smrg int n; 2874d4fba8b9Smrg FT_Face face; 2875d4fba8b9Smrg face = XftLockFace(font); 2876d4fba8b9Smrg broken = False; 2877d4fba8b9Smrg for (n = 0; unicode_boxes[n].code; ++n) { 2878d4fba8b9Smrg unsigned code = unicode_boxes[n].code; 2879d4fba8b9Smrg 2880d4fba8b9Smrg if (!XftGlyphExists(screen->display, font, code)) { 2881d4fba8b9Smrg TRACE(("Xft glyph U+%04X is missing\n", code)); 2882d4fba8b9Smrg broken = True; 2883d4fba8b9Smrg break; 2884d4fba8b9Smrg } 2885d4fba8b9Smrg 2886d4fba8b9Smrg if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 2887d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 2888d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 2889d4fba8b9Smrg code, 2890d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 2891d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 2892d4fba8b9Smrg unicode_boxes[n].name)); 2893d4fba8b9Smrg /* 2894d4fba8b9Smrg * While it is possible for badly-designed fonts to have line 2895d4fba8b9Smrg * drawing characters which do not meet, FreeType aggravates the 2896d4fba8b9Smrg * situation with its rounding. Check for an obvious case where 2897d4fba8b9Smrg * the weights at the ends of a vertical line do not add up. That 2898d4fba8b9Smrg * shows up as two under-weight rows at the beginning/end of the 2899d4fba8b9Smrg * bitmap. 2900d4fba8b9Smrg */ 2901d4fba8b9Smrg if (code == 0x2502) { 2902d4fba8b9Smrg unsigned r, c; 2903d4fba8b9Smrg unsigned mids = 0, ends = 0; 2904d4fba8b9Smrg unsigned char *data = g->bitmap.buffer; 2905d4fba8b9Smrg 2906d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 2907d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 2908d4fba8b9Smrg /* FALLTHRU */ 2909d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 2910d4fba8b9Smrg for (r = 0; r < (unsigned) g->bitmap.rows; ++r) { 2911d4fba8b9Smrg unsigned k = r * (unsigned) g->bitmap.pitch; 2912d4fba8b9Smrg unsigned sum = 0; 2913d4fba8b9Smrg for (c = 0; c < (unsigned) g->bitmap.width; ++c) { 2914d4fba8b9Smrg unsigned xx = 0; 2915d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 2916d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 2917d4fba8b9Smrg xx = (unsigned) ((data[k + (c / 8)] 2918d4fba8b9Smrg >> (c % 8)) & 1); 2919d4fba8b9Smrg break; 2920d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 2921d4fba8b9Smrg xx = data[k + c]; 2922d4fba8b9Smrg break; 2923d4fba8b9Smrg } 2924d4fba8b9Smrg sum += xx; 2925d4fba8b9Smrg TRACE2((" %2x", xx)); 2926d4fba8b9Smrg } 2927d4fba8b9Smrg TRACE2((" = %u\n", sum)); 2928d4fba8b9Smrg if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) { 2929d4fba8b9Smrg mids = sum; 2930d4fba8b9Smrg } else { 2931d4fba8b9Smrg ends += sum; 2932d4fba8b9Smrg } 2933d4fba8b9Smrg } 2934d4fba8b9Smrg TRACE(("...compare middle %u vs ends %u\n", mids, ends)); 2935d4fba8b9Smrg if ((mids > ends) && (g->bitmap.rows < 16)) 2936d4fba8b9Smrg broken = True; 2937d4fba8b9Smrg break; 2938d4fba8b9Smrg default: 2939d4fba8b9Smrg TRACE(("FIXME pixel_mode %d not handled\n", 2940d4fba8b9Smrg g->bitmap.pixel_mode)); 2941d4fba8b9Smrg break; 2942d4fba8b9Smrg } 2943d4fba8b9Smrg if (broken) 2944d4fba8b9Smrg break; 2945d4fba8b9Smrg } 2946d4fba8b9Smrg /* 2947d4fba8b9Smrg * The factor of two accounts for line-drawing that goes through 2948d4fba8b9Smrg * the middle of a cell, possibly leaving half of the cell unused. 2949d4fba8b9Smrg * A horizontal line has to extend the full width of the cell. 2950d4fba8b9Smrg */ 2951d4fba8b9Smrg switch (unicode_boxes[n].high) { 2952d4fba8b9Smrg case 1: 2953d4fba8b9Smrg if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) { 2954d4fba8b9Smrg TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n", 2955d4fba8b9Smrg (unsigned) g->bitmap.rows, 2956d4fba8b9Smrg (unsigned) FontHeight(screen))); 2957d4fba8b9Smrg broken = True; 2958d4fba8b9Smrg } 2959d4fba8b9Smrg break; 2960d4fba8b9Smrg case 2: 2961d4fba8b9Smrg if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) { 2962d4fba8b9Smrg TRACE(("...bitmap is too short for half-cell (%u vs %u)\n", 2963d4fba8b9Smrg (unsigned) (g->bitmap.rows * 2), 2964d4fba8b9Smrg (unsigned) FontHeight(screen))); 2965d4fba8b9Smrg broken = True; 2966d4fba8b9Smrg } 2967d4fba8b9Smrg break; 2968d4fba8b9Smrg } 2969d4fba8b9Smrg switch (unicode_boxes[n].wide) { 2970d4fba8b9Smrg case 1: 2971d4fba8b9Smrg if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) { 2972d4fba8b9Smrg TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n", 2973d4fba8b9Smrg (unsigned) g->bitmap.width, 2974d4fba8b9Smrg (unsigned) FontWidth(screen))); 2975d4fba8b9Smrg broken = True; 2976d4fba8b9Smrg } 2977d4fba8b9Smrg break; 2978d4fba8b9Smrg case 2: 2979d4fba8b9Smrg if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) { 2980d4fba8b9Smrg TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n", 2981d4fba8b9Smrg (unsigned) (g->bitmap.width * 2), 2982d4fba8b9Smrg (unsigned) FontWidth(screen))); 2983d4fba8b9Smrg broken = True; 2984d4fba8b9Smrg } 2985d4fba8b9Smrg break; 2986d4fba8b9Smrg } 2987d4fba8b9Smrg if (broken) 2988d4fba8b9Smrg break; 2989d4fba8b9Smrg } 2990d4fba8b9Smrg } 2991d4fba8b9Smrg XftUnlockFace(font); 2992d4fba8b9Smrg#else 2993d4fba8b9Smrg (void) font; 2994d4fba8b9Smrg broken = True; 2995d4fba8b9Smrg#endif 2996d4fba8b9Smrg 2997d4fba8b9Smrg if (broken) { 2998d4fba8b9Smrg TRACE(("Xft line-drawing would not work\n")); 2999d4fba8b9Smrg setBrokenBoxChars(xw, True); 3000d4fba8b9Smrg } 3001d4fba8b9Smrg} 3002d4fba8b9Smrg#endif /* OPT_BOX_CHARS */ 3003d4fba8b9Smrg 3004d522f475Smrg/* 3005d522f475Smrg * Given the Xft font metrics, determine the actual font size. This is used 3006d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same 3007d522f475Smrg * rule. 3008d522f475Smrg */ 3009d522f475Smrgstatic void 3010d4fba8b9SmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XftFont *font, const char *tag) 3011d522f475Smrg{ 3012d522f475Smrg if (font != 0) { 3013d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3014d522f475Smrg int width, height, ascent, descent; 3015d4fba8b9Smrg#ifdef DEBUG_XFT 3016d4fba8b9Smrg int n; 3017d4fba8b9Smrg FT_Face face; 3018d4fba8b9Smrg FT_Size size; 3019d4fba8b9Smrg FT_Size_Metrics metrics; 3020d4fba8b9Smrg Boolean scalable; 3021d4fba8b9Smrg Boolean is_fixed; 3022d4fba8b9Smrg Boolean debug_xft = False; 3023d4fba8b9Smrg 3024d4fba8b9Smrg face = XftLockFace(font); 3025d4fba8b9Smrg size = face->size; 3026d4fba8b9Smrg metrics = size->metrics; 3027d4fba8b9Smrg is_fixed = FT_IS_FIXED_WIDTH(face); 3028d4fba8b9Smrg scalable = FT_IS_SCALABLE(face); 3029d4fba8b9Smrg trace_xft_line_drawing(screen, font, face); 3030d4fba8b9Smrg for (n = 32; n < 127; ++n) { 3031d4fba8b9Smrg char name[80]; 3032d4fba8b9Smrg sprintf(name, "letter \"%c\"", n); 3033d4fba8b9Smrg trace_xft_glyph(screen, font, face, n, name); 3034d4fba8b9Smrg } 3035d4fba8b9Smrg XftUnlockFace(font); 3036d4fba8b9Smrg 3037d4fba8b9Smrg /* freetype's inconsistent for this sign */ 3038d4fba8b9Smrg metrics.descender = -metrics.descender; 3039d4fba8b9Smrg 3040d4fba8b9Smrg#define TR_XFT "Xft metrics: " 3041d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0) 3042d4fba8b9Smrg#define M_64(a,b) ((font->a * 64) != metrics.b) 3043d4fba8b9Smrg#define BOTH(a,b) D_64(b), M_64(a,b) ? "*" : "" 3044d4fba8b9Smrg 3045d4fba8b9Smrg debug_xft = (M_64(ascent, ascender) 3046d4fba8b9Smrg || M_64(descent, descender) 3047d4fba8b9Smrg || M_64(height, height) 3048d4fba8b9Smrg || M_64(max_advance_width, max_advance)); 3049d4fba8b9Smrg 3050d4fba8b9Smrg TRACE(("Xft font is %sscalable, %sfixed-width\n", 3051d4fba8b9Smrg is_fixed ? "" : "not ", 3052d4fba8b9Smrg scalable ? "" : "not ")); 3053d4fba8b9Smrg 3054d4fba8b9Smrg if (debug_xft) { 3055d4fba8b9Smrg TRACE(("Xft font size %d+%d vs %d by %d\n", 3056d4fba8b9Smrg font->ascent, 3057d4fba8b9Smrg font->descent, 3058d4fba8b9Smrg font->height, 3059d4fba8b9Smrg font->max_advance_width)); 3060d4fba8b9Smrg TRACE((TR_XFT "ascender %6.2f%s\n", BOTH(ascent, ascender))); 3061d4fba8b9Smrg TRACE((TR_XFT "descender %6.2f%s\n", BOTH(descent, descender))); 3062d4fba8b9Smrg TRACE((TR_XFT "height %6.2f%s\n", BOTH(height, height))); 3063d4fba8b9Smrg TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance))); 3064d4fba8b9Smrg } else { 3065d4fba8b9Smrg TRACE((TR_XFT "matches font\n")); 3066d4fba8b9Smrg } 3067d4fba8b9Smrg#endif 3068d522f475Smrg 3069d522f475Smrg width = font->max_advance_width; 3070d522f475Smrg height = font->height; 3071d522f475Smrg ascent = font->ascent; 3072d522f475Smrg descent = font->descent; 3073d4fba8b9Smrg if (screen->force_xft_height && height < ascent + descent) { 3074d4fba8b9Smrg TRACE(("...height is less than ascent + descent (%u vs %u)\n", 3075d4fba8b9Smrg height, ascent + descent)); 3076d4fba8b9Smrg if ((ascent + descent) > (height + 1)) { 3077d4fba8b9Smrg /* this happens less than 10% of the time */ 3078d4fba8b9Smrg --ascent; 3079d4fba8b9Smrg --descent; 3080d4fba8b9Smrg TRACE(("...decrement both ascent and descent before retry\n")); 3081d4fba8b9Smrg } else if (ascent > descent) { 3082d4fba8b9Smrg /* this is the usual case */ 3083d4fba8b9Smrg --ascent; 3084d4fba8b9Smrg TRACE(("...decrement ascent before retry\n")); 3085d4fba8b9Smrg } else { 3086d4fba8b9Smrg /* this could happen, though rare... */ 3087d4fba8b9Smrg --descent; 3088d4fba8b9Smrg TRACE(("...decrement descent before retry\n")); 3089d4fba8b9Smrg } 3090d522f475Smrg height = ascent + descent; 3091d4fba8b9Smrg font->ascent = ascent; 3092d4fba8b9Smrg font->descent = descent; 3093d4fba8b9Smrg TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n", 3094d4fba8b9Smrg height, ascent + descent, ascent, descent)); 3095d522f475Smrg } 3096d522f475Smrg if (is_double_width_font_xft(screen->display, font)) { 3097d4fba8b9Smrg TRACE(("...reduce width from %d to %d\n", width, width >> 1)); 3098d522f475Smrg width >>= 1; 3099d522f475Smrg } 3100d522f475Smrg if (tag == 0) { 31010bd37d32Smrg SetFontWidth(screen, win, width); 31020bd37d32Smrg SetFontHeight(screen, win, height); 3103d522f475Smrg win->f_ascent = ascent; 3104d522f475Smrg win->f_descent = descent; 3105d522f475Smrg TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 3106d522f475Smrg width, height, ascent, descent)); 3107d522f475Smrg } else if (win->f_width < width || 3108d522f475Smrg win->f_height < height || 3109d522f475Smrg win->f_ascent < ascent || 3110d522f475Smrg win->f_descent < descent) { 3111d522f475Smrg TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 3112d522f475Smrg tag, 3113d522f475Smrg win->f_width, win->f_height, win->f_ascent, win->f_descent, 3114d522f475Smrg width, height, ascent, descent)); 3115d522f475Smrg 31160bd37d32Smrg SetFontWidth(screen, win, width); 31170bd37d32Smrg SetFontHeight(screen, win, height); 3118d522f475Smrg win->f_ascent = ascent; 3119d522f475Smrg win->f_descent = descent; 3120d522f475Smrg } else { 3121d522f475Smrg TRACE(("setRenderFontsize %s unchanged\n", tag)); 3122d522f475Smrg } 3123d4fba8b9Smrg#if OPT_BOX_CHARS 3124d4fba8b9Smrg if (!screen->broken_box_chars && (tag == 0)) { 3125d4fba8b9Smrg linedrawing_gaps(xw, font); 3126d4fba8b9Smrg } 3127d4fba8b9Smrg#endif 3128d522f475Smrg } 3129d522f475Smrg} 3130d522f475Smrg#endif 3131d522f475Smrg 313220d2c4d2Smrgstatic void 3133d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed) 313420d2c4d2Smrg{ 3135d4fba8b9Smrg if (value == 0 || failed) { 3136d4fba8b9Smrg if (value == 0) { 3137d4fba8b9Smrg xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 3138d4fba8b9Smrg exit(1); 3139d4fba8b9Smrg } else { 3140d4fba8b9Smrg xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag); 3141d4fba8b9Smrg } 314220d2c4d2Smrg } 314320d2c4d2Smrg} 314420d2c4d2Smrg 314520d2c4d2Smrg#if OPT_RENDERFONT 314620d2c4d2Smrgvoid 31479a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub) 314820d2c4d2Smrg{ 314920d2c4d2Smrg if (pub->font != 0) { 3150d4fba8b9Smrg Cardinal n; 3151d4fba8b9Smrg 3152d4fba8b9Smrg closeCachedXft(screen, pub->font); 315320d2c4d2Smrg pub->font = 0; 3154d4fba8b9Smrg 3155d4fba8b9Smrg if (pub->pattern) { 3156d4fba8b9Smrg XftPatternDestroy(pub->pattern); 3157d4fba8b9Smrg pub->pattern = 0; 3158d4fba8b9Smrg } 3159d4fba8b9Smrg if (pub->fontset) { 3160d4fba8b9Smrg XftFontSetDestroy(pub->fontset); 3161d4fba8b9Smrg pub->fontset = 0; 3162d4fba8b9Smrg } 3163d4fba8b9Smrg 3164d4fba8b9Smrg for (n = 0; n < pub->limit; ++n) { 3165d4fba8b9Smrg if (pub->cache[n].font) { 3166d4fba8b9Smrg closeCachedXft(screen, pub->cache[n].font); 3167d4fba8b9Smrg pub->cache[n].font = 0; 3168d4fba8b9Smrg } 3169d4fba8b9Smrg } 3170d4fba8b9Smrg free(pub->cache); 3171d4fba8b9Smrg pub->cache = NULL; 317220d2c4d2Smrg } 317320d2c4d2Smrg} 317420d2c4d2Smrg 317520d2c4d2Smrg/* 3176d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting. 317720d2c4d2Smrg */ 3178492d43a5SmrgString 3179d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName) 318020d2c4d2Smrg{ 318120d2c4d2Smrg#if OPT_RENDERWIDE 3182492d43a5Smrg String result = (wideName 3183dfb07bc7Smrg ? FirstItemOf(xw->work.fonts.xft.list_w) 3184dfb07bc7Smrg : CurrentXftFont(xw)); 318520d2c4d2Smrg#else 3186dfb07bc7Smrg String result = CurrentXftFont(xw); 3187d4fba8b9Smrg (void) wideName; 318820d2c4d2Smrg#endif 318920d2c4d2Smrg return x_nonempty(result); 319020d2c4d2Smrg} 319120d2c4d2Smrg 319220d2c4d2Smrg/* 319320d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that 319420d2c4d2Smrg * are derived from it. 319520d2c4d2Smrg */ 319620d2c4d2Smrgvoid 319720d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value) 319820d2c4d2Smrg{ 319920d2c4d2Smrg TScreen *screen = TScreenOf(xw); 3200dfb07bc7Smrg Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0) 3201dfb07bc7Smrg || strcmp(CurrentXftFont(xw), value)); 320220d2c4d2Smrg 32030bd37d32Smrg if (changed) { 3204037a25ddSmrg int n; 3205037a25ddSmrg 3206dfb07bc7Smrg CurrentXftFont(xw) = x_strdup(value); 32070bd37d32Smrg for (n = 0; n < NMENUFONTS; ++n) { 3208dfb07bc7Smrg int e; 32090bd37d32Smrg xw->misc.face_size[n] = -1.0; 3210dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 3211dfb07bc7Smrg xtermCloseXft(screen, getMyXftFont(xw, e, n)); 3212dfb07bc7Smrg } 32130bd37d32Smrg } 321420d2c4d2Smrg } 321520d2c4d2Smrg} 321620d2c4d2Smrg#endif 321720d2c4d2Smrg 3218d522f475Smrg/* 3219d522f475Smrg * Compute useful values for the font/window sizes 3220d522f475Smrg */ 3221d522f475Smrgvoid 3222d522f475SmrgxtermComputeFontInfo(XtermWidget xw, 32239a64e1c5Smrg VTwin *win, 32249a64e1c5Smrg XFontStruct *font, 3225d522f475Smrg int sbwidth) 3226d522f475Smrg{ 3227956cc18dSsnj TScreen *screen = TScreenOf(xw); 3228d522f475Smrg 3229d522f475Smrg int i, j, width, height; 3230492d43a5Smrg#if OPT_RENDERFONT 3231492d43a5Smrg int fontnum = screen->menu_font_number; 3232492d43a5Smrg#endif 3233d4fba8b9Smrg int failed = 0; 3234d522f475Smrg 3235d522f475Smrg#if OPT_RENDERFONT 3236d522f475Smrg /* 3237d522f475Smrg * xterm contains a lot of references to fonts, assuming they are fixed 3238d522f475Smrg * size. This chunk of code overrides the actual font-selection (see 3239d522f475Smrg * drawXtermText()), if the user has selected render-font. All of the 3240d522f475Smrg * font-loading for fixed-fonts still goes on whether or not this chunk 3241d522f475Smrg * overrides it. 3242d522f475Smrg */ 3243492d43a5Smrg if (UsingRenderFont(xw) && fontnum >= 0) { 3244492d43a5Smrg String face_name = getFaceName(xw, False); 3245d4fba8b9Smrg XTermXftFonts norm = screen->renderFontNorm[fontnum]; 3246d4fba8b9Smrg XTermXftFonts bold = screen->renderFontBold[fontnum]; 3247d4fba8b9Smrg XTermXftFonts ital = screen->renderFontItal[fontnum]; 3248d4fba8b9Smrg XTermXftFonts btal = screen->renderFontBtal[fontnum]; 3249d522f475Smrg#if OPT_RENDERWIDE 3250d4fba8b9Smrg XTermXftFonts wnorm = screen->renderWideNorm[fontnum]; 3251d4fba8b9Smrg XTermXftFonts wbold = screen->renderWideBold[fontnum]; 3252d4fba8b9Smrg XTermXftFonts wital = screen->renderWideItal[fontnum]; 3253d4fba8b9Smrg XTermXftFonts wbtal = screen->renderWideBtal[fontnum]; 3254d522f475Smrg#endif 3255d522f475Smrg 3256d4fba8b9Smrg if (norm.font == 0 && !IsEmpty(face_name)) { 3257d522f475Smrg XftPattern *pat; 32580bd37d32Smrg double face_size; 3259d522f475Smrg 32600bd37d32Smrg TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 3261492d43a5Smrg fontnum, face_name, 3262d522f475Smrg xw->misc.face_size[fontnum])); 3263d522f475Smrg 3264d4fba8b9Smrg TRACE(("Using Xft %d\n", XftVersion)); 3265d4fba8b9Smrg TRACE(("Using FontConfig %d\n", FC_VERSION)); 3266d4fba8b9Smrg 32670bd37d32Smrg fillInFaceSize(xw, fontnum); 3268d4fba8b9Smrg face_size = (double) xw->misc.face_size[fontnum]; 3269d522f475Smrg 3270d522f475Smrg /* 3271d522f475Smrg * By observation (there is no documentation), XftPatternBuild is 3272d522f475Smrg * cumulative. Build the bold- and italic-patterns on top of the 3273d522f475Smrg * normal pattern. 3274d522f475Smrg */ 3275d4fba8b9Smrg#ifdef FC_COLOR 3276d522f475Smrg#define NormXftPattern \ 3277d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3278d4fba8b9Smrg FC_COLOR, XftTypeBool, FcFalse, \ 3279d4fba8b9Smrg FC_OUTLINE, XftTypeBool, FcTrue, \ 3280d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3281d4fba8b9Smrg#else 3282d4fba8b9Smrg#define NormXftPattern \ 3283d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3284d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3285d4fba8b9Smrg#endif 3286d522f475Smrg 3287d522f475Smrg#define BoldXftPattern(norm) \ 3288d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3289d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width 3290d522f475Smrg 3291d522f475Smrg#define ItalXftPattern(norm) \ 3292d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3293d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width 3294d4fba8b9Smrg 3295d4fba8b9Smrg#define BtalXftPattern(norm) \ 3296d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3297d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3298d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width 3299d522f475Smrg 33009a64e1c5Smrg#if OPT_WIDE_ATTRS 33019a64e1c5Smrg#define HAVE_ITALICS 1 33029a64e1c5Smrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0) 33039a64e1c5Smrg#elif OPT_ISO_COLORS 33049a64e1c5Smrg#define HAVE_ITALICS 1 33059a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0) 33069a64e1c5Smrg#else 33079a64e1c5Smrg#define HAVE_ITALICS 0 33089a64e1c5Smrg#endif 33099a64e1c5Smrg 3310d4fba8b9Smrg#if OPT_DEC_CHRSET 3311d4fba8b9Smrg freeall_DoubleFT(xw); 3312d4fba8b9Smrg#endif 331320d2c4d2Smrg if ((pat = XftNameParse(face_name)) != 0) { 3314d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag) 3315d4fba8b9Smrg norm.pattern = XftPatternDuplicate(pat); 3316d4fba8b9Smrg XftPatternBuild(norm.pattern, 3317d522f475Smrg NormXftPattern, 3318d522f475Smrg (void *) 0); 3319d4fba8b9Smrg OPEN_XFT(norm, "normal"); 3320d522f475Smrg 3321d4fba8b9Smrg if (norm.font != 0) { 3322d4fba8b9Smrg bold.pattern = XftPatternDuplicate(pat); 3323d4fba8b9Smrg XftPatternBuild(bold.pattern, 3324d4fba8b9Smrg NormXftPattern, 3325d522f475Smrg BoldXftPattern(norm), 3326d522f475Smrg (void *) 0); 3327d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3328d522f475Smrg 33299a64e1c5Smrg#if HAVE_ITALICS 33309a64e1c5Smrg if (FIND_ITALICS) { 3331d4fba8b9Smrg ital.pattern = XftPatternDuplicate(pat); 3332d4fba8b9Smrg XftPatternBuild(ital.pattern, 3333d522f475Smrg NormXftPattern, 3334d522f475Smrg ItalXftPattern(norm), 3335d522f475Smrg (void *) 0); 3336d4fba8b9Smrg OPEN_XFT(ital, "italic"); 3337d4fba8b9Smrg btal.pattern = XftPatternDuplicate(pat); 3338d4fba8b9Smrg XftPatternBuild(btal.pattern, 3339d4fba8b9Smrg NormXftPattern, 3340d4fba8b9Smrg BtalXftPattern(norm), 3341d4fba8b9Smrg (void *) 0); 3342d4fba8b9Smrg OPEN_XFT(btal, "bold-italic"); 3343d522f475Smrg } 33449a64e1c5Smrg#endif 3345d522f475Smrg 3346d522f475Smrg /* 3347d522f475Smrg * FIXME: just assume that the corresponding font has no 3348d522f475Smrg * graphics characters. 3349d522f475Smrg */ 3350d522f475Smrg if (screen->fnt_boxes) { 3351d4fba8b9Smrg screen->fnt_boxes = 0; 3352d522f475Smrg TRACE(("Xft opened - will %suse internal line-drawing characters\n", 3353d522f475Smrg screen->fnt_boxes ? "not " : "")); 3354d522f475Smrg } 3355d522f475Smrg } 3356d522f475Smrg 3357d4fba8b9Smrg CACHE_XFT(screen->renderFontNorm, norm); 3358d4fba8b9Smrg 3359d4fba8b9Smrg CACHE_XFT(screen->renderFontBold, bold); 3360d4fba8b9Smrg if (norm.font != 0 && !bold.font) { 3361d4fba8b9Smrg noUsableXft(xw, "bold"); 3362d4fba8b9Smrg XftPatternDestroy(bold.pattern); 3363d4fba8b9Smrg bold.pattern = XftPatternDuplicate(pat); 3364d4fba8b9Smrg XftPatternBuild(bold.pattern, 3365d4fba8b9Smrg NormXftPattern, 3366d4fba8b9Smrg (void *) 0); 3367d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3368d4fba8b9Smrg failed = 0; 3369d4fba8b9Smrg CACHE_XFT(screen->renderFontBold, bold); 3370d4fba8b9Smrg } 3371d4fba8b9Smrg#if HAVE_ITALICS 3372d4fba8b9Smrg CACHE_XFT(screen->renderFontItal, ital); 3373d4fba8b9Smrg if (norm.font != 0 && !ital.font) { 3374d4fba8b9Smrg noUsableXft(xw, "italic"); 3375d4fba8b9Smrg XftPatternDestroy(ital.pattern); 3376d4fba8b9Smrg ital.pattern = XftPatternDuplicate(pat); 3377d4fba8b9Smrg XftPatternBuild(ital.pattern, 3378d4fba8b9Smrg NormXftPattern, 3379d4fba8b9Smrg (void *) 0); 3380d4fba8b9Smrg OPEN_XFT(ital, "italics"); 3381d4fba8b9Smrg failed = 0; 3382d4fba8b9Smrg CACHE_XFT(screen->renderFontItal, ital); 3383d4fba8b9Smrg } 3384d4fba8b9Smrg CACHE_XFT(screen->renderFontBtal, btal); 3385d4fba8b9Smrg if (norm.font != 0 && !btal.font) { 3386d4fba8b9Smrg noUsableXft(xw, "bold italic"); 3387d4fba8b9Smrg XftPatternDestroy(btal.pattern); 3388d4fba8b9Smrg btal.pattern = XftPatternDuplicate(pat); 3389d4fba8b9Smrg XftPatternBuild(btal.pattern, 3390d4fba8b9Smrg NormXftPattern, 3391d4fba8b9Smrg (void *) 0); 3392d4fba8b9Smrg OPEN_XFT(btal, "bold-italics"); 3393d4fba8b9Smrg failed = 0; 3394d4fba8b9Smrg CACHE_XFT(screen->renderFontBtal, btal); 3395d4fba8b9Smrg } 3396d4fba8b9Smrg#endif 3397d522f475Smrg XftPatternDestroy(pat); 3398d4fba8b9Smrg } else { 3399d4fba8b9Smrg failed = 1; 3400d522f475Smrg } 3401d4fba8b9Smrg#undef OPEN_XFT 3402d522f475Smrg 3403d522f475Smrg /* 3404d4fba8b9Smrg * See xtermXftDrawString(). A separate double-width font is nice 3405d4fba8b9Smrg * to have, but not essential. 3406d522f475Smrg */ 3407d522f475Smrg#if OPT_RENDERWIDE 3408d4fba8b9Smrg if (norm.font != 0 && screen->wide_chars) { 3409d4fba8b9Smrg int char_width = norm.font->max_advance_width * 2; 3410dfb07bc7Smrg double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w) 3411956cc18dSsnj || screen->renderFontNorm[fontnum].map.mixed) 3412956cc18dSsnj ? 1.0 3413956cc18dSsnj : 2.0); 3414d522f475Smrg 341520d2c4d2Smrg face_name = getFaceName(xw, True); 3416d522f475Smrg TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 341720d2c4d2Smrg NonNull(face_name), 3418d522f475Smrg char_width)); 3419d522f475Smrg 3420d522f475Smrg#define WideXftPattern \ 3421d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3422d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size, \ 3423d4fba8b9Smrg XFT_SPACING, XftTypeInteger, XFT_MONO, \ 3424d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, char_width, \ 3425d4fba8b9Smrg FC_ASPECT, XftTypeDouble, aspect 3426d4fba8b9Smrg 3427d4fba8b9Smrg if (!IsEmpty(face_name) && (pat = XftNameParse(face_name)) 3428d4fba8b9Smrg != 0) { 3429d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag) 3430d4fba8b9Smrg wnorm.pattern = XftPatternDuplicate(pat); 3431d4fba8b9Smrg XftPatternBuild(wnorm.pattern, 3432d522f475Smrg WideXftPattern, 3433d522f475Smrg (void *) 0); 3434d4fba8b9Smrg OPEN_XFT(wnorm, "wide"); 3435d522f475Smrg 3436d4fba8b9Smrg if (wnorm.font != 0) { 3437d4fba8b9Smrg wbold.pattern = XftPatternDuplicate(pat); 3438d4fba8b9Smrg XftPatternBuild(wbold.pattern, 3439d522f475Smrg WideXftPattern, 3440d522f475Smrg BoldXftPattern(wnorm), 3441d522f475Smrg (void *) 0); 3442d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3443d522f475Smrg 34449a64e1c5Smrg#if HAVE_ITALICS 34459a64e1c5Smrg if (FIND_ITALICS) { 3446d4fba8b9Smrg wital.pattern = XftPatternDuplicate(pat); 3447d4fba8b9Smrg XftPatternBuild(wital.pattern, 3448d522f475Smrg WideXftPattern, 3449d522f475Smrg ItalXftPattern(wnorm), 3450d522f475Smrg (void *) 0); 3451d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3452d4fba8b9Smrg } 3453d4fba8b9Smrg CACHE_XFT(screen->renderWideBtal, wbtal); 3454d4fba8b9Smrg if (!wbtal.font) { 3455d4fba8b9Smrg noUsableXft(xw, "wide bold"); 3456d4fba8b9Smrg XftPatternDestroy(wbtal.pattern); 3457d4fba8b9Smrg wbtal.pattern = XftPatternDuplicate(pat); 3458d4fba8b9Smrg XftPatternBuild(wbtal.pattern, 3459d4fba8b9Smrg WideXftPattern, 3460d4fba8b9Smrg (void *) 0); 3461d4fba8b9Smrg OPEN_XFT(wbtal, "wide-bold-italics"); 3462d4fba8b9Smrg failed = 0; 3463d4fba8b9Smrg CACHE_XFT(screen->renderWideBtal, wbtal); 3464d522f475Smrg } 3465d522f475Smrg#endif 3466d522f475Smrg } 3467d4fba8b9Smrg 3468d4fba8b9Smrg CACHE_XFT(screen->renderWideNorm, wnorm); 3469d4fba8b9Smrg 3470d4fba8b9Smrg CACHE_XFT(screen->renderWideBold, wbold); 3471d4fba8b9Smrg if (wnorm.font != 0 && !wbold.font) { 3472d4fba8b9Smrg noUsableXft(xw, "wide-bold"); 3473d4fba8b9Smrg XftPatternDestroy(wbold.pattern); 3474d4fba8b9Smrg wbold.pattern = XftPatternDuplicate(pat); 3475d4fba8b9Smrg XftPatternBuild(bold.pattern, 3476d4fba8b9Smrg WideXftPattern, 3477d4fba8b9Smrg (void *) 0); 3478d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3479d4fba8b9Smrg failed = 0; 3480d4fba8b9Smrg CACHE_XFT(screen->renderWideBold, bold); 3481d4fba8b9Smrg } 3482d4fba8b9Smrg 3483d4fba8b9Smrg CACHE_XFT(screen->renderWideItal, wital); 3484d4fba8b9Smrg if (wnorm.font != 0 && !wital.font) { 3485d4fba8b9Smrg noUsableXft(xw, "wide-italic"); 3486d4fba8b9Smrg XftPatternDestroy(wital.pattern); 3487d4fba8b9Smrg wital.pattern = XftPatternDuplicate(pat); 3488d4fba8b9Smrg XftPatternBuild(wital.pattern, 3489d4fba8b9Smrg WideXftPattern, 3490d4fba8b9Smrg (void *) 0); 3491d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3492d4fba8b9Smrg failed = 0; 3493d4fba8b9Smrg CACHE_XFT(screen->renderWideItal, wital); 3494d4fba8b9Smrg } 3495d4fba8b9Smrg 3496d522f475Smrg XftPatternDestroy(pat); 3497d522f475Smrg } 3498d4fba8b9Smrg#undef OPEN_XFT 3499d522f475Smrg } 3500d522f475Smrg#endif /* OPT_RENDERWIDE */ 3501d522f475Smrg } 3502d4fba8b9Smrg if (norm.font == 0) { 35032eaa94a1Schristos TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 35040bd37d32Smrg xw->work.render_font = False; 3505d522f475Smrg update_font_renderfont(); 3506d522f475Smrg /* now we will fall through into the bitmap fonts */ 3507d522f475Smrg } else { 3508d4fba8b9Smrg setBrokenBoxChars(xw, False); 3509d4fba8b9Smrg setRenderFontsize(xw, win, norm.font, NULL); 3510d4fba8b9Smrg setRenderFontsize(xw, win, bold.font, "bold"); 3511d4fba8b9Smrg setRenderFontsize(xw, win, ital.font, "ital"); 3512d4fba8b9Smrg setRenderFontsize(xw, win, btal.font, "btal"); 351320d2c4d2Smrg#if OPT_BOX_CHARS 351420d2c4d2Smrg setupPackedFonts(xw); 351520d2c4d2Smrg 351620d2c4d2Smrg if (screen->force_packed) { 351720d2c4d2Smrg XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 35180bd37d32Smrg SetFontHeight(screen, win, use->font->ascent + use->font->descent); 35190bd37d32Smrg SetFontWidth(screen, win, use->map.min_width); 352020d2c4d2Smrg TRACE(("...packed TrueType font %dx%d vs %d\n", 352120d2c4d2Smrg win->f_height, 352220d2c4d2Smrg win->f_width, 352320d2c4d2Smrg use->map.max_width)); 352420d2c4d2Smrg } 352520d2c4d2Smrg#endif 352620d2c4d2Smrg DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 3527d522f475Smrg } 3528d522f475Smrg } 3529d522f475Smrg /* 3530d522f475Smrg * Are we handling a bitmap font? 3531d522f475Smrg */ 3532492d43a5Smrg else 3533d522f475Smrg#endif /* OPT_RENDERFONT */ 3534d522f475Smrg { 353520d2c4d2Smrg if (is_double_width_font(font) && !(screen->fnt_prop)) { 35360bd37d32Smrg SetFontWidth(screen, win, font->min_bounds.width); 3537d522f475Smrg } else { 35380bd37d32Smrg SetFontWidth(screen, win, font->max_bounds.width); 3539d522f475Smrg } 35400bd37d32Smrg SetFontHeight(screen, win, font->ascent + font->descent); 3541d522f475Smrg win->f_ascent = font->ascent; 3542d522f475Smrg win->f_descent = font->descent; 3543d522f475Smrg } 3544d522f475Smrg i = 2 * screen->border + sbwidth; 3545d522f475Smrg j = 2 * screen->border; 3546d522f475Smrg width = MaxCols(screen) * win->f_width + i; 3547d522f475Smrg height = MaxRows(screen) * win->f_height + j; 3548956cc18dSsnj win->fullwidth = (Dimension) width; 3549956cc18dSsnj win->fullheight = (Dimension) height; 3550d522f475Smrg win->width = width - i; 3551d522f475Smrg win->height = height - j; 3552d522f475Smrg 3553d522f475Smrg TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 3554d522f475Smrg win->height, 3555d522f475Smrg win->width, 3556d522f475Smrg win->fullheight, 3557d522f475Smrg win->fullwidth, 3558d522f475Smrg win->f_height, 3559d522f475Smrg win->f_width, 3560d522f475Smrg win->f_ascent, 3561d522f475Smrg win->f_descent)); 356220d2c4d2Smrg 3563d4fba8b9Smrg checkFontInfo(win->f_height, "height", failed); 3564d4fba8b9Smrg checkFontInfo(win->f_width, "width", failed); 3565d522f475Smrg} 3566d522f475Smrg 3567d522f475Smrg/* save this information as a side-effect for double-sized characters */ 3568d4fba8b9Smrgstatic void 35699a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font) 3570d522f475Smrg{ 3571956cc18dSsnj screen->fnt_wide = (Dimension) (font->max_bounds.width); 3572956cc18dSsnj screen->fnt_high = (Dimension) (font->ascent + font->descent); 3573d522f475Smrg TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 3574d522f475Smrg} 3575d522f475Smrg 3576d522f475Smrg/* 3577d522f475Smrg * After loading a new font, update the structures that use its size. 3578d522f475Smrg */ 3579d522f475Smrgvoid 3580d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize) 3581d522f475Smrg{ 3582956cc18dSsnj TScreen *screen = TScreenOf(xw); 3583d522f475Smrg 3584d522f475Smrg int scrollbar_width; 3585d522f475Smrg VTwin *win = &(screen->fullVwin); 3586d522f475Smrg 3587d4fba8b9Smrg#if USE_DOUBLE_BUFFER 3588d4fba8b9Smrg discardRenderDraw(TScreenOf(xw)); 3589d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */ 3590d4fba8b9Smrg 3591d522f475Smrg scrollbar_width = (xw->misc.scrollbar 3592d522f475Smrg ? (screen->scrollWidget->core.width + 3593d522f475Smrg BorderWidth(screen->scrollWidget)) 3594d522f475Smrg : 0); 3595d4fba8b9Smrg xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width); 3596d4fba8b9Smrg xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs); 3597d522f475Smrg 3598d522f475Smrg if (doresize) { 3599d522f475Smrg if (VWindow(screen)) { 3600d522f475Smrg xtermClear(xw); 3601d522f475Smrg } 3602d4fba8b9Smrg TRACE(("xtermUpdateFontInfo " TRACE_L "\n")); 3603d522f475Smrg DoResizeScreen(xw); /* set to the new natural size */ 3604d522f475Smrg ResizeScrollBar(xw); 3605d522f475Smrg Redraw(); 3606d4fba8b9Smrg TRACE((TRACE_R " xtermUpdateFontInfo\n")); 3607d522f475Smrg#ifdef SCROLLBAR_RIGHT 3608d522f475Smrg updateRightScrollbar(xw); 3609d522f475Smrg#endif 3610d522f475Smrg } 3611d522f475Smrg xtermSetCursorBox(screen); 3612d522f475Smrg} 3613d522f475Smrg 3614fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS 3615d522f475Smrg 3616d522f475Smrg/* 3617d522f475Smrg * Returns true if the given character is missing from the specified font. 3618d522f475Smrg */ 3619d522f475SmrgBool 3620956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font) 3621d522f475Smrg{ 3622956cc18dSsnj Bool result = False; 3623956cc18dSsnj XFontStruct *fs = font->fs; 3624fa3f02f3Smrg XCharStruct *pc = 0; 3625d522f475Smrg 3626d4fba8b9Smrg if (fs == NULL) { 3627d4fba8b9Smrg result = True; 3628d4fba8b9Smrg } else if (fs->max_byte1 == 0) { 3629d522f475Smrg#if OPT_WIDE_CHARS 3630fa3f02f3Smrg if (ch < 256) 3631956cc18dSsnj#endif 3632fa3f02f3Smrg { 3633fa3f02f3Smrg CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc); 3634fa3f02f3Smrg } 3635956cc18dSsnj } 3636d522f475Smrg#if OPT_WIDE_CHARS 3637956cc18dSsnj else { 3638fa3f02f3Smrg unsigned row = (ch >> 8); 3639fa3f02f3Smrg unsigned col = (ch & 0xff); 3640fa3f02f3Smrg CI_GET_CHAR_INFO_2D(fs, row, col, pc); 3641956cc18dSsnj } 3642d522f475Smrg#endif 3643d522f475Smrg 3644fa3f02f3Smrg if (pc == 0 || CI_NONEXISTCHAR(pc)) { 3645c48a5815Smrg TRACE2(("xtermMissingChar %#04x (!exists)\n", ch)); 3646956cc18dSsnj result = True; 3647d522f475Smrg } 3648fa3f02f3Smrg if (ch < KNOWN_MISSING) { 3649956cc18dSsnj font->known_missing[ch] = (Char) (result ? 2 : 1); 3650d522f475Smrg } 3651956cc18dSsnj return result; 3652d522f475Smrg} 3653fa3f02f3Smrg#endif 3654d522f475Smrg 3655fa3f02f3Smrg#if OPT_BOX_CHARS 3656d522f475Smrg/* 3657d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in 3658d522f475Smrg * initialization. 3659d522f475Smrg */ 3660d522f475Smrg#define BOX_HIGH 60 3661d522f475Smrg#define BOX_WIDE 60 3662d522f475Smrg 3663d522f475Smrg#define MID_HIGH (BOX_HIGH/2) 3664d522f475Smrg#define MID_WIDE (BOX_WIDE/2) 3665d522f475Smrg 3666d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10) 3667d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10) 3668d522f475Smrg 3669d522f475Smrg/* 3670d522f475Smrg * ...since we'll scale the values anyway. 3671d522f475Smrg */ 3672d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d) 3673d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width) 3674d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height) 3675e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n) 3676e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n) 3677d522f475Smrg 3678d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 3679d522f475Smrg 3680d522f475Smrg/* 3681d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a 3682d522f475Smrg * line-drawing character). 3683d522f475Smrg */ 3684d522f475Smrgvoid 3685d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params, 3686d522f475Smrg unsigned ch, 3687d522f475Smrg GC gc, 3688d522f475Smrg int x, 3689d522f475Smrg int y, 3690d4fba8b9Smrg int cells, 3691d4fba8b9Smrg Bool xftords) 3692d522f475Smrg{ 3693d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 3694d522f475Smrg /* *INDENT-OFF* */ 3695d522f475Smrg static const short glyph_ht[] = { 3696d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 3697d522f475Smrg SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 3698d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 3699d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3700d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3701d522f475Smrg -1 3702d522f475Smrg }, glyph_ff[] = { 3703d522f475Smrg SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 3704d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 3705d522f475Smrg SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 3706d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3707d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3708d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3709d522f475Smrg -1 3710d522f475Smrg }, glyph_lf[] = { 3711d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 3712d522f475Smrg SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 3713d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3714d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3715d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3716d522f475Smrg -1 3717d522f475Smrg }, glyph_nl[] = { 3718d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 3719d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 3720d522f475Smrg SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3721d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 3722d522f475Smrg SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 3723d522f475Smrg -1 3724d522f475Smrg }, glyph_vt[] = { 3725d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 3726d522f475Smrg SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3727d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3728d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3729d522f475Smrg -1 3730d522f475Smrg }, plus_or_minus[] = 3731d522f475Smrg { 3732d522f475Smrg SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 3733d522f475Smrg SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 3734d522f475Smrg SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 3735d522f475Smrg -1 3736d522f475Smrg }, lower_right_corner[] = 3737d522f475Smrg { 3738d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3739d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 3740d522f475Smrg -1 3741d522f475Smrg }, upper_right_corner[] = 3742d522f475Smrg { 3743d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3744d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3745d522f475Smrg -1 3746d522f475Smrg }, upper_left_corner[] = 3747d522f475Smrg { 3748d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3749d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3750d522f475Smrg -1 3751d522f475Smrg }, lower_left_corner[] = 3752d522f475Smrg { 3753d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3754d522f475Smrg SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 3755d522f475Smrg -1 3756d522f475Smrg }, cross[] = 3757d522f475Smrg { 3758d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3759d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3760d522f475Smrg -1 3761d522f475Smrg }, scan_line_1[] = 3762d522f475Smrg { 3763d522f475Smrg SEG( 0, 0, BOX_WIDE, 0), 3764d522f475Smrg -1 3765d522f475Smrg }, scan_line_3[] = 3766d522f475Smrg { 3767d522f475Smrg SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 3768d522f475Smrg -1 3769d522f475Smrg }, scan_line_7[] = 3770d522f475Smrg { 3771d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3772d522f475Smrg -1 3773d522f475Smrg }, scan_line_9[] = 3774d522f475Smrg { 3775d522f475Smrg SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 3776d522f475Smrg -1 3777d522f475Smrg }, horizontal_line[] = 3778d522f475Smrg { 3779d522f475Smrg SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 3780d522f475Smrg -1 3781d522f475Smrg }, left_tee[] = 3782d522f475Smrg { 3783d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3784d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3785d522f475Smrg -1 3786d522f475Smrg }, right_tee[] = 3787d522f475Smrg { 3788d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3789d522f475Smrg SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 3790d522f475Smrg -1 3791d522f475Smrg }, bottom_tee[] = 3792d522f475Smrg { 3793d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3794d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3795d522f475Smrg -1 3796d522f475Smrg }, top_tee[] = 3797d522f475Smrg { 3798d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3799d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3800d522f475Smrg -1 3801d522f475Smrg }, vertical_line[] = 3802d522f475Smrg { 3803d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3804d522f475Smrg -1 3805d522f475Smrg }, less_than_or_equal[] = 3806d522f475Smrg { 3807d522f475Smrg SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 3808d522f475Smrg SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 3809d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3810d522f475Smrg -1 3811d522f475Smrg }, greater_than_or_equal[] = 3812d522f475Smrg { 3813d522f475Smrg SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3814d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3815d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3816d522f475Smrg -1 3817d522f475Smrg }, greek_pi[] = 3818d522f475Smrg { 3819d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3820d522f475Smrg SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 3821d522f475Smrg SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 3822d522f475Smrg -1 3823d522f475Smrg }, not_equal_to[] = 3824d522f475Smrg { 3825d522f475Smrg SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 3826d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 3827d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3828d522f475Smrg -1 3829d522f475Smrg }; 3830d522f475Smrg 3831d4fba8b9Smrg static const struct { 3832d4fba8b9Smrg const int mode; /* 1=y, 2=x, 3=both */ 3833d4fba8b9Smrg const short *data; 3834d4fba8b9Smrg } lines[] = 3835d522f475Smrg { 3836d4fba8b9Smrg { 0, 0 }, /* 00 (unused) */ 3837d4fba8b9Smrg { 0, 0 }, /* 01 diamond */ 3838d4fba8b9Smrg { 0, 0 }, /* 02 box */ 3839d4fba8b9Smrg { 0, glyph_ht }, /* 03 HT */ 3840d4fba8b9Smrg { 0, glyph_ff }, /* 04 FF */ 3841d4fba8b9Smrg { 0, 0 }, /* 05 CR */ 3842d4fba8b9Smrg { 0, glyph_lf }, /* 06 LF */ 3843d4fba8b9Smrg { 0, 0 }, /* 07 degrees (small circle) */ 3844d4fba8b9Smrg { 3, plus_or_minus }, /* 08 */ 3845d4fba8b9Smrg { 0, glyph_nl }, /* 09 */ 3846d4fba8b9Smrg { 0, glyph_vt }, /* 0A */ 3847d4fba8b9Smrg { 3, lower_right_corner }, /* 0B */ 3848d4fba8b9Smrg { 3, upper_right_corner }, /* 0C */ 3849d4fba8b9Smrg { 3, upper_left_corner }, /* 0D */ 3850d4fba8b9Smrg { 3, lower_left_corner }, /* 0E */ 3851d4fba8b9Smrg { 3, cross }, /* 0F */ 3852d4fba8b9Smrg { 2, scan_line_1 }, /* 10 */ 3853d4fba8b9Smrg { 2, scan_line_3 }, /* 11 */ 3854d4fba8b9Smrg { 2, scan_line_7 }, /* 12 */ 3855d4fba8b9Smrg { 2, scan_line_9 }, /* 13 */ 3856d4fba8b9Smrg { 2, horizontal_line }, /* 14 */ 3857d4fba8b9Smrg { 3, left_tee }, /* 15 */ 3858d4fba8b9Smrg { 3, right_tee }, /* 16 */ 3859d4fba8b9Smrg { 3, bottom_tee }, /* 17 */ 3860d4fba8b9Smrg { 3, top_tee }, /* 18 */ 3861d4fba8b9Smrg { 1, vertical_line }, /* 19 */ 3862d4fba8b9Smrg { 0, less_than_or_equal }, /* 1A */ 3863d4fba8b9Smrg { 0, greater_than_or_equal }, /* 1B */ 3864d4fba8b9Smrg { 0, greek_pi }, /* 1C */ 3865d4fba8b9Smrg { 0, not_equal_to }, /* 1D */ 3866d4fba8b9Smrg { 0, 0 }, /* 1E LB */ 3867d4fba8b9Smrg { 0, 0 }, /* 1F bullet */ 3868d522f475Smrg }; 3869d4fba8b9Smrg /* *INDENT-ON* */ 3870d522f475Smrg 3871d522f475Smrg GC gc2; 3872d522f475Smrg CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 3873d522f475Smrg VTwin *cgsWin = WhichVWin(screen); 3874d522f475Smrg const short *p; 3875d4fba8b9Smrg unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U) 3876d4fba8b9Smrg * screen->fnt_wide); 3877d4fba8b9Smrg unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U) 3878d4fba8b9Smrg * screen->fnt_high); 3879d522f475Smrg 3880d522f475Smrg if (cells > 1) 3881956cc18dSsnj font_width *= (unsigned) cells; 3882d522f475Smrg 3883d522f475Smrg#if OPT_WIDE_CHARS 3884d522f475Smrg /* 3885d522f475Smrg * Try to show line-drawing characters if we happen to be in UTF-8 3886d522f475Smrg * mode, but have gotten an old-style font. 3887d522f475Smrg */ 3888d522f475Smrg if (screen->utf8_mode 3889d522f475Smrg#if OPT_RENDERFONT 3890d4fba8b9Smrg && !UsingRenderFont(params->xw) 3891d522f475Smrg#endif 3892d522f475Smrg && (ch > 127) 3893d522f475Smrg && (ch != UCS_REPL)) { 3894d4fba8b9Smrg int which = (params->attr_flags & BOLD) ? fBold : fNorm; 3895d522f475Smrg unsigned n; 3896d522f475Smrg for (n = 1; n < 32; n++) { 3897d4fba8b9Smrg if (xtermMissingChar(n, getNormalFont(screen, which))) 3898d4fba8b9Smrg continue; 3899d4fba8b9Smrg if (dec2ucs(screen, n) != ch) 3900d4fba8b9Smrg continue; 3901d4fba8b9Smrg TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n)); 3902d4fba8b9Smrg ch = n; 3903d4fba8b9Smrg break; 3904d522f475Smrg } 3905d522f475Smrg } 3906d522f475Smrg#endif 3907d522f475Smrg 3908d4fba8b9Smrg#if OPT_VT52_MODE 3909d4fba8b9Smrg if (!(screen->vtXX_level)) { 3910d4fba8b9Smrg switch (ch) { 3911d4fba8b9Smrg case 6: 3912d4fba8b9Smrg ch = 7; 3913d4fba8b9Smrg break; 3914d4fba8b9Smrg default: 3915d4fba8b9Smrg ch = 256; 3916d4fba8b9Smrg break; 3917d4fba8b9Smrg } 3918d4fba8b9Smrg } 3919d4fba8b9Smrg#endif 3920d4fba8b9Smrg 3921d4fba8b9Smrg /* 3922d4fba8b9Smrg * Line-drawing characters show use the full (scaled) cellsize, while 3923d4fba8b9Smrg * other characters should be shifted to center them vertically. 3924d4fba8b9Smrg */ 3925d4fba8b9Smrg if (!xftords) { 3926d4fba8b9Smrg if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) { 3927d4fba8b9Smrg font_height = (unsigned) ((float) font_height * screen->scale_height); 3928d4fba8b9Smrg } else { 3929d4fba8b9Smrg y += ScaleShift(screen); 3930d4fba8b9Smrg } 3931d4fba8b9Smrg } 3932d4fba8b9Smrg 3933d4fba8b9Smrg TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n", 3934d522f475Smrg ch, font_height, font_width, y, x, 3935d4fba8b9Smrg ((ch >= XtNumber(lines)) 3936d522f475Smrg ? "-BAD" 3937d522f475Smrg : ""))); 3938d522f475Smrg 3939d522f475Smrg if (cgsId == gcDots) { 3940d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 3941d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 3942d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3943d522f475Smrg } else { 3944d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 3945d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3946d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3947d522f475Smrg } 3948d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 3949d522f475Smrg 3950d4fba8b9Smrg if (!(params->draw_flags & NOBACKGROUND)) { 39510bd37d32Smrg XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 3952d522f475Smrg font_width, 3953d522f475Smrg font_height); 3954d522f475Smrg } 3955d522f475Smrg 3956d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 3957d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 3958d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3959d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 3960d522f475Smrg 3961d522f475Smrg XSetLineAttributes(screen->display, gc2, 3962d4fba8b9Smrg (params->attr_flags & BOLD) 3963d522f475Smrg ? ((font_height > 12) 3964d522f475Smrg ? font_height / 12 3965d522f475Smrg : 1) 3966d522f475Smrg : ((font_height > 16) 3967d522f475Smrg ? font_height / 16 3968d522f475Smrg : 1), 3969d522f475Smrg LineSolid, 3970d522f475Smrg CapProjecting, 3971d522f475Smrg JoinMiter); 3972d522f475Smrg 3973d522f475Smrg if (ch == 1) { /* diamond */ 3974d522f475Smrg XPoint points[5]; 3975d522f475Smrg int npoints = 5, n; 3976d522f475Smrg 3977d522f475Smrg points[0].x = MID_WIDE; 3978d522f475Smrg points[0].y = BOX_HIGH / 4; 3979d522f475Smrg 3980d522f475Smrg points[1].x = 8 * BOX_WIDE / 8; 3981d522f475Smrg points[1].y = MID_HIGH; 3982d522f475Smrg 3983d522f475Smrg points[2].x = points[0].x; 3984d522f475Smrg points[2].y = 3 * BOX_HIGH / 4; 3985d522f475Smrg 3986d522f475Smrg points[3].x = 0 * BOX_WIDE / 8; 3987d522f475Smrg points[3].y = points[1].y; 3988d522f475Smrg 3989d522f475Smrg points[4].x = points[0].x; 3990d522f475Smrg points[4].y = points[0].y; 3991d522f475Smrg 3992d522f475Smrg for (n = 0; n < npoints; ++n) { 3993d4fba8b9Smrg points[n].x = (short) (SCALED_X(points[n].x)); 3994d4fba8b9Smrg points[n].y = (short) (SCALED_Y(points[n].y)); 3995e39b573cSmrg points[n].x = (short) (points[n].x + x); 3996e39b573cSmrg points[n].y = (short) (points[n].y + y); 3997d522f475Smrg } 3998d522f475Smrg 3999d522f475Smrg XFillPolygon(screen->display, 40000bd37d32Smrg VDrawable(screen), gc2, 4001d522f475Smrg points, npoints, 4002d522f475Smrg Convex, CoordModeOrigin); 4003d522f475Smrg } else if (ch == 7) { /* degrees */ 4004d522f475Smrg unsigned width = (BOX_WIDE / 3); 4005956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 2); 4006956cc18dSsnj int y_coord = MID_HIGH - (int) width; 4007d522f475Smrg 4008d522f475Smrg SCALE_X(x_coord); 4009d522f475Smrg SCALE_Y(y_coord); 4010e39b573cSmrg width = (unsigned) SCALED_X(width); 4011d522f475Smrg 4012d522f475Smrg XDrawArc(screen->display, 40130bd37d32Smrg VDrawable(screen), gc2, 4014d522f475Smrg x + x_coord, y + y_coord, width, width, 4015d522f475Smrg 0, 4016d522f475Smrg 360 * 64); 4017d522f475Smrg } else if (ch == 0x1f) { /* bullet */ 4018d522f475Smrg unsigned width = 7 * BOX_WIDE / 10; 4019956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 3); 4020956cc18dSsnj int y_coord = MID_HIGH - (int) (width / 3); 4021d522f475Smrg 4022d522f475Smrg SCALE_X(x_coord); 4023d522f475Smrg SCALE_Y(y_coord); 4024e39b573cSmrg width = (unsigned) SCALED_X(width); 4025d522f475Smrg 4026d522f475Smrg XDrawArc(screen->display, 40270bd37d32Smrg VDrawable(screen), gc2, 4028d522f475Smrg x + x_coord, y + y_coord, width, width, 4029d522f475Smrg 0, 4030d522f475Smrg 360 * 64); 4031d4fba8b9Smrg } else if (ch < XtNumber(lines) 4032d4fba8b9Smrg && (p = lines[ch].data) != 0) { 4033956cc18dSsnj int coord[4]; 4034d522f475Smrg int n = 0; 4035d522f475Smrg while (*p >= 0) { 4036d522f475Smrg coord[n++] = *p++; 4037d522f475Smrg if (n == 4) { 4038d522f475Smrg SCALE_X(coord[0]); 4039d522f475Smrg SCALE_Y(coord[1]); 4040d522f475Smrg SCALE_X(coord[2]); 4041d522f475Smrg SCALE_Y(coord[3]); 4042d522f475Smrg XDrawLine(screen->display, 40430bd37d32Smrg VDrawable(screen), gc2, 4044d522f475Smrg x + coord[0], y + coord[1], 4045d522f475Smrg x + coord[2], y + coord[3]); 4046d522f475Smrg n = 0; 4047d522f475Smrg } 4048d522f475Smrg } 4049d522f475Smrg } else if (screen->force_all_chars) { 4050d522f475Smrg /* bounding rectangle, for debugging */ 40510bd37d32Smrg XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y, 4052d522f475Smrg font_width - 1, 4053d522f475Smrg font_height - 1); 4054d522f475Smrg } 4055d522f475Smrg} 4056fa3f02f3Smrg#endif /* OPT_BOX_CHARS */ 4057d522f475Smrg 4058d522f475Smrg#if OPT_RENDERFONT 4059d4fba8b9Smrg/* 4060d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out 4061d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline. 4062d4fba8b9Smrg */ 4063d4fba8b9Smrgstatic Boolean 4064d4fba8b9SmrgfoundXftGlyph(XtermWidget xw, XftFont *font, unsigned wc) 4065d4fba8b9Smrg{ 4066d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4067d4fba8b9Smrg Boolean result = False; 4068d4fba8b9Smrg 4069d4fba8b9Smrg if (font != 0 && XftGlyphExists(screen->display, font, wc)) { 4070d4fba8b9Smrg int expect; 4071d4fba8b9Smrg 4072c48a5815Smrg if ((expect = CharWidth(screen, wc)) > 0) { 4073d4fba8b9Smrg XGlyphInfo gi; 4074d4fba8b9Smrg int actual; 4075d4fba8b9Smrg 4076d4fba8b9Smrg XftTextExtents32(screen->display, font, &wc, 1, &gi); 4077d4fba8b9Smrg /* 4078d4fba8b9Smrg * Some (more than a few) fonts are sloppy; allow 10% outside 4079d4fba8b9Smrg * the bounding box to accommodate them. 4080d4fba8b9Smrg */ 4081d4fba8b9Smrg actual = ((gi.xOff * 10) >= (11 * FontWidth(screen))) ? 2 : 1; 4082d4fba8b9Smrg if (actual <= expect) { 4083d4fba8b9Smrg /* allow double-cell if wcwidth agrees */ 4084d4fba8b9Smrg result = True; 4085d4fba8b9Smrg } else { 4086d4fba8b9Smrg TRACE(("SKIP U+%04X %d vs %d (%d vs %d)\n", 4087d4fba8b9Smrg wc, gi.xOff, FontWidth(screen), actual, expect)); 4088d4fba8b9Smrg } 4089d4fba8b9Smrg } else { 4090d4fba8b9Smrg result = True; 4091d4fba8b9Smrg } 4092d4fba8b9Smrg } 4093d4fba8b9Smrg return result; 4094d4fba8b9Smrg} 4095d4fba8b9Smrg 4096d4fba8b9Smrgstatic void 4097d4fba8b9SmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, Cardinal n, unsigned wc) 4098d4fba8b9Smrg{ 4099d4fba8b9Smrg if (which->cache[n].usage != xcOpened) { 4100d4fba8b9Smrg which->opened++; 4101d4fba8b9Smrg which->cache[n].usage = xcOpened; 4102d4fba8b9Smrg /* XFT_DEBUG=3 will show useful context for this */ 4103d4fba8b9Smrg if (getenv("XFT_DEBUG") != 0) { 4104d4fba8b9Smrg printf("xterm: matched U+%04X in fontset #%d [%u:%u]\n", 4105d4fba8b9Smrg wc, n + 1, 4106d4fba8b9Smrg which->opened, 4107d4fba8b9Smrg xw->work.max_fontsets); 4108d4fba8b9Smrg } 4109d4fba8b9Smrg } 4110d4fba8b9Smrg} 4111d4fba8b9Smrg 4112d4fba8b9Smrg/* 4113d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4114d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph. 4115d4fba8b9Smrg */ 4116d4fba8b9SmrgXftFont * 4117d4fba8b9SmrgfindXftGlyph(XtermWidget xw, XftFont *given, unsigned wc) 4118d4fba8b9Smrg{ 4119d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4120d4fba8b9Smrg XTermXftFonts *which = 0; 4121d4fba8b9Smrg XftFont *result = 0; 4122d4fba8b9Smrg /* workaround for interface changes... */ 4123d4fba8b9Smrg int fontnum = screen->menu_font_number; 4124d4fba8b9Smrg static int table[] = 4125d4fba8b9Smrg { 4126d4fba8b9Smrg offsetof(TScreen, renderFontNorm), 4127d4fba8b9Smrg offsetof(TScreen, renderFontBold), 4128d4fba8b9Smrg offsetof(TScreen, renderFontItal), 4129d4fba8b9Smrg offsetof(TScreen, renderFontBtal), 4130d4fba8b9Smrg#if OPT_RENDERWIDE 4131d4fba8b9Smrg offsetof(TScreen, renderWideNorm), 4132d4fba8b9Smrg offsetof(TScreen, renderWideBold), 4133d4fba8b9Smrg offsetof(TScreen, renderWideItal), 4134d4fba8b9Smrg offsetof(TScreen, renderWideBtal), 4135d4fba8b9Smrg#endif 4136d4fba8b9Smrg }; 4137d4fba8b9Smrg Cardinal n; 4138d4fba8b9Smrg FcResult status; 4139d4fba8b9Smrg const char *tag = 0; 4140d4fba8b9Smrg 4141d4fba8b9Smrg /* if fontsets are not wanted, just leave */ 4142d4fba8b9Smrg if (xw->work.max_fontsets == 0) { 4143d4fba8b9Smrg return 0; 4144d4fba8b9Smrg } 4145d4fba8b9Smrg 4146d4fba8b9Smrg /* ignore codes in private use areas */ 4147d4fba8b9Smrg if ((wc >= 0xe000 && wc <= 0xf8ff) 4148d4fba8b9Smrg || (wc >= 0xf0000 && wc <= 0xffffd) 4149d4fba8b9Smrg || (wc >= 0x100000 && wc <= 0x10fffd)) { 4150d4fba8b9Smrg return 0; 4151d4fba8b9Smrg } 4152d4fba8b9Smrg /* the end of the BMP is reserved for non-characters */ 4153d4fba8b9Smrg if (wc >= 0xfff0 && wc <= 0xffff) { 4154d4fba8b9Smrg return 0; 4155d4fba8b9Smrg } 4156d4fba8b9Smrg 4157d4fba8b9Smrg for (n = 0; n < XtNumber(table); ++n) { 4158d4fba8b9Smrg XTermXftFonts *check = (XTermXftFonts *) ((void *) ((char *) screen 4159d4fba8b9Smrg + table[n])); 4160d4fba8b9Smrg if (check[fontnum].font == given) { 4161d4fba8b9Smrg which = &check[fontnum]; 4162d4fba8b9Smrg tag = whichFontEnum((VTFontEnum) n); 4163d4fba8b9Smrg break; 4164d4fba8b9Smrg } 4165d4fba8b9Smrg } 4166d4fba8b9Smrg if (which != 0) { 4167d4fba8b9Smrg if (which->fontset == 0) { 4168d4fba8b9Smrg FcFontSet *sortedFonts; 4169d4fba8b9Smrg FcPattern *myPattern; 4170d4fba8b9Smrg int j; 4171d4fba8b9Smrg 4172d4fba8b9Smrg myPattern = FcPatternDuplicate(which->pattern); 4173d4fba8b9Smrg 4174d4fba8b9Smrg FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4175d4fba8b9Smrg FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4176d4fba8b9Smrg 4177d4fba8b9Smrg FcConfigSubstitute(FcConfigGetCurrent(), 4178d4fba8b9Smrg myPattern, 4179d4fba8b9Smrg FcMatchPattern); 4180d4fba8b9Smrg FcDefaultSubstitute(myPattern); 4181d4fba8b9Smrg 4182d4fba8b9Smrg which->fontset = FcFontSetCreate(); 4183d4fba8b9Smrg 4184d4fba8b9Smrg sortedFonts = FcFontSort(0, myPattern, FcTrue, 0, &status); 4185d4fba8b9Smrg 4186d4fba8b9Smrg if (!sortedFonts || sortedFonts->nfont <= 0) { 4187d4fba8b9Smrg xtermWarning("did not find any usable TrueType font\n"); 4188d4fba8b9Smrg return 0; 4189d4fba8b9Smrg } 4190d4fba8b9Smrg which->limit = (unsigned) sortedFonts->nfont; 4191d4fba8b9Smrg which->cache = TypeCallocN(XTermXftCache, (which->limit + 1)); 4192d4fba8b9Smrg for (j = 0; j < sortedFonts->nfont; j++) { 4193d4fba8b9Smrg FcPattern *font_pattern; 4194d4fba8b9Smrg 4195d4fba8b9Smrg font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(), 4196d4fba8b9Smrg myPattern, 4197d4fba8b9Smrg sortedFonts->fonts[j]); 4198d4fba8b9Smrg if (font_pattern) 4199d4fba8b9Smrg FcFontSetAdd(which->fontset, font_pattern); 4200d4fba8b9Smrg } 4201d4fba8b9Smrg 4202d4fba8b9Smrg FcFontSetSortDestroy(sortedFonts); 4203d4fba8b9Smrg FcPatternDestroy(myPattern); 4204d4fba8b9Smrg } 4205d4fba8b9Smrg if (which->fontset != 0) { 4206d4fba8b9Smrg XftFont *check; 4207d4fba8b9Smrg Cardinal empty = which->limit; 4208d4fba8b9Smrg 4209d4fba8b9Smrg for (n = 0; n < which->limit; ++n) { 4210d4fba8b9Smrg XftCache usage = which->cache[n].usage; 4211d4fba8b9Smrg if (usage == xcEmpty) { 4212d4fba8b9Smrg if (empty > n) 4213d4fba8b9Smrg empty = n; 4214d4fba8b9Smrg } else if (usage == xcOpened 4215d4fba8b9Smrg || (usage == xcUnused 4216d4fba8b9Smrg && (which->opened < xw->work.max_fontsets))) { 4217d4fba8b9Smrg check = which->cache[n].font; 4218d4fba8b9Smrg if (foundXftGlyph(xw, check, wc)) { 4219d4fba8b9Smrg markXftOpened(xw, which, n, wc); 4220d4fba8b9Smrg result = check; 4221d4fba8b9Smrg TRACE_FALLBACK(xw, "old", wc, (int) n, result); 4222d4fba8b9Smrg break; 4223d4fba8b9Smrg } 4224d4fba8b9Smrg } 4225d4fba8b9Smrg } 4226d4fba8b9Smrg 4227d4fba8b9Smrg if ((result == 0) 4228d4fba8b9Smrg && (empty < which->limit) 4229d4fba8b9Smrg && (which->opened < xw->work.max_fontsets)) { 4230d4fba8b9Smrg FcPattern *myPattern = 0; 4231d4fba8b9Smrg FcPattern *myReport = 0; 4232d4fba8b9Smrg 4233d4fba8b9Smrg for (n = empty; n < which->limit; ++n) { 4234d4fba8b9Smrg if (which->cache[n].usage >= xcBogus) 4235d4fba8b9Smrg continue; 4236d4fba8b9Smrg if (resource.reportFonts) { 4237d4fba8b9Smrg myReport = FcPatternDuplicate(which->fontset->fonts[n]); 4238d4fba8b9Smrg } 4239d4fba8b9Smrg myPattern = FcPatternDuplicate(which->fontset->fonts[n]); 4240d4fba8b9Smrg check = XftFontOpenPattern(screen->display, myPattern); 4241d4fba8b9Smrg closeCachedXft(screen, which->cache[n].font); 4242d4fba8b9Smrg (void) maybeXftCache(xw, check); 4243d4fba8b9Smrg which->cache[n].font = check; 4244d4fba8b9Smrg which->cache[n].usage = xcBogus; 4245d4fba8b9Smrg if (check == 0) 4246d4fba8b9Smrg continue; /* shouldn't happen... */ 4247d4fba8b9Smrg#ifdef FC_COLOR 4248d4fba8b9Smrg if (isBogusXft(check)) { 4249d4fba8b9Smrg continue; 4250d4fba8b9Smrg } 4251d4fba8b9Smrg#endif 4252d4fba8b9Smrg if (foundXftGlyph(xw, check, wc)) { 4253d4fba8b9Smrg markXftOpened(xw, which, n, wc); 4254d4fba8b9Smrg reportXftFonts(xw, check, "fallback", tag, myReport); 4255d4fba8b9Smrg result = check; 4256d4fba8b9Smrg TRACE_FALLBACK(xw, "new", wc, (int) n, result); 4257d4fba8b9Smrg break; 4258d4fba8b9Smrg } 4259d4fba8b9Smrg /* 4260d4fba8b9Smrg * The slot is opened, but we are not using it. 4261d4fba8b9Smrg */ 4262d4fba8b9Smrg which->cache[n].usage = xcUnused; 4263d4fba8b9Smrg } 4264d4fba8b9Smrg } 4265d4fba8b9Smrg } 4266d4fba8b9Smrg } 4267d4fba8b9Smrg return result; 4268d4fba8b9Smrg} 4269d522f475Smrg 4270d522f475Smrg/* 4271d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4272d4fba8b9Smrg * return true. 4273d522f475Smrg * 4274d522f475Smrg * see xc/lib/Xft/xftglyphs.c 4275d522f475Smrg */ 4276d522f475SmrgBool 42779a64e1c5SmrgxtermXftMissing(XtermWidget xw, XftFont *font, unsigned wc) 4278d522f475Smrg{ 4279d522f475Smrg Bool result = False; 4280d522f475Smrg 4281d522f475Smrg if (font != 0) { 4282956cc18dSsnj TScreen *screen = TScreenOf(xw); 4283956cc18dSsnj if (!XftGlyphExists(screen->display, font, wc)) { 4284d522f475Smrg#if OPT_WIDE_CHARS 4285dfb07bc7Smrg TRACE2(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 4286d4fba8b9Smrg wc, ucs2dec(screen, wc), dec2ucs(screen, wc))); 4287d522f475Smrg#else 4288dfb07bc7Smrg TRACE2(("xtermXftMissing %d\n", wc)); 4289d522f475Smrg#endif 4290d522f475Smrg result = True; 4291d522f475Smrg } 4292d522f475Smrg } 4293d522f475Smrg return result; 4294d522f475Smrg} 4295fa3f02f3Smrg#endif /* OPT_RENDERFONT */ 4296d522f475Smrg 4297d522f475Smrg#if OPT_WIDE_CHARS 4298d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break 4299d522f475Smrgunsigned 4300d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch) 4301d522f475Smrg{ 4302d522f475Smrg unsigned result = ch; 4303d4fba8b9Smrg 4304d4fba8b9Smrg (void) screen; 4305d522f475Smrg if ((ch > 127) 4306d522f475Smrg && (ch != UCS_REPL)) { 4307d4fba8b9Smrg#if OPT_VT52_MODE 4308d4fba8b9Smrg if (screen != 0 && !(screen->vtXX_level)) { 4309d4fba8b9Smrg /* 4310d4fba8b9Smrg * Intentionally empty: it would be possible to use the built-in 4311d4fba8b9Smrg * line-drawing fallback in xtermDrawBoxChar(), but for testing 4312d4fba8b9Smrg * ncurses, this is good enough. 4313d4fba8b9Smrg */ 4314d4fba8b9Smrg ; 4315d4fba8b9Smrg } else 4316d4fba8b9Smrg#endif 4317d4fba8b9Smrg switch (ch) { 4318d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4319d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4320d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4321d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4322d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4323d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4324d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4325d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4326d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4327d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4328d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4329d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4330d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4331d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4332d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4333d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4334d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4335d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4336d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4337d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4338d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4339d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4340d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4341d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4342d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4343d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4344d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4345d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4346d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4347d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4348d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4349d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4350d4fba8b9Smrg } 4351d522f475Smrg } 4352d522f475Smrg return result; 4353d522f475Smrg} 4354d522f475Smrg 4355d522f475Smrg#undef MY_UCS 4356d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break 4357d522f475Smrg 4358d522f475Smrgunsigned 4359d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch) 4360d522f475Smrg{ 4361d522f475Smrg unsigned result = ch; 4362d4fba8b9Smrg 4363d4fba8b9Smrg (void) screen; 4364d522f475Smrg if (xtermIsDecGraphic(ch)) { 4365d4fba8b9Smrg#if OPT_VT52_MODE 4366d4fba8b9Smrg if (screen != 0 && !(screen->vtXX_level)) { 4367d4fba8b9Smrg switch (ch) { 4368d4fba8b9Smrg MY_UCS(0x0020, 0); /* nbsp, treat as blank */ 4369d4fba8b9Smrg MY_UCS(0x0020, 1); /* reserved, treat as blank */ 4370d4fba8b9Smrg MY_UCS(0x25ae, 2); /* black vertical rectangle */ 4371d4fba8b9Smrg MY_UCS(0x215f, 3); /* "1/" */ 4372d4fba8b9Smrg MY_UCS(0x0020, 4); /* "3/", not in Unicode, ignore */ 4373d4fba8b9Smrg MY_UCS(0x0020, 5); /* "5/", not in Unicode, ignore */ 4374d4fba8b9Smrg MY_UCS(0x0020, 6); /* "7/", not in Unicode, ignore */ 4375d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4376d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4377d4fba8b9Smrg MY_UCS(0x2192, 9); /* right-arrow */ 4378d4fba8b9Smrg MY_UCS(0x2026, 10); /* ellipsis */ 4379d4fba8b9Smrg MY_UCS(0x00f7, 11); /* divide by */ 4380d4fba8b9Smrg MY_UCS(0x2193, 12); /* down arrow */ 4381d4fba8b9Smrg MY_UCS(0x23ba, 13); /* bar at scan 0 */ 4382d4fba8b9Smrg MY_UCS(0x23ba, 14); /* bar at scan 1 */ 4383d4fba8b9Smrg MY_UCS(0x23bb, 15); /* bar at scan 2 */ 4384d4fba8b9Smrg MY_UCS(0x23bb, 16); /* bar at scan 3 */ 4385d4fba8b9Smrg MY_UCS(0x23bc, 17); /* bar at scan 4 */ 4386d4fba8b9Smrg MY_UCS(0x23bc, 18); /* bar at scan 5 */ 4387d4fba8b9Smrg MY_UCS(0x23bd, 19); /* bar at scan 6 */ 4388d4fba8b9Smrg MY_UCS(0x23bd, 20); /* bar at scan 7 */ 4389d4fba8b9Smrg MY_UCS(0x2080, 21); /* subscript 0 */ 4390d4fba8b9Smrg MY_UCS(0x2081, 22); /* subscript 1 */ 4391d4fba8b9Smrg MY_UCS(0x2082, 23); /* subscript 2 */ 4392d4fba8b9Smrg MY_UCS(0x2083, 24); /* subscript 3 */ 4393d4fba8b9Smrg MY_UCS(0x2084, 25); /* subscript 4 */ 4394d4fba8b9Smrg MY_UCS(0x2085, 26); /* subscript 5 */ 4395d4fba8b9Smrg MY_UCS(0x2086, 27); /* subscript 6 */ 4396d4fba8b9Smrg MY_UCS(0x2087, 28); /* subscript 7 */ 4397d4fba8b9Smrg MY_UCS(0x2088, 29); /* subscript 8 */ 4398d4fba8b9Smrg MY_UCS(0x2089, 30); /* subscript 9 */ 4399d4fba8b9Smrg MY_UCS(0x00b6, 31); /* paragraph */ 4400d4fba8b9Smrg } 4401d4fba8b9Smrg } else 4402d4fba8b9Smrg#endif 4403d4fba8b9Smrg switch (ch) { 4404d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4405d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4406d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4407d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4408d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4409d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4410d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4411d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4412d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4413d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4414d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4415d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4416d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4417d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4418d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4419d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4420d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4421d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4422d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4423d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4424d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4425d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4426d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4427d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4428d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4429d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4430d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4431d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4432d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4433d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4434d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4435d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4436d4fba8b9Smrg } 4437d522f475Smrg } 4438d522f475Smrg return result; 4439d522f475Smrg} 4440d522f475Smrg 4441d522f475Smrg#endif /* OPT_WIDE_CHARS */ 4442d522f475Smrg 4443b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS 44440bd37d32Smrgstatic int 4445d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum) 4446d522f475Smrg{ 4447d522f475Smrg TScreen *screen = TScreenOf(xw); 4448d522f475Smrg 4449d522f475Smrg if (screen->menu_font_sizes[fontnum] == 0) { 4450d522f475Smrg XTermFonts fnt; 4451d522f475Smrg 4452d522f475Smrg memset(&fnt, 0, sizeof(fnt)); 4453d522f475Smrg screen->menu_font_sizes[fontnum] = -1; 4454dfb07bc7Smrg if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, True)) { 445520d2c4d2Smrg if (fontnum <= fontMenu_lastBuiltin 44560bd37d32Smrg || strcmp(fnt.fn, DEFFONT)) { 445720d2c4d2Smrg screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 44580bd37d32Smrg if (screen->menu_font_sizes[fontnum] <= 0) 44590bd37d32Smrg screen->menu_font_sizes[fontnum] = -1; 44600bd37d32Smrg } 4461d522f475Smrg xtermCloseFont(xw, &fnt); 4462d522f475Smrg } 4463d522f475Smrg } 44640bd37d32Smrg return (screen->menu_font_sizes[fontnum] > 0); 4465d522f475Smrg} 4466d522f475Smrg 4467d522f475Smrg/* 4468d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 4469d522f475Smrg */ 4470d522f475Smrgstatic void 4471d522f475SmrglookupFontSizes(XtermWidget xw) 4472d522f475Smrg{ 4473d522f475Smrg int n; 4474d522f475Smrg 4475d522f475Smrg for (n = 0; n < NMENUFONTS; n++) { 44760bd37d32Smrg (void) lookupOneFontSize(xw, n); 4477d522f475Smrg } 4478d522f475Smrg} 4479b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 4480d522f475Smrg 44812eaa94a1Schristos#if OPT_RENDERFONT 44829a64e1c5Smrgstatic double 44839a64e1c5SmrgdefaultFaceSize(void) 44849a64e1c5Smrg{ 44859a64e1c5Smrg double result; 44869a64e1c5Smrg float value; 44879a64e1c5Smrg 44889a64e1c5Smrg if (sscanf(DEFFACESIZE, "%f", &value) == 1) 4489d4fba8b9Smrg result = (double) value; 44909a64e1c5Smrg else 44919a64e1c5Smrg result = 14.0; 44929a64e1c5Smrg return result; 44939a64e1c5Smrg} 44949a64e1c5Smrg 44950bd37d32Smrgstatic void 44960bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum) 44970bd37d32Smrg{ 44980bd37d32Smrg TScreen *screen = TScreenOf(xw); 4499d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 45000bd37d32Smrg 45010bd37d32Smrg if (face_size <= 0.0) { 45020bd37d32Smrg#if OPT_SHIFT_FONTS 45030bd37d32Smrg /* 45040bd37d32Smrg * If the user is switching font-sizes, make it follow by 45050bd37d32Smrg * default the same ratios to the default as the fixed fonts 45060bd37d32Smrg * would, for easy comparison. There will be some differences 45070bd37d32Smrg * since the fixed fonts have a variety of height/width ratios, 45080bd37d32Smrg * but this is simpler than adding another resource value - and 45090bd37d32Smrg * as noted above, the data for the fixed fonts are available. 45100bd37d32Smrg */ 45110bd37d32Smrg (void) lookupOneFontSize(xw, 0); 45120bd37d32Smrg if (fontnum == fontMenu_default) { 45139a64e1c5Smrg face_size = defaultFaceSize(); 45140bd37d32Smrg } else if (lookupOneFontSize(xw, fontnum) 45150bd37d32Smrg && (screen->menu_font_sizes[0] 45160bd37d32Smrg != screen->menu_font_sizes[fontnum])) { 45170bd37d32Smrg double ratio; 45180bd37d32Smrg long num = screen->menu_font_sizes[fontnum]; 45190bd37d32Smrg long den = screen->menu_font_sizes[0]; 45200bd37d32Smrg 45210bd37d32Smrg if (den <= 0) 45220bd37d32Smrg den = 1; 45230bd37d32Smrg ratio = dimSquareRoot((double) num / (double) den); 45240bd37d32Smrg 4525d4fba8b9Smrg face_size = (ratio * (double) xw->misc.face_size[0]); 45260bd37d32Smrg TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 45270bd37d32Smrg fontnum, num, den, ratio, face_size)); 45280bd37d32Smrg } else 45290bd37d32Smrg#endif 45300bd37d32Smrg { 4531d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default]) 45320bd37d32Smrg switch (fontnum) { 45330bd37d32Smrg case fontMenu_font1: 45340bd37d32Smrg face_size = LikeBitmap(2.0); 45350bd37d32Smrg break; 45360bd37d32Smrg case fontMenu_font2: 45370bd37d32Smrg face_size = LikeBitmap(35.0); 45380bd37d32Smrg break; 45390bd37d32Smrg case fontMenu_font3: 45400bd37d32Smrg face_size = LikeBitmap(60.0); 45410bd37d32Smrg break; 45420bd37d32Smrg default: 45439a64e1c5Smrg face_size = defaultFaceSize(); 45440bd37d32Smrg break; 45450bd37d32Smrg case fontMenu_font4: 45460bd37d32Smrg face_size = LikeBitmap(90.0); 45470bd37d32Smrg break; 45480bd37d32Smrg case fontMenu_font5: 45490bd37d32Smrg face_size = LikeBitmap(135.0); 45500bd37d32Smrg break; 45510bd37d32Smrg case fontMenu_font6: 45520bd37d32Smrg face_size = LikeBitmap(200.0); 45530bd37d32Smrg break; 4554d4fba8b9Smrg case fontMenu_font7: 4555d4fba8b9Smrg face_size = LikeBitmap(240.0); 4556d4fba8b9Smrg break; 45570bd37d32Smrg } 45580bd37d32Smrg TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 45590bd37d32Smrg } 45600bd37d32Smrg xw->misc.face_size[fontnum] = (float) face_size; 45610bd37d32Smrg } 45620bd37d32Smrg} 45630bd37d32Smrg 45640bd37d32Smrg/* no selection or escape */ 45650bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 45660bd37d32Smrg 45670bd37d32Smrg/* 45680bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font 45690bd37d32Smrg * sizes are the same, and if we're using TrueType fonts. 45700bd37d32Smrg */ 45712eaa94a1Schristosstatic Boolean 45722eaa94a1SchristosuseFaceSizes(XtermWidget xw) 45732eaa94a1Schristos{ 45742eaa94a1Schristos Boolean result = False; 45752eaa94a1Schristos 4576d4fba8b9Smrg TRACE(("useFaceSizes " TRACE_L "\n")); 45772eaa94a1Schristos if (UsingRenderFont(xw)) { 45780bd37d32Smrg Boolean nonzero = True; 4579037a25ddSmrg int n; 45800bd37d32Smrg 45812eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 4582d4fba8b9Smrg if (xw->misc.face_size[n] <= 0.0f) { 45830bd37d32Smrg nonzero = False; 45842eaa94a1Schristos break; 45852eaa94a1Schristos } 45862eaa94a1Schristos } 45870bd37d32Smrg if (!nonzero) { 4588956cc18dSsnj Boolean broken_fonts = True; 4589956cc18dSsnj TScreen *screen = TScreenOf(xw); 45900bd37d32Smrg long first; 4591956cc18dSsnj 4592956cc18dSsnj lookupFontSizes(xw); 45930bd37d32Smrg first = screen->menu_font_sizes[0]; 4594956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 4595956cc18dSsnj if (screen->menu_font_sizes[n] > 0 4596956cc18dSsnj && screen->menu_font_sizes[n] != first) { 4597956cc18dSsnj broken_fonts = False; 4598956cc18dSsnj break; 4599956cc18dSsnj } 4600956cc18dSsnj } 4601956cc18dSsnj 4602956cc18dSsnj if (broken_fonts) { 4603956cc18dSsnj 4604956cc18dSsnj TRACE(("bitmap fonts are broken - set faceSize resources\n")); 4605956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 46060bd37d32Smrg fillInFaceSize(xw, n); 4607956cc18dSsnj } 4608956cc18dSsnj 4609956cc18dSsnj } 4610956cc18dSsnj } 46110bd37d32Smrg result = True; 46122eaa94a1Schristos } 4613d4fba8b9Smrg TRACE((TRACE_R " useFaceSizes %d\n", result)); 46142eaa94a1Schristos return result; 46152eaa94a1Schristos} 46160bd37d32Smrg#endif /* OPT_RENDERFONT */ 46172eaa94a1Schristos 4618b6fea0ceSmrg#if OPT_SHIFT_FONTS 4619d522f475Smrg/* 4620d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative' 4621d522f475Smrg * and its magnitude), starting from the 'old' index. 4622d522f475Smrg */ 4623d522f475Smrgint 4624d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative) 4625d522f475Smrg{ 4626d522f475Smrg TScreen *screen = TScreenOf(xw); 4627037a25ddSmrg int m = -1; 4628d522f475Smrg 46292eaa94a1Schristos TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 4630d522f475Smrg if (!IsIcon(screen)) { 46312eaa94a1Schristos#if OPT_RENDERFONT 46322eaa94a1Schristos if (useFaceSizes(xw)) { 46332eaa94a1Schristos TRACE(("...using FaceSize\n")); 46342eaa94a1Schristos if (relative != 0) { 4635037a25ddSmrg int n; 46362eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 46370bd37d32Smrg fillInFaceSize(xw, n); 46382eaa94a1Schristos if (xw->misc.face_size[n] > 0 && 46392eaa94a1Schristos xw->misc.face_size[n] != xw->misc.face_size[old]) { 46402eaa94a1Schristos int cmp_0 = ((xw->misc.face_size[n] > 46412eaa94a1Schristos xw->misc.face_size[old]) 46422eaa94a1Schristos ? relative 46432eaa94a1Schristos : -relative); 46442eaa94a1Schristos int cmp_m = ((m < 0) 46452eaa94a1Schristos ? 1 46462eaa94a1Schristos : ((xw->misc.face_size[n] < 46472eaa94a1Schristos xw->misc.face_size[m]) 46482eaa94a1Schristos ? relative 46492eaa94a1Schristos : -relative)); 46502eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 46512eaa94a1Schristos m = n; 46522eaa94a1Schristos } 4653d522f475Smrg } 4654d522f475Smrg } 4655d522f475Smrg } 46562eaa94a1Schristos } else 46572eaa94a1Schristos#endif 46582eaa94a1Schristos { 46592eaa94a1Schristos TRACE(("...using bitmap areas\n")); 46602eaa94a1Schristos lookupFontSizes(xw); 46612eaa94a1Schristos if (relative != 0) { 4662037a25ddSmrg int n; 46632eaa94a1Schristos for (n = 0; n < NMENUFONTS; ++n) { 46642eaa94a1Schristos if (screen->menu_font_sizes[n] > 0 && 46652eaa94a1Schristos screen->menu_font_sizes[n] != 46662eaa94a1Schristos screen->menu_font_sizes[old]) { 46672eaa94a1Schristos int cmp_0 = ((screen->menu_font_sizes[n] > 46682eaa94a1Schristos screen->menu_font_sizes[old]) 46692eaa94a1Schristos ? relative 46702eaa94a1Schristos : -relative); 46712eaa94a1Schristos int cmp_m = ((m < 0) 46722eaa94a1Schristos ? 1 46732eaa94a1Schristos : ((screen->menu_font_sizes[n] < 46742eaa94a1Schristos screen->menu_font_sizes[m]) 46752eaa94a1Schristos ? relative 46762eaa94a1Schristos : -relative)); 46772eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 46782eaa94a1Schristos m = n; 46792eaa94a1Schristos } 46802eaa94a1Schristos } 46812eaa94a1Schristos } 4682d522f475Smrg } 4683d522f475Smrg } 46842eaa94a1Schristos TRACE(("...new index %d\n", m)); 46852eaa94a1Schristos if (m >= 0) { 46862eaa94a1Schristos if (relative > 1) 46872eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative - 1); 46882eaa94a1Schristos else if (relative < -1) 46892eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative + 1); 46902eaa94a1Schristos } 4691d522f475Smrg } 4692d522f475Smrg return m; 4693d522f475Smrg} 4694d522f475Smrg 4695d522f475Smrg/* ARGSUSED */ 4696d522f475Smrgvoid 4697d4fba8b9SmrgHandleLargerFont(Widget w, 46989a64e1c5Smrg XEvent *event GCC_UNUSED, 4699fa3f02f3Smrg String *params GCC_UNUSED, 4700d522f475Smrg Cardinal *param_count GCC_UNUSED) 4701d522f475Smrg{ 4702956cc18dSsnj XtermWidget xw; 4703d522f475Smrg 470420d2c4d2Smrg TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 4705956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 4706d522f475Smrg if (xw->misc.shift_fonts) { 4707956cc18dSsnj TScreen *screen = TScreenOf(xw); 4708d522f475Smrg int m; 4709d522f475Smrg 4710d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 4711d522f475Smrg if (m >= 0) { 4712d522f475Smrg SetVTFont(xw, m, True, NULL); 4713d522f475Smrg } else { 471420d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4715d522f475Smrg } 4716d522f475Smrg } 4717d522f475Smrg } 4718d522f475Smrg} 4719d522f475Smrg 4720d522f475Smrg/* ARGSUSED */ 4721d522f475Smrgvoid 4722d4fba8b9SmrgHandleSmallerFont(Widget w, 47239a64e1c5Smrg XEvent *event GCC_UNUSED, 4724fa3f02f3Smrg String *params GCC_UNUSED, 4725d522f475Smrg Cardinal *param_count GCC_UNUSED) 4726d522f475Smrg{ 4727956cc18dSsnj XtermWidget xw; 4728d522f475Smrg 472920d2c4d2Smrg TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 4730956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 4731d522f475Smrg if (xw->misc.shift_fonts) { 4732956cc18dSsnj TScreen *screen = TScreenOf(xw); 4733d522f475Smrg int m; 4734d522f475Smrg 4735d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 4736d522f475Smrg if (m >= 0) { 4737d522f475Smrg SetVTFont(xw, m, True, NULL); 4738d522f475Smrg } else { 473920d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4740d522f475Smrg } 4741d522f475Smrg } 4742d522f475Smrg } 4743d522f475Smrg} 4744b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */ 4745d522f475Smrg 4746d522f475Smrgint 4747d522f475SmrgxtermGetFont(const char *param) 4748d522f475Smrg{ 4749d522f475Smrg int fontnum; 4750d522f475Smrg 4751d522f475Smrg switch (param[0]) { 4752d522f475Smrg case 'd': 4753d522f475Smrg case 'D': 4754d522f475Smrg case '0': 4755d522f475Smrg fontnum = fontMenu_default; 4756d522f475Smrg break; 4757d522f475Smrg case '1': 4758d522f475Smrg fontnum = fontMenu_font1; 4759d522f475Smrg break; 4760d522f475Smrg case '2': 4761d522f475Smrg fontnum = fontMenu_font2; 4762d522f475Smrg break; 4763d522f475Smrg case '3': 4764d522f475Smrg fontnum = fontMenu_font3; 4765d522f475Smrg break; 4766d522f475Smrg case '4': 4767d522f475Smrg fontnum = fontMenu_font4; 4768d522f475Smrg break; 4769d522f475Smrg case '5': 4770d522f475Smrg fontnum = fontMenu_font5; 4771d522f475Smrg break; 4772d522f475Smrg case '6': 4773d522f475Smrg fontnum = fontMenu_font6; 4774d522f475Smrg break; 4775d4fba8b9Smrg case '7': 4776d4fba8b9Smrg fontnum = fontMenu_font7; 4777d4fba8b9Smrg break; 4778d522f475Smrg case 'e': 4779d522f475Smrg case 'E': 4780d522f475Smrg fontnum = fontMenu_fontescape; 4781d522f475Smrg break; 4782d522f475Smrg case 's': 4783d522f475Smrg case 'S': 4784d522f475Smrg fontnum = fontMenu_fontsel; 4785d522f475Smrg break; 4786d522f475Smrg default: 4787d522f475Smrg fontnum = -1; 4788d522f475Smrg break; 4789d522f475Smrg } 4790d4fba8b9Smrg TRACE(("xtermGetFont(%s) ->%d\n", NonNull(param), fontnum)); 4791d522f475Smrg return fontnum; 4792d522f475Smrg} 4793d522f475Smrg 4794d522f475Smrg/* ARGSUSED */ 4795d522f475Smrgvoid 4796d4fba8b9SmrgHandleSetFont(Widget w, 47979a64e1c5Smrg XEvent *event GCC_UNUSED, 4798fa3f02f3Smrg String *params, 4799d522f475Smrg Cardinal *param_count) 4800d522f475Smrg{ 4801956cc18dSsnj XtermWidget xw; 4802956cc18dSsnj 4803956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 4804d522f475Smrg int fontnum; 4805d522f475Smrg VTFontNames fonts; 4806d522f475Smrg 4807d522f475Smrg memset(&fonts, 0, sizeof(fonts)); 4808d522f475Smrg 4809d522f475Smrg if (*param_count == 0) { 4810d522f475Smrg fontnum = fontMenu_default; 4811d522f475Smrg } else { 4812d522f475Smrg Cardinal maxparams = 1; /* total number of params allowed */ 4813d522f475Smrg int result = xtermGetFont(params[0]); 4814d522f475Smrg 4815d522f475Smrg switch (result) { 4816d522f475Smrg case fontMenu_default: /* FALLTHRU */ 4817d522f475Smrg case fontMenu_font1: /* FALLTHRU */ 4818d522f475Smrg case fontMenu_font2: /* FALLTHRU */ 4819d522f475Smrg case fontMenu_font3: /* FALLTHRU */ 4820d522f475Smrg case fontMenu_font4: /* FALLTHRU */ 4821d522f475Smrg case fontMenu_font5: /* FALLTHRU */ 4822d522f475Smrg case fontMenu_font6: /* FALLTHRU */ 4823d4fba8b9Smrg case fontMenu_font7: /* FALLTHRU */ 4824d522f475Smrg break; 4825d522f475Smrg case fontMenu_fontescape: 4826d522f475Smrg#if OPT_WIDE_CHARS 4827d522f475Smrg maxparams = 5; 4828d522f475Smrg#else 4829d522f475Smrg maxparams = 3; 4830d522f475Smrg#endif 4831d522f475Smrg break; 4832d522f475Smrg case fontMenu_fontsel: 4833d522f475Smrg maxparams = 2; 4834d522f475Smrg break; 4835d522f475Smrg default: 483620d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4837d522f475Smrg return; 4838d522f475Smrg } 4839d522f475Smrg fontnum = result; 4840d522f475Smrg 4841d522f475Smrg if (*param_count > maxparams) { /* see if extra args given */ 484220d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4843d522f475Smrg return; 4844d522f475Smrg } 4845d522f475Smrg switch (*param_count) { /* assign 'em */ 4846d522f475Smrg#if OPT_WIDE_CHARS 4847d522f475Smrg case 5: 4848dfb07bc7Smrg fonts.f_wb = x_strdup(params[4]); 4849d522f475Smrg /* FALLTHRU */ 4850d522f475Smrg case 4: 4851dfb07bc7Smrg fonts.f_w = x_strdup(params[3]); 4852d522f475Smrg#endif 4853dfb07bc7Smrg /* FALLTHRU */ 4854d522f475Smrg case 3: 4855dfb07bc7Smrg fonts.f_b = x_strdup(params[2]); 4856d522f475Smrg /* FALLTHRU */ 4857d522f475Smrg case 2: 4858dfb07bc7Smrg fonts.f_n = x_strdup(params[1]); 4859d522f475Smrg break; 4860d522f475Smrg } 4861d522f475Smrg } 4862d522f475Smrg 4863956cc18dSsnj SetVTFont(xw, fontnum, True, &fonts); 4864d522f475Smrg } 4865d522f475Smrg} 4866d522f475Smrg 4867d522f475Smrgvoid 4868d522f475SmrgSetVTFont(XtermWidget xw, 4869d522f475Smrg int which, 4870d522f475Smrg Bool doresize, 4871d522f475Smrg const VTFontNames * fonts) 4872d522f475Smrg{ 4873956cc18dSsnj TScreen *screen = TScreenOf(xw); 4874d522f475Smrg 4875d522f475Smrg TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 4876d522f475Smrg (fonts && fonts->f_n) ? fonts->f_n : "<null>", 4877d522f475Smrg (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 4878d522f475Smrg 4879d522f475Smrg if (IsIcon(screen)) { 488020d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4881d522f475Smrg } else if (which >= 0 && which < NMENUFONTS) { 4882d522f475Smrg VTFontNames myfonts; 4883d522f475Smrg 4884d522f475Smrg memset(&myfonts, 0, sizeof(myfonts)); 4885d522f475Smrg if (fonts != 0) 4886d522f475Smrg myfonts = *fonts; 4887d522f475Smrg 4888d522f475Smrg if (which == fontMenu_fontsel) { /* go get the selection */ 4889d522f475Smrg FindFontSelection(xw, myfonts.f_n, False); 4890d522f475Smrg } else { 4891d522f475Smrg int oldFont = screen->menu_font_number; 4892d522f475Smrg 4893d522f475Smrg#define USE_CACHED(field, name) \ 4894d522f475Smrg if (myfonts.field == 0) { \ 4895492d43a5Smrg myfonts.field = x_strdup(screen->menu_font_names[which][name]); \ 4896d522f475Smrg TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 4897d522f475Smrg which, NonNull(myfonts.field))); \ 4898d522f475Smrg } else { \ 4899d522f475Smrg TRACE(("set myfonts." #field " reused\n")); \ 4900d522f475Smrg } 490120d2c4d2Smrg#define SAVE_FNAME(field, name) \ 490220d2c4d2Smrg if (myfonts.field != 0) { \ 490320d2c4d2Smrg if (screen->menu_font_names[which][name] == 0 \ 490420d2c4d2Smrg || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \ 4905d4fba8b9Smrg TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \ 490620d2c4d2Smrg which, myfonts.field)); \ 49079a64e1c5Smrg FREE_STRING(screen->menu_font_names[which][name]); \ 490820d2c4d2Smrg screen->menu_font_names[which][name] = x_strdup(myfonts.field); \ 490920d2c4d2Smrg } \ 491020d2c4d2Smrg } 491120d2c4d2Smrg 4912d522f475Smrg USE_CACHED(f_n, fNorm); 4913d522f475Smrg USE_CACHED(f_b, fBold); 4914d522f475Smrg#if OPT_WIDE_CHARS 4915d522f475Smrg USE_CACHED(f_w, fWide); 4916d522f475Smrg USE_CACHED(f_wb, fWBold); 4917d522f475Smrg#endif 4918d522f475Smrg if (xtermLoadFont(xw, 4919d522f475Smrg &myfonts, 4920d522f475Smrg doresize, which)) { 492120d2c4d2Smrg /* 492220d2c4d2Smrg * If successful, save the data so that a subsequent query via 492320d2c4d2Smrg * OSC-50 will return the expected values. 492420d2c4d2Smrg */ 492520d2c4d2Smrg SAVE_FNAME(f_n, fNorm); 492620d2c4d2Smrg SAVE_FNAME(f_b, fBold); 492720d2c4d2Smrg#if OPT_WIDE_CHARS 492820d2c4d2Smrg SAVE_FNAME(f_w, fWide); 492920d2c4d2Smrg SAVE_FNAME(f_wb, fWBold); 493020d2c4d2Smrg#endif 4931d522f475Smrg } else { 493294644356Smrg (void) xtermLoadFont(xw, 493394644356Smrg xtermFontName(screen->MenuFontName(oldFont)), 493494644356Smrg doresize, oldFont); 493520d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4936d522f475Smrg } 49379a64e1c5Smrg FREE_FNAME(f_n); 49389a64e1c5Smrg FREE_FNAME(f_b); 49399a64e1c5Smrg#if OPT_WIDE_CHARS 49409a64e1c5Smrg FREE_FNAME(f_w); 49419a64e1c5Smrg FREE_FNAME(f_wb); 49429a64e1c5Smrg#endif 4943d522f475Smrg } 494420d2c4d2Smrg } else { 494520d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4946d522f475Smrg } 4947d522f475Smrg return; 4948d522f475Smrg} 4949dfb07bc7Smrg 4950dfb07bc7Smrg#if OPT_RENDERFONT 4951dfb07bc7Smrgstatic void 4952dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size) 4953dfb07bc7Smrg{ 4954dfb07bc7Smrg char *first = strstr(face_name, ":size="); 4955dfb07bc7Smrg if (first == 0) { 4956dfb07bc7Smrg first = face_name; 4957dfb07bc7Smrg } else { 4958dfb07bc7Smrg first++; 4959dfb07bc7Smrg } 4960dfb07bc7Smrg if (!strncmp(first, "size=", (size_t) 5)) { 4961dfb07bc7Smrg char *last = strchr(first, ':'); 4962dfb07bc7Smrg char mark; 4963dfb07bc7Smrg float value; 4964dfb07bc7Smrg char extra; 4965dfb07bc7Smrg TRACE(("...before trimming, font = \"%s\"\n", face_name)); 4966dfb07bc7Smrg if (last == 0) 4967dfb07bc7Smrg last = first + strlen(first); 4968dfb07bc7Smrg mark = *last; 4969dfb07bc7Smrg *last = '\0'; 4970dfb07bc7Smrg if (sscanf(first, "size=%g%c", &value, &extra) == 1) { 4971dfb07bc7Smrg TRACE(("...trimmed size from font: %g\n", value)); 4972dfb07bc7Smrg if (face_size != 0) 4973dfb07bc7Smrg *face_size = value; 4974dfb07bc7Smrg } 4975dfb07bc7Smrg if (mark) { 4976dfb07bc7Smrg while ((*first++ = *++last) != '\0') { 4977dfb07bc7Smrg ; 4978dfb07bc7Smrg } 4979dfb07bc7Smrg } else { 4980dfb07bc7Smrg if (first != face_name) 4981dfb07bc7Smrg --first; 4982dfb07bc7Smrg *first = '\0'; 4983dfb07bc7Smrg } 4984dfb07bc7Smrg TRACE(("...after trimming, font = \"%s\"\n", face_name)); 4985dfb07bc7Smrg } 4986dfb07bc7Smrg} 4987dfb07bc7Smrg#endif 4988dfb07bc7Smrg 4989dfb07bc7Smrg/* 4990dfb07bc7Smrg * Save a font specification to the proper list. 4991dfb07bc7Smrg */ 4992dfb07bc7Smrgstatic void 4993dfb07bc7Smrgsave2FontList(XtermWidget xw, 4994dfb07bc7Smrg const char *name, 4995dfb07bc7Smrg XtermFontNames * fontnames, 4996dfb07bc7Smrg VTFontEnum which, 4997dfb07bc7Smrg const char *source, 4998dfb07bc7Smrg Bool ttf) 4999dfb07bc7Smrg{ 5000dfb07bc7Smrg char *value; 5001dfb07bc7Smrg size_t plen; 5002dfb07bc7Smrg Bool marked = False; 5003dfb07bc7Smrg Bool use_ttf = ttf; 5004dfb07bc7Smrg 5005dfb07bc7Smrg (void) xw; 5006dfb07bc7Smrg 5007dfb07bc7Smrg if (source == 0) 5008dfb07bc7Smrg source = ""; 5009dfb07bc7Smrg while (isspace(CharOf(*source))) 5010dfb07bc7Smrg ++source; 5011dfb07bc7Smrg 5012dfb07bc7Smrg /* fontconfig patterns can contain ':' separators, but we'll treat 5013dfb07bc7Smrg * a leading prefix specially to denote whether the pattern might be 5014dfb07bc7Smrg * XLFD ("x" or "xlfd") versus Xft ("xft"). 5015dfb07bc7Smrg */ 5016dfb07bc7Smrg for (plen = 0; source[plen] != '\0'; ++plen) { 5017dfb07bc7Smrg if (source[plen] == ':') { 5018dfb07bc7Smrg marked = True; 5019dfb07bc7Smrg switch (plen) { 5020dfb07bc7Smrg case 0: 5021dfb07bc7Smrg ++plen; /* trim leading ':' */ 5022dfb07bc7Smrg break; 5023dfb07bc7Smrg case 1: 5024dfb07bc7Smrg if (!strncmp(source, "x", plen)) { 5025dfb07bc7Smrg ++plen; 5026dfb07bc7Smrg use_ttf = False; 5027dfb07bc7Smrg } else { 5028dfb07bc7Smrg marked = False; 5029dfb07bc7Smrg } 5030dfb07bc7Smrg break; 5031dfb07bc7Smrg case 3: 5032dfb07bc7Smrg if (!strncmp(source, "xft", plen)) { 5033dfb07bc7Smrg ++plen; 5034dfb07bc7Smrg use_ttf = True; 5035dfb07bc7Smrg } else { 5036dfb07bc7Smrg marked = False; 5037dfb07bc7Smrg } 5038dfb07bc7Smrg break; 5039dfb07bc7Smrg case 4: 5040dfb07bc7Smrg if (!strncmp(source, "xlfd", plen)) { 5041dfb07bc7Smrg ++plen; 5042dfb07bc7Smrg use_ttf = False; 5043dfb07bc7Smrg } else { 5044dfb07bc7Smrg marked = False; 5045dfb07bc7Smrg } 5046dfb07bc7Smrg break; 5047dfb07bc7Smrg default: 5048dfb07bc7Smrg marked = False; 5049dfb07bc7Smrg plen = 0; 5050dfb07bc7Smrg break; 5051dfb07bc7Smrg } 5052dfb07bc7Smrg break; 5053dfb07bc7Smrg } 5054dfb07bc7Smrg } 5055dfb07bc7Smrg if (!marked) 5056dfb07bc7Smrg plen = 0; 5057dfb07bc7Smrg value = x_strtrim(source + plen); 5058dfb07bc7Smrg if (value != 0) { 5059dfb07bc7Smrg Bool success = False; 5060dfb07bc7Smrg#if OPT_RENDERFONT 5061dfb07bc7Smrg VTFontList *target = (use_ttf 5062dfb07bc7Smrg ? &(fontnames->xft) 5063dfb07bc7Smrg : &(fontnames->x11)); 5064dfb07bc7Smrg#else 5065dfb07bc7Smrg VTFontList *target = &(fontnames->x11); 5066dfb07bc7Smrg#endif 5067dfb07bc7Smrg char ***list = 0; 5068dfb07bc7Smrg char **next = 0; 5069dfb07bc7Smrg size_t count = 0; 5070dfb07bc7Smrg 5071dfb07bc7Smrg (void) use_ttf; 5072dfb07bc7Smrg switch (which) { 5073dfb07bc7Smrg case fNorm: 5074dfb07bc7Smrg list = &(target->list_n); 5075dfb07bc7Smrg break; 5076dfb07bc7Smrg case fBold: 5077dfb07bc7Smrg list = &(target->list_b); 5078dfb07bc7Smrg break; 5079dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5080dfb07bc7Smrg case fItal: 5081dfb07bc7Smrg list = &(target->list_i); 5082dfb07bc7Smrg break; 5083d4fba8b9Smrg case fBtal: 5084d4fba8b9Smrg list = &(target->list_bi); 5085d4fba8b9Smrg break; 5086dfb07bc7Smrg#endif 5087dfb07bc7Smrg#if OPT_WIDE_CHARS 5088dfb07bc7Smrg case fWide: 5089dfb07bc7Smrg list = &(target->list_w); 5090dfb07bc7Smrg break; 5091dfb07bc7Smrg case fWBold: 5092dfb07bc7Smrg list = &(target->list_wb); 5093dfb07bc7Smrg break; 5094dfb07bc7Smrg case fWItal: 5095dfb07bc7Smrg list = &(target->list_wi); 5096dfb07bc7Smrg break; 5097d4fba8b9Smrg case fWBtal: 5098d4fba8b9Smrg list = &(target->list_wbi); 5099d4fba8b9Smrg break; 5100dfb07bc7Smrg#endif 5101dfb07bc7Smrg case fMAX: 5102dfb07bc7Smrg list = 0; 5103dfb07bc7Smrg break; 5104dfb07bc7Smrg } 5105dfb07bc7Smrg 5106dfb07bc7Smrg if (list != 0) { 5107dfb07bc7Smrg success = True; 5108dfb07bc7Smrg if (*list != 0) { 5109dfb07bc7Smrg while ((*list)[count] != 0) { 5110dfb07bc7Smrg if (IsEmpty((*list)[count])) { 5111dfb07bc7Smrg TRACE(("... initial %s\n", value)); 5112dfb07bc7Smrg free((*list)[count]); 5113dfb07bc7Smrg break; 5114dfb07bc7Smrg } else if (!strcmp(value, (*list)[count])) { 5115dfb07bc7Smrg TRACE(("... duplicate %s\n", value)); 5116dfb07bc7Smrg success = False; 5117dfb07bc7Smrg break; 5118dfb07bc7Smrg } 5119dfb07bc7Smrg ++count; 5120dfb07bc7Smrg } 5121dfb07bc7Smrg } 5122dfb07bc7Smrg if (success) { 5123dfb07bc7Smrg next = realloc(*list, sizeof(char *) * (count + 2)); 5124dfb07bc7Smrg if (next != 0) { 5125dfb07bc7Smrg#if OPT_RENDERFONT 5126dfb07bc7Smrg if (use_ttf) { 5127dfb07bc7Smrg trimSizeFromFace(value, 5128dfb07bc7Smrg (count == 0 && which == fNorm) 5129dfb07bc7Smrg ? &(xw->misc.face_size[0]) 5130dfb07bc7Smrg : (float *) 0); 5131dfb07bc7Smrg } 5132dfb07bc7Smrg#endif 5133dfb07bc7Smrg next[count++] = value; 5134dfb07bc7Smrg next[count] = 0; 5135dfb07bc7Smrg *list = next; 51368f44fb3bSmrg TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n", 5137dfb07bc7Smrg whichFontList(xw, target), 5138dfb07bc7Smrg whichFontList2(xw, *list), 5139dfb07bc7Smrg (unsigned long) count, 5140dfb07bc7Smrg value)); 5141dfb07bc7Smrg } else { 5142dfb07bc7Smrg fprintf(stderr, 5143dfb07bc7Smrg "realloc failure in save2FontList(%s)\n", 5144dfb07bc7Smrg name); 5145dfb07bc7Smrg freeFontList(list); 5146dfb07bc7Smrg success = False; 5147dfb07bc7Smrg } 5148dfb07bc7Smrg } 5149dfb07bc7Smrg } 5150dfb07bc7Smrg if (success) { 5151d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS) 5152d4fba8b9Smrg size_t limit = MAX_XFT_FONTS; 5153d4fba8b9Smrg#else 5154dfb07bc7Smrg size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS; 5155d4fba8b9Smrg#endif 5156d4fba8b9Smrg if (count > limit && *x_skip_blanks(value)) { 5157dfb07bc7Smrg fprintf(stderr, "%s: too many fonts for %s, ignoring %s\n", 5158dfb07bc7Smrg ProgramName, 5159dfb07bc7Smrg whichFontEnum(which), 5160dfb07bc7Smrg value); 5161dfb07bc7Smrg if (list && *list) { 5162dfb07bc7Smrg free((*list)[limit]); 5163dfb07bc7Smrg (*list)[limit] = 0; 5164dfb07bc7Smrg } 5165dfb07bc7Smrg } 5166dfb07bc7Smrg } else { 5167dfb07bc7Smrg free(value); 5168dfb07bc7Smrg } 5169dfb07bc7Smrg } 5170dfb07bc7Smrg} 5171dfb07bc7Smrg 5172dfb07bc7Smrg/* 5173dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list 5174dfb07bc7Smrg * of font-names. That would be bad for performance, but as a basis for an 5175dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating 5176dfb07bc7Smrg * an array of font-names. 5177dfb07bc7Smrg */ 5178dfb07bc7Smrgvoid 5179dfb07bc7SmrgallocFontList(XtermWidget xw, 5180dfb07bc7Smrg const char *name, 5181dfb07bc7Smrg XtermFontNames * target, 5182dfb07bc7Smrg VTFontEnum which, 5183dfb07bc7Smrg const char *source, 5184dfb07bc7Smrg Bool ttf) 5185dfb07bc7Smrg{ 5186dfb07bc7Smrg char *blob; 5187dfb07bc7Smrg 5188dfb07bc7Smrg blob = x_strdup(source); 5189d4fba8b9Smrg if (blob != 0) { 5190dfb07bc7Smrg int n; 5191dfb07bc7Smrg int pass; 5192dfb07bc7Smrg char **list = 0; 5193dfb07bc7Smrg 51948f44fb3bSmrg TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n", 51958f44fb3bSmrg whichFontEnum(which), name, blob)); 5196dfb07bc7Smrg 5197dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5198dfb07bc7Smrg unsigned count = 0; 5199dfb07bc7Smrg if (pass) 5200dfb07bc7Smrg list[0] = blob; 5201dfb07bc7Smrg for (n = 0; blob[n] != '\0'; ++n) { 5202dfb07bc7Smrg if (blob[n] == ',') { 5203dfb07bc7Smrg ++count; 5204dfb07bc7Smrg if (pass != 0) { 5205dfb07bc7Smrg blob[n] = '\0'; 5206dfb07bc7Smrg list[count] = blob + n + 1; 5207dfb07bc7Smrg } 5208dfb07bc7Smrg } 5209dfb07bc7Smrg } 5210dfb07bc7Smrg if (!pass) { 5211dfb07bc7Smrg if (count == 0 && *blob == '\0') 5212dfb07bc7Smrg break; 5213dfb07bc7Smrg list = TypeCallocN(char *, count + 2); 5214dfb07bc7Smrg if (list == 0) 5215dfb07bc7Smrg break; 5216dfb07bc7Smrg } 5217dfb07bc7Smrg } 5218dfb07bc7Smrg if (list) { 5219dfb07bc7Smrg for (n = 0; list[n] != 0; ++n) { 5220dfb07bc7Smrg if (*list[n]) { 5221dfb07bc7Smrg save2FontList(xw, name, target, which, list[n], ttf); 5222dfb07bc7Smrg } 5223dfb07bc7Smrg } 5224dfb07bc7Smrg free(list); 5225dfb07bc7Smrg } 5226dfb07bc7Smrg } 5227dfb07bc7Smrg free(blob); 5228dfb07bc7Smrg} 5229dfb07bc7Smrg 5230dfb07bc7Smrgstatic void 5231dfb07bc7SmrginitFontList(XtermWidget xw, 5232dfb07bc7Smrg const char *name, 5233dfb07bc7Smrg XtermFontNames * target, 5234dfb07bc7Smrg Bool ttf) 5235dfb07bc7Smrg{ 5236dfb07bc7Smrg int which; 5237dfb07bc7Smrg 5238dfb07bc7Smrg TRACE(("initFontList(%s)\n", name)); 5239dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5240dfb07bc7Smrg save2FontList(xw, name, target, (VTFontEnum) which, "", ttf); 5241dfb07bc7Smrg } 5242dfb07bc7Smrg} 5243dfb07bc7Smrg 5244dfb07bc7Smrgvoid 5245dfb07bc7SmrginitFontLists(XtermWidget xw) 5246dfb07bc7Smrg{ 5247dfb07bc7Smrg TRACE(("initFontLists\n")); 5248dfb07bc7Smrg initFontList(xw, "x11 font", &(xw->work.fonts), False); 5249dfb07bc7Smrg#if OPT_RENDERFONT 5250dfb07bc7Smrg initFontList(xw, "xft font", &(xw->work.fonts), True); 5251dfb07bc7Smrg#endif 5252dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5253dfb07bc7Smrg initFontList(xw, "cached font", 5254dfb07bc7Smrg &(xw->screen.cacheVTFonts.fonts), False); 5255dfb07bc7Smrg#endif 5256dfb07bc7Smrg} 5257dfb07bc7Smrg 5258dfb07bc7Smrgvoid 5259dfb07bc7SmrgcopyFontList(char ***targetp, char **source) 5260dfb07bc7Smrg{ 5261dfb07bc7Smrg freeFontList(targetp); 5262dfb07bc7Smrg 5263dfb07bc7Smrg if (source != 0) { 5264dfb07bc7Smrg int pass; 5265dfb07bc7Smrg size_t count; 5266dfb07bc7Smrg 5267dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5268dfb07bc7Smrg for (count = 0; source[count] != 0; ++count) { 5269dfb07bc7Smrg if (pass) 5270dfb07bc7Smrg (*targetp)[count] = x_strdup(source[count]); 5271dfb07bc7Smrg } 5272dfb07bc7Smrg if (!pass) { 5273dfb07bc7Smrg ++count; 5274dfb07bc7Smrg *targetp = TypeCallocN(char *, count); 5275dfb07bc7Smrg } 5276dfb07bc7Smrg } 5277dfb07bc7Smrg } else { 5278dfb07bc7Smrg *targetp = TypeCallocN(char *, 2); 5279dfb07bc7Smrg (*targetp)[0] = x_strdup(""); 5280dfb07bc7Smrg } 5281dfb07bc7Smrg} 5282dfb07bc7Smrg 5283dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5284dfb07bc7Smrgstatic Boolean 5285dfb07bc7Smrgmerge_sublist(char ***targetp, char **source) 5286dfb07bc7Smrg{ 5287dfb07bc7Smrg Boolean result = False; 5288dfb07bc7Smrg if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) { 5289dfb07bc7Smrg copyFontList(targetp, source); 5290dfb07bc7Smrg result = True; 5291dfb07bc7Smrg } 5292dfb07bc7Smrg return result; 5293dfb07bc7Smrg} 5294dfb07bc7Smrg#endif 5295dfb07bc7Smrg 5296dfb07bc7Smrgvoid 5297dfb07bc7SmrgfreeFontList(char ***targetp) 5298dfb07bc7Smrg{ 5299dfb07bc7Smrg if (targetp != 0) { 5300dfb07bc7Smrg char **target = *targetp; 5301dfb07bc7Smrg if (target != 0) { 5302dfb07bc7Smrg int n; 5303dfb07bc7Smrg for (n = 0; target[n] != 0; ++n) { 5304dfb07bc7Smrg free(target[n]); 5305dfb07bc7Smrg } 5306dfb07bc7Smrg free(target); 5307dfb07bc7Smrg *targetp = 0; 5308dfb07bc7Smrg } 5309dfb07bc7Smrg } 5310dfb07bc7Smrg} 5311dfb07bc7Smrg 5312dfb07bc7Smrgvoid 5313dfb07bc7SmrgfreeFontLists(VTFontList * lists) 5314dfb07bc7Smrg{ 5315dfb07bc7Smrg int which; 5316dfb07bc7Smrg 5317dfb07bc7Smrg TRACE(("freeFontLists\n")); 5318dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5319dfb07bc7Smrg char ***target = 0; 5320dfb07bc7Smrg switch (which) { 5321dfb07bc7Smrg case fNorm: 5322dfb07bc7Smrg target = &(lists->list_n); 5323dfb07bc7Smrg break; 5324dfb07bc7Smrg case fBold: 5325dfb07bc7Smrg target = &(lists->list_b); 5326dfb07bc7Smrg break; 5327dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5328dfb07bc7Smrg case fItal: 5329dfb07bc7Smrg target = &(lists->list_i); 5330dfb07bc7Smrg break; 5331d4fba8b9Smrg case fBtal: 5332d4fba8b9Smrg target = &(lists->list_bi); 5333d4fba8b9Smrg break; 5334dfb07bc7Smrg#endif 5335dfb07bc7Smrg#if OPT_WIDE_CHARS 5336dfb07bc7Smrg case fWide: 5337dfb07bc7Smrg target = &(lists->list_w); 5338dfb07bc7Smrg break; 5339dfb07bc7Smrg case fWBold: 5340dfb07bc7Smrg target = &(lists->list_wb); 5341dfb07bc7Smrg break; 5342dfb07bc7Smrg case fWItal: 5343dfb07bc7Smrg target = &(lists->list_wi); 5344dfb07bc7Smrg break; 5345d4fba8b9Smrg case fWBtal: 5346d4fba8b9Smrg target = &(lists->list_wbi); 5347d4fba8b9Smrg break; 5348dfb07bc7Smrg#endif 5349dfb07bc7Smrg default: 5350dfb07bc7Smrg target = 0; 5351dfb07bc7Smrg break; 5352dfb07bc7Smrg } 5353dfb07bc7Smrg freeFontList(target); 5354dfb07bc7Smrg } 5355dfb07bc7Smrg} 5356dfb07bc7Smrg 5357dfb07bc7Smrg/* 5358dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class. 5359dfb07bc7Smrg * XXX make this allocate the font on demand. 5360dfb07bc7Smrg */ 5361dfb07bc7SmrgXTermFonts * 5362dfb07bc7SmrggetNormalFont(TScreen *screen, int which) 5363dfb07bc7Smrg{ 5364dfb07bc7Smrg XTermFonts *result = 0; 5365dfb07bc7Smrg if (which >= 0 && which < fMAX) 5366d4fba8b9Smrg result = GetNormalFont(screen, which); 5367dfb07bc7Smrg return result; 5368dfb07bc7Smrg} 5369dfb07bc7Smrg 5370dfb07bc7Smrg#if OPT_DEC_CHRSET 5371dfb07bc7SmrgXTermFonts * 5372dfb07bc7SmrggetDoubleFont(TScreen *screen, int which) 5373dfb07bc7Smrg{ 5374dfb07bc7Smrg XTermFonts *result = 0; 5375dfb07bc7Smrg if ((int) which >= 0 && which < NUM_CHRSET) 5376d4fba8b9Smrg result = GetDoubleFont(screen, which); 5377d4fba8b9Smrg return result; 5378d4fba8b9Smrg} 5379d4fba8b9Smrg 5380d4fba8b9Smrg#if OPT_RENDERFONT 5381d4fba8b9SmrgXftFont * 5382d4fba8b9SmrggetDoubleXftFont(XTermDraw * params, unsigned chrset, unsigned attr_flags) 5383d4fba8b9Smrg{ 5384d4fba8b9Smrg XftFont *result = 0; 5385d4fba8b9Smrg 5386d4fba8b9Smrg XtermWidget xw = params->xw; 5387d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 5388d4fba8b9Smrg XftPattern *top_pattern; 5389d4fba8b9Smrg int fontnum = screen->menu_font_number; 5390d4fba8b9Smrg const char *face_name = getFaceName(xw, False); 5391d4fba8b9Smrg 5392d4fba8b9Smrg if (chrset != CSET_SWL 5393d4fba8b9Smrg && (top_pattern = XftNameParse(face_name)) != 0) { 5394d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 5395d4fba8b9Smrg XftPattern *sub_pattern = XftPatternDuplicate(top_pattern); 5396d4fba8b9Smrg 5397d4fba8b9Smrg switch (chrset) { 5398d4fba8b9Smrg case CSET_DHL_TOP: 5399d4fba8b9Smrg /* FALLTHRU */ 5400d4fba8b9Smrg case CSET_DHL_BOT: 5401d4fba8b9Smrg face_size *= 2; 5402d4fba8b9Smrg XftPatternBuild(sub_pattern, 5403d4fba8b9Smrg NormXftPattern, 5404d4fba8b9Smrg (void *) 0); 5405d4fba8b9Smrg break; 5406d4fba8b9Smrg case CSET_DWL: 5407d4fba8b9Smrg XftPatternBuild(sub_pattern, 5408d4fba8b9Smrg NormXftPattern, 5409d4fba8b9Smrg FC_ASPECT, XftTypeDouble, 2.0, 5410d4fba8b9Smrg (void *) 0); 5411d4fba8b9Smrg break; 5412d4fba8b9Smrg } 5413d4fba8b9Smrg if (attr_flags & BOLD) { 5414d4fba8b9Smrg XftPatternBuild(sub_pattern, 5415d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, 5416d4fba8b9Smrg (void *) 0); 5417d4fba8b9Smrg } 5418d4fba8b9Smrg result = xtermOpenXft(xw, face_name, sub_pattern, "doublesize"); 5419d4fba8b9Smrg } 5420dfb07bc7Smrg return result; 5421dfb07bc7Smrg} 5422dfb07bc7Smrg#endif 5423d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */ 5424dfb07bc7Smrg 5425dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5426dfb07bc7SmrgXTermFonts * 5427dfb07bc7SmrggetItalicFont(TScreen *screen, int which) 5428dfb07bc7Smrg{ 5429dfb07bc7Smrg XTermFonts *result = 0; 5430dfb07bc7Smrg#if OPT_WIDE_ATTRS 5431dfb07bc7Smrg if (which >= 0 && which < fMAX) 5432d4fba8b9Smrg result = GetItalicFont(screen, which); 5433dfb07bc7Smrg#else 5434dfb07bc7Smrg (void) screen; 5435dfb07bc7Smrg (void) which; 5436dfb07bc7Smrg#endif 5437dfb07bc7Smrg return result; 5438dfb07bc7Smrg} 5439dfb07bc7Smrg#endif 5440dfb07bc7Smrg 5441dfb07bc7Smrg#if OPT_RENDERFONT 5442dfb07bc7Smrg/* 5443dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font. 5444dfb07bc7Smrg * XXX make this allocate the font on demand. 5445dfb07bc7Smrg */ 5446dfb07bc7SmrgXTermXftFonts * 5447dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum) 5448dfb07bc7Smrg{ 5449dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 5450dfb07bc7Smrg XTermXftFonts *result = 0; 5451dfb07bc7Smrg if (fontnum >= 0 && fontnum < NMENUFONTS) { 5452dfb07bc7Smrg switch ((VTFontEnum) which) { 5453dfb07bc7Smrg case fNorm: 5454dfb07bc7Smrg result = &(screen->renderFontNorm[fontnum]); 5455dfb07bc7Smrg break; 5456dfb07bc7Smrg case fBold: 5457dfb07bc7Smrg result = &(screen->renderFontBold[fontnum]); 5458dfb07bc7Smrg break; 5459dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5460dfb07bc7Smrg case fItal: 5461dfb07bc7Smrg result = &(screen->renderFontItal[fontnum]); 5462dfb07bc7Smrg break; 5463d4fba8b9Smrg case fBtal: 5464d4fba8b9Smrg result = &(screen->renderFontBtal[fontnum]); 5465d4fba8b9Smrg break; 5466dfb07bc7Smrg#endif 5467dfb07bc7Smrg#if OPT_WIDE_CHARS 5468dfb07bc7Smrg case fWide: 5469dfb07bc7Smrg result = &(screen->renderWideNorm[fontnum]); 5470dfb07bc7Smrg break; 5471dfb07bc7Smrg case fWBold: 5472dfb07bc7Smrg result = &(screen->renderWideBold[fontnum]); 5473dfb07bc7Smrg break; 5474dfb07bc7Smrg case fWItal: 5475dfb07bc7Smrg result = &(screen->renderWideItal[fontnum]); 5476dfb07bc7Smrg break; 5477d4fba8b9Smrg case fWBtal: 5478d4fba8b9Smrg result = &(screen->renderWideBtal[fontnum]); 5479d4fba8b9Smrg break; 5480dfb07bc7Smrg#endif 5481dfb07bc7Smrg case fMAX: 5482dfb07bc7Smrg break; 5483dfb07bc7Smrg } 5484dfb07bc7Smrg } 5485dfb07bc7Smrg return result; 5486dfb07bc7Smrg} 5487dfb07bc7Smrg 5488dfb07bc7SmrgXftFont * 5489dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum) 5490dfb07bc7Smrg{ 5491d4fba8b9Smrg XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum); 5492dfb07bc7Smrg XftFont *result = 0; 5493dfb07bc7Smrg if (data != 0) 5494dfb07bc7Smrg result = data->font; 5495dfb07bc7Smrg return result; 5496dfb07bc7Smrg} 5497dfb07bc7Smrg#endif 5498dfb07bc7Smrg 5499dfb07bc7Smrgconst char * 5500dfb07bc7SmrgwhichFontEnum(VTFontEnum value) 5501dfb07bc7Smrg{ 5502dfb07bc7Smrg const char *result = "?"; 5503dfb07bc7Smrg#define DATA(name) case name: result = #name; break 5504dfb07bc7Smrg switch (value) { 5505dfb07bc7Smrg DATA(fNorm); 5506dfb07bc7Smrg DATA(fBold); 5507dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5508dfb07bc7Smrg DATA(fItal); 5509d4fba8b9Smrg DATA(fBtal); 5510dfb07bc7Smrg#endif 5511dfb07bc7Smrg#if OPT_WIDE_CHARS 5512dfb07bc7Smrg DATA(fWide); 5513dfb07bc7Smrg DATA(fWBold); 5514dfb07bc7Smrg DATA(fWItal); 5515d4fba8b9Smrg DATA(fWBtal); 5516dfb07bc7Smrg#endif 5517dfb07bc7Smrg DATA(fMAX); 5518dfb07bc7Smrg } 5519dfb07bc7Smrg#undef DATA 5520dfb07bc7Smrg return result; 5521dfb07bc7Smrg} 5522dfb07bc7Smrg 5523dfb07bc7Smrgconst char * 5524dfb07bc7SmrgwhichFontList(XtermWidget xw, VTFontList * value) 5525dfb07bc7Smrg{ 5526dfb07bc7Smrg const char *result = "?"; 5527dfb07bc7Smrg if (value == &(xw->work.fonts.x11)) 5528dfb07bc7Smrg result = "x11_fontnames"; 5529dfb07bc7Smrg#if OPT_RENDERFONT 5530dfb07bc7Smrg else if (value == &(xw->work.fonts.xft)) 5531dfb07bc7Smrg result = "xft_fontnames"; 5532dfb07bc7Smrg#endif 5533dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5534dfb07bc7Smrg else if (value == &(xw->screen.cacheVTFonts.fonts.x11)) 5535dfb07bc7Smrg result = "cached_fontnames"; 5536dfb07bc7Smrg#endif 5537dfb07bc7Smrg return result; 5538dfb07bc7Smrg} 5539dfb07bc7Smrg 5540dfb07bc7Smrgstatic const char * 5541dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value) 5542dfb07bc7Smrg{ 5543dfb07bc7Smrg const char *result = 0; 5544dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name 5545dfb07bc7Smrg DATA(list_n); 5546dfb07bc7Smrg DATA(list_b); 5547dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5548dfb07bc7Smrg DATA(list_i); 5549d4fba8b9Smrg DATA(list_bi); 5550dfb07bc7Smrg#endif 5551dfb07bc7Smrg#if OPT_WIDE_CHARS 5552dfb07bc7Smrg DATA(list_w); 5553dfb07bc7Smrg DATA(list_wb); 5554dfb07bc7Smrg DATA(list_wi); 5555d4fba8b9Smrg DATA(list_wbi); 5556dfb07bc7Smrg#endif 5557dfb07bc7Smrg#undef DATA 5558dfb07bc7Smrg return result; 5559dfb07bc7Smrg} 5560dfb07bc7Smrg 5561dfb07bc7Smrgconst char * 5562dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value) 5563dfb07bc7Smrg{ 5564dfb07bc7Smrg const char *result = 0; 5565dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value)) 5566dfb07bc7Smrg if (DATA(work.fonts.x11) == 0) { 5567dfb07bc7Smrg#if OPT_RENDERFONT 5568dfb07bc7Smrg if (DATA(work.fonts.xft) == 0) 5569dfb07bc7Smrg#endif 5570dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5571dfb07bc7Smrg if (DATA(screen.cacheVTFonts.fonts.x11) == 0) 5572dfb07bc7Smrg#endif 5573dfb07bc7Smrg result = "?"; 5574dfb07bc7Smrg } 5575dfb07bc7Smrg#undef DATA 5576dfb07bc7Smrg return result; 5577dfb07bc7Smrg} 5578