fontutils.c revision c48a5815
1c48a5815Smrg/* $XTermId: fontutils.c,v 1.709 2021/11/10 00:36:27 Rajeev.V.Pillai Exp $ */ 2d522f475Smrg 30bd37d32Smrg/* 4d4fba8b9Smrg * Copyright 1998-2020,2021 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) { 473d522f475Smrg want = ALLOCHUNK(want); 474d522f475Smrg if (last != 0) { 4759a64e1c5Smrg char *save = *result; 476d522f475Smrg *result = TypeRealloc(char, want, *result); 4779a64e1c5Smrg if (*result == 0) 4789a64e1c5Smrg free(save); 479d522f475Smrg } else { 480d522f475Smrg if ((*result = TypeMallocN(char, want)) != 0) 481d522f475Smrg **result = '\0'; 482d522f475Smrg } 483d522f475Smrg } 484d522f475Smrg} 485d522f475Smrg 486d522f475Smrgstatic void 48720d2c4d2Smrgappend_fontname_str(char **result, const char *value) 488d522f475Smrg{ 489d522f475Smrg if (value == 0) 490d522f475Smrg value = "*"; 491d522f475Smrg alloca_fontname(result, strlen(value)); 492d522f475Smrg if (*result != 0) { 493d522f475Smrg if (**result != '\0') 494d522f475Smrg strcat(*result, "-"); 495d522f475Smrg strcat(*result, value); 496d522f475Smrg } 497d522f475Smrg} 498d522f475Smrg 499d522f475Smrgstatic void 500d522f475Smrgappend_fontname_num(char **result, int value) 501d522f475Smrg{ 502d522f475Smrg if (value < 0) { 503d522f475Smrg append_fontname_str(result, "*"); 504d522f475Smrg } else { 505d522f475Smrg char temp[100]; 506d522f475Smrg sprintf(temp, "%d", value); 507d522f475Smrg append_fontname_str(result, temp); 508d522f475Smrg } 509d522f475Smrg} 510d522f475Smrg 511d522f475Smrg/* 512d522f475Smrg * Take the given font props and try to make a well formed font name specifying 513d522f475Smrg * the same base font and size and everything, but with different weight/width 514d522f475Smrg * according to the parameters. The return value is allocated, should be freed 515d522f475Smrg * by the caller. 516d522f475Smrg */ 517d522f475Smrgstatic char * 5189a64e1c5Smrgderive_font_name(FontNameProperties *props, 51920d2c4d2Smrg const char *use_weight, 520d522f475Smrg int use_average_width, 52120d2c4d2Smrg const char *use_encoding) 522d522f475Smrg{ 523d522f475Smrg char *result = 0; 524d522f475Smrg 525d522f475Smrg append_fontname_str(&result, props->beginning); 526d522f475Smrg append_fontname_str(&result, use_weight); 527d522f475Smrg append_fontname_str(&result, props->slant); 528d522f475Smrg append_fontname_str(&result, 0); 529d522f475Smrg append_fontname_str(&result, 0); 530d522f475Smrg append_fontname_num(&result, props->pixel_size); 531d522f475Smrg append_fontname_str(&result, props->point_size); 532d522f475Smrg append_fontname_num(&result, props->res_x); 533d522f475Smrg append_fontname_num(&result, props->res_y); 534d522f475Smrg append_fontname_str(&result, props->spacing); 535d522f475Smrg append_fontname_num(&result, use_average_width); 536d522f475Smrg append_fontname_str(&result, use_encoding); 537d522f475Smrg 538d4fba8b9Smrg xtermDerivedFont(result); 539d522f475Smrg return result; 540d522f475Smrg} 541d522f475Smrg 542d522f475Smrgstatic char * 5439a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width) 544d522f475Smrg{ 545d522f475Smrg return derive_font_name(props, "bold", use_average_width, props->end); 546d522f475Smrg} 547d522f475Smrg 5489a64e1c5Smrg#if OPT_WIDE_ATTRS 5499a64e1c5Smrgstatic char * 550dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant) 5519a64e1c5Smrg{ 5529a64e1c5Smrg FontNameProperties myprops = *props; 553dfb07bc7Smrg myprops.slant = slant; 554dfb07bc7Smrg return derive_font_name(&myprops, props->weight, myprops.average_width, props->end); 555dfb07bc7Smrg} 556dfb07bc7Smrg 557dfb07bc7Smrgstatic Boolean 558dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data) 559dfb07bc7Smrg{ 560dfb07bc7Smrg static const char *slant[] = 561dfb07bc7Smrg { 562dfb07bc7Smrg "o", 563dfb07bc7Smrg "i" 564dfb07bc7Smrg }; 565dfb07bc7Smrg Cardinal pass; 566dfb07bc7Smrg Boolean result = False; 567dfb07bc7Smrg 568d4fba8b9Smrg NoFontWarning(data); 569dfb07bc7Smrg for (pass = 0; pass < XtNumber(slant); ++pass) { 570d4fba8b9Smrg char *name; 571dfb07bc7Smrg if ((name = italic_font_name(fp, slant[pass])) != 0) { 572dfb07bc7Smrg TRACE(("open_italic_font %s %s\n", 573dfb07bc7Smrg whichFontEnum((VTFontEnum) n), name)); 574dfb07bc7Smrg if (xtermOpenFont(xw, name, data, False)) { 575dfb07bc7Smrg result = (data->fs != 0); 576dfb07bc7Smrg#if OPT_REPORT_FONTS 577dfb07bc7Smrg if (resource.reportFonts) { 578dfb07bc7Smrg printf("opened italic version of %s:\n\t%s\n", 579d4fba8b9Smrg whichFontEnum((VTFontEnum) n), 580dfb07bc7Smrg name); 581dfb07bc7Smrg } 582dfb07bc7Smrg#endif 583dfb07bc7Smrg } 584dfb07bc7Smrg free(name); 585dfb07bc7Smrg if (result) 586dfb07bc7Smrg break; 587dfb07bc7Smrg } 588dfb07bc7Smrg } 589dfb07bc7Smrg#if OPT_TRACE 590dfb07bc7Smrg if (result) { 591dfb07bc7Smrg XFontStruct *fs = data->fs; 592dfb07bc7Smrg if (fs != 0) { 593dfb07bc7Smrg TRACE(("...actual size %dx%d (ascent %d, descent %d)\n", 594dfb07bc7Smrg fs->ascent + 595dfb07bc7Smrg fs->descent, 596dfb07bc7Smrg fs->max_bounds.width, 597dfb07bc7Smrg fs->ascent, 598dfb07bc7Smrg fs->descent)); 599dfb07bc7Smrg } 600dfb07bc7Smrg } 601dfb07bc7Smrg#endif 602dfb07bc7Smrg return result; 6039a64e1c5Smrg} 6049a64e1c5Smrg#endif 6059a64e1c5Smrg 606d522f475Smrg#if OPT_WIDE_CHARS 607d522f475Smrg#define derive_wide_font(props, weight) \ 608d522f475Smrg derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 609d522f475Smrg 610d522f475Smrgstatic char * 6119a64e1c5Smrgwide_font_name(FontNameProperties *props) 612d522f475Smrg{ 613d522f475Smrg return derive_wide_font(props, "medium"); 614d522f475Smrg} 615d522f475Smrg 616d522f475Smrgstatic char * 6179a64e1c5Smrgwidebold_font_name(FontNameProperties *props) 618d522f475Smrg{ 619d522f475Smrg return derive_wide_font(props, "bold"); 620d522f475Smrg} 621d522f475Smrg#endif /* OPT_WIDE_CHARS */ 622d522f475Smrg 623d522f475Smrg#if OPT_DEC_CHRSET 624d522f475Smrg/* 625d522f475Smrg * Take the given font props and try to make a well formed font name specifying 626d522f475Smrg * the same base font but changed depending on the given attributes and chrset. 627d522f475Smrg * 628d522f475Smrg * For double width fonts, we just double the X-resolution, for double height 629d522f475Smrg * fonts we double the pixel-size and Y-resolution 630d522f475Smrg */ 631d522f475Smrgchar * 632d4fba8b9SmrgxtermSpecialFont(XTermDraw * params) 633d522f475Smrg{ 634d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 635d522f475Smrg#if OPT_TRACE 636d522f475Smrg static char old_spacing[80]; 637d522f475Smrg static FontNameProperties old_props; 638d522f475Smrg#endif 639d522f475Smrg FontNameProperties *props; 640d522f475Smrg char *result = 0; 64120d2c4d2Smrg const char *weight; 642d522f475Smrg int pixel_size; 643d522f475Smrg int res_x; 644d522f475Smrg int res_y; 645d522f475Smrg 646dfb07bc7Smrg props = get_font_name_props(screen->display, 647d4fba8b9Smrg GetNormalFont(screen, fNorm)->fs, 0); 648d522f475Smrg if (props == 0) 649d522f475Smrg return result; 650d522f475Smrg 651d522f475Smrg pixel_size = props->pixel_size; 652d522f475Smrg res_x = props->res_x; 653d522f475Smrg res_y = props->res_y; 654d4fba8b9Smrg if (params->attr_flags & BOLD) 655d522f475Smrg weight = "bold"; 656d522f475Smrg else 657d522f475Smrg weight = props->weight; 658d522f475Smrg 659d4fba8b9Smrg if (CSET_DOUBLE(params->this_chrset)) 660d522f475Smrg res_x *= 2; 661d522f475Smrg 662d4fba8b9Smrg if (params->this_chrset == CSET_DHL_TOP 663d4fba8b9Smrg || params->this_chrset == CSET_DHL_BOT) { 664d522f475Smrg res_y *= 2; 665d522f475Smrg pixel_size *= 2; 666d522f475Smrg } 667d522f475Smrg#if OPT_TRACE 668d522f475Smrg if (old_props.res_x != res_x 669d522f475Smrg || old_props.res_x != res_y 670d522f475Smrg || old_props.pixel_size != pixel_size 671d522f475Smrg || strcmp(old_props.spacing, props->spacing)) { 6729a64e1c5Smrg TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n", 673d4fba8b9Smrg params->attr_flags, params->draw_flags, params->this_chrset)); 674d522f475Smrg TRACE(("res_x = %d\n", res_x)); 675d522f475Smrg TRACE(("res_y = %d\n", res_y)); 676d522f475Smrg TRACE(("point_size = %s\n", props->point_size)); 677d522f475Smrg TRACE(("pixel_size = %d\n", pixel_size)); 678d522f475Smrg TRACE(("spacing = %s\n", props->spacing)); 679d522f475Smrg old_props.res_x = res_x; 680037a25ddSmrg old_props.res_y = res_y; 681d522f475Smrg old_props.pixel_size = pixel_size; 6820bd37d32Smrg old_props.spacing = old_spacing; 6830bd37d32Smrg sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 684d522f475Smrg } 685d522f475Smrg#endif 686d522f475Smrg 687d522f475Smrg append_fontname_str(&result, props->beginning); 688d522f475Smrg append_fontname_str(&result, weight); 689d522f475Smrg append_fontname_str(&result, props->slant); 690d522f475Smrg append_fontname_str(&result, props->wideness); 691d522f475Smrg append_fontname_str(&result, props->add_style); 692d522f475Smrg append_fontname_num(&result, pixel_size); 693d522f475Smrg append_fontname_str(&result, props->point_size); 694d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x); 695d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y); 696d522f475Smrg append_fontname_str(&result, props->spacing); 697d522f475Smrg append_fontname_str(&result, 0); 698d522f475Smrg append_fontname_str(&result, props->end); 699d522f475Smrg 700d4fba8b9Smrg xtermDerivedFont(result); 701d522f475Smrg return result; 702d522f475Smrg} 703d522f475Smrg#endif /* OPT_DEC_CHRSET */ 704d522f475Smrg 705d522f475Smrg/* 706d522f475Smrg * Case-independent comparison for font-names, including wildcards. 707d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 708d522f475Smrg * to use it). 709d522f475Smrg */ 710d522f475Smrgstatic Bool 711492d43a5Smrgsame_font_name(const char *pattern, const char *match) 712d522f475Smrg{ 713956cc18dSsnj Bool result = False; 714956cc18dSsnj 715956cc18dSsnj if (pattern && match) { 716956cc18dSsnj while (*pattern && *match) { 717956cc18dSsnj if (*pattern == *match) { 718956cc18dSsnj pattern++; 719956cc18dSsnj match++; 720956cc18dSsnj } else if (*pattern == '*' || *match == '*') { 721956cc18dSsnj if (same_font_name(pattern + 1, match)) { 722956cc18dSsnj return True; 723956cc18dSsnj } else if (same_font_name(pattern, match + 1)) { 724956cc18dSsnj return True; 725956cc18dSsnj } else { 726956cc18dSsnj return False; 727956cc18dSsnj } 728d522f475Smrg } else { 729956cc18dSsnj int p = x_toupper(*pattern++); 730956cc18dSsnj int m = x_toupper(*match++); 731956cc18dSsnj if (p != m) 732956cc18dSsnj return False; 733d522f475Smrg } 734d522f475Smrg } 735956cc18dSsnj result = (*pattern == *match); /* both should be NUL */ 736d522f475Smrg } 737956cc18dSsnj return result; 738d522f475Smrg} 739d522f475Smrg 740d522f475Smrg/* 741d522f475Smrg * Double-check the fontname that we asked for versus what the font server 742d522f475Smrg * actually gave us. The larger fixed fonts do not always have a matching bold 743d522f475Smrg * font, and the font server may try to scale another font or otherwise 744d522f475Smrg * substitute a mismatched font. 745d522f475Smrg * 746d522f475Smrg * If we cannot get what we requested, we will fallback to the original 747d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel 748d522f475Smrg * offset. 749d522f475Smrg */ 750d522f475Smrgstatic int 7519a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested) 752d522f475Smrg{ 7530bd37d32Smrg char *actual = 0; 754d522f475Smrg int got; 755d522f475Smrg 7560bd37d32Smrg if (get_font_name_props(dpy, fs, &actual) == 0) 757d522f475Smrg got = 0; 758d522f475Smrg else 759d522f475Smrg got = same_font_name(requested, actual); 7600bd37d32Smrg free(actual); 761d522f475Smrg return got; 762d522f475Smrg} 763d522f475Smrg 7649a64e1c5Smrg/* 7659a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able 7669a64e1c5Smrg * to check for missing glyphs in a comparable manner. 7679a64e1c5Smrg */ 7689a64e1c5Smrgstatic int 7699a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold) 7709a64e1c5Smrg{ 7719a64e1c5Smrg#define DATA "comparable_metrics: " 7729a64e1c5Smrg int result = 0; 7739a64e1c5Smrg 774dfb07bc7Smrg if (normal == 0 || bold == 0) { 775dfb07bc7Smrg ; 776dfb07bc7Smrg } else if (normal->all_chars_exist) { 7779a64e1c5Smrg if (bold->all_chars_exist) { 7789a64e1c5Smrg result = 1; 7799a64e1c5Smrg } else { 7809a64e1c5Smrg TRACE((DATA "all chars exist in normal font, but not in bold\n")); 7819a64e1c5Smrg } 7829a64e1c5Smrg } else if (normal->per_char != 0) { 7839a64e1c5Smrg if (bold->per_char != 0) { 7849a64e1c5Smrg result = 1; 7859a64e1c5Smrg } else { 7869a64e1c5Smrg TRACE((DATA "normal font has per-char metrics, but not bold\n")); 7879a64e1c5Smrg } 7889a64e1c5Smrg } else { 7899a64e1c5Smrg TRACE((DATA "normal font is not very good!\n")); 7909a64e1c5Smrg result = 1; /* give in (we're not going in reverse) */ 7919a64e1c5Smrg } 7929a64e1c5Smrg return result; 7939a64e1c5Smrg#undef DATA 7949a64e1c5Smrg} 7959a64e1c5Smrg 796d522f475Smrg/* 797d522f475Smrg * If the font server tries to adjust another font, it may not adjust it 798d522f475Smrg * properly. Check that the bounding boxes are compatible. Otherwise we'll 799d522f475Smrg * leave trash on the display when we mix normal and bold fonts. 800d522f475Smrg */ 801d522f475Smrgstatic int 8029a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs) 803d522f475Smrg{ 804956cc18dSsnj TScreen *screen = TScreenOf(xw); 805dfb07bc7Smrg int result = 0; 806dfb07bc7Smrg 807dfb07bc7Smrg if (nfs != 0 && bfs != 0) { 808dfb07bc7Smrg TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 809dfb07bc7Smrg nfs->ascent + nfs->descent, 810dfb07bc7Smrg bfs->ascent + bfs->descent, 811dfb07bc7Smrg nfs->min_bounds.width, bfs->min_bounds.width, 812dfb07bc7Smrg nfs->max_bounds.width, bfs->max_bounds.width)); 813dfb07bc7Smrg result = screen->free_bold_box 814dfb07bc7Smrg || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 815dfb07bc7Smrg && (nfs->min_bounds.width == bfs->min_bounds.width 816dfb07bc7Smrg || nfs->min_bounds.width == bfs->min_bounds.width + 1) 817dfb07bc7Smrg && (nfs->max_bounds.width == bfs->max_bounds.width 818dfb07bc7Smrg || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 819dfb07bc7Smrg } 820dfb07bc7Smrg return result; 821d522f475Smrg} 822d522f475Smrg 823d522f475Smrg/* 824d522f475Smrg * Check if the font looks like it has fixed width 825d522f475Smrg */ 826d522f475Smrgstatic int 8279a64e1c5Smrgis_fixed_font(XFontStruct *fs) 828d522f475Smrg{ 829d522f475Smrg if (fs) 830d522f475Smrg return (fs->min_bounds.width == fs->max_bounds.width); 831d522f475Smrg return 1; 832d522f475Smrg} 833d522f475Smrg 834d4fba8b9Smrgstatic int 835d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b) 836d4fba8b9Smrg{ 837d4fba8b9Smrg int result = 0; 838d4fba8b9Smrg if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width) 839d4fba8b9Smrg result = 1; 840d4fba8b9Smrg return result; 841d4fba8b9Smrg} 842d4fba8b9Smrg 843d522f475Smrg/* 844d522f475Smrg * Check if the font looks like a double width font (i.e. contains 845d522f475Smrg * characters of width X and 2X 846d522f475Smrg */ 847d522f475Smrg#if OPT_WIDE_CHARS 848d522f475Smrgstatic int 8499a64e1c5Smrgis_double_width_font(XFontStruct *fs) 850d522f475Smrg{ 851d4fba8b9Smrg return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width)); 852d522f475Smrg} 853d522f475Smrg#else 854d522f475Smrg#define is_double_width_font(fs) 0 855d522f475Smrg#endif 856d522f475Smrg 857d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 858d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890" 859d522f475Smrg 860d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */ 861d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 862d522f475Smrg "\xe5\x9b\x9b\xe4\xba\x94" \ 863d522f475Smrg "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 864d522f475Smrg "\xe4\xb9\x9d\xef\xa6\xb2" 865d522f475Smrg 866d522f475Smrg/* '1234567890' in Korean script in UTF-8 */ 867d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 868d522f475Smrg "\xec\x82\xac\xec\x98\xa4" \ 869d522f475Smrg "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 870d522f475Smrg "\xea\xb5\xac\xec\x98\x81" 871d522f475Smrg 872d522f475Smrg#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 873d522f475Smrg#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 874d522f475Smrg#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 875d522f475Smrg#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 876d522f475Smrg 877d522f475Smrgstatic Bool 8789a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font) 879d522f475Smrg{ 880d522f475Smrg XGlyphInfo gi1, gi2; 881d522f475Smrg FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 8820bd37d32Smrg String fwstr = FULL_WIDTH_TEST_STRING; 8830bd37d32Smrg String hwstr = HALF_WIDTH_TEST_STRING; 884d522f475Smrg 885d522f475Smrg /* Some Korean fonts don't have Chinese characters at all. */ 886d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 887d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 888d522f475Smrg return False; /* Not a CJK font */ 889d522f475Smrg else /* a Korean font without CJK Ideographs */ 890d522f475Smrg fwstr = FULL_WIDTH_TEST_STRING2; 891d522f475Smrg } 892d522f475Smrg 893d522f475Smrg XftTextExtents32(dpy, font, &c1, 1, &gi1); 894d522f475Smrg XftTextExtents32(dpy, font, &c2, 1, &gi2); 895d522f475Smrg if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 896d522f475Smrg return False; 897d522f475Smrg 8980bd37d32Smrg XftTextExtentsUtf8(dpy, 8990bd37d32Smrg font, 9000bd37d32Smrg (_Xconst FcChar8 *) hwstr, 9010bd37d32Smrg (int) strlen(hwstr), 9020bd37d32Smrg &gi1); 9030bd37d32Smrg XftTextExtentsUtf8(dpy, 9040bd37d32Smrg font, 9050bd37d32Smrg (_Xconst FcChar8 *) fwstr, 9060bd37d32Smrg (int) strlen(fwstr), 9070bd37d32Smrg &gi2); 908d522f475Smrg 909d522f475Smrg /* 910d522f475Smrg * fontconfig and Xft prior to 2.2(?) set the width of half-width 911d522f475Smrg * characters identical to that of full-width character in CJK double-width 912d522f475Smrg * (bi-width / monospace) font even though the former is half as wide as 913d522f475Smrg * the latter. This was fixed sometime before the release of fontconfig 914d522f475Smrg * 2.2 in early 2003. See 915d522f475Smrg * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 916d522f475Smrg * In the meantime, we have to check both possibilities. 917d522f475Smrg */ 918d522f475Smrg return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 919d522f475Smrg} 920d522f475Smrg#else 921d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0 922d522f475Smrg#endif 923d522f475Smrg 924d522f475Smrg#define EmptyFont(fs) (fs != 0 \ 925d522f475Smrg && ((fs)->ascent + (fs)->descent == 0 \ 926d522f475Smrg || (fs)->max_bounds.width == 0)) 927d522f475Smrg 928d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 929d522f475Smrg * (fs)->max_bounds.width) 930d522f475Smrg 931d522f475Smrgconst VTFontNames * 93220d2c4d2SmrgxtermFontName(const char *normal) 933d522f475Smrg{ 934d522f475Smrg static VTFontNames data; 9359a64e1c5Smrg FREE_STRING(data.f_n); 936d522f475Smrg memset(&data, 0, sizeof(data)); 937dfb07bc7Smrg if (normal) 938dfb07bc7Smrg data.f_n = x_strdup(normal); 939dfb07bc7Smrg return &data; 940dfb07bc7Smrg} 941dfb07bc7Smrg 942dfb07bc7Smrgconst VTFontNames * 943dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw) 944dfb07bc7Smrg{ 945dfb07bc7Smrg static VTFontNames data; 946dfb07bc7Smrg memset(&data, 0, sizeof(data)); 947dfb07bc7Smrg data.f_n = DefaultFontN(xw); 948dfb07bc7Smrg data.f_b = DefaultFontB(xw); 949dfb07bc7Smrg#if OPT_WIDE_CHARS 950dfb07bc7Smrg data.f_w = DefaultFontW(xw); 951dfb07bc7Smrg data.f_wb = DefaultFontWB(xw); 952dfb07bc7Smrg#endif 953d522f475Smrg return &data; 954d522f475Smrg} 955d522f475Smrg 956d522f475Smrgstatic void 957fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 958d522f475Smrg{ 959d522f475Smrg if (name != 0) { 9609a64e1c5Smrg String last = screen->menu_font_names[fontnum][which]; 961d522f475Smrg if (last != 0) { 962d522f475Smrg if (strcmp(last, name)) { 9639a64e1c5Smrg FREE_STRING(last); 964d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 965d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 966d522f475Smrg } 967d522f475Smrg } else { 968d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 969d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 970d522f475Smrg } 971d522f475Smrg } 972d522f475Smrg} 973d522f475Smrg 974dfb07bc7Smrgstatic void 975d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name) 976dfb07bc7Smrg{ 977d4fba8b9Smrg static NameList *reported; 978d4fba8b9Smrg NameList *list; 979dfb07bc7Smrg 980dfb07bc7Smrg switch (xw->misc.fontWarnings) { 981dfb07bc7Smrg case fwNever: 982dfb07bc7Smrg return; 983dfb07bc7Smrg case fwResource: 984d4fba8b9Smrg if (is_derived_font_name(name)) 985d4fba8b9Smrg return; 986dfb07bc7Smrg break; 987dfb07bc7Smrg case fwAlways: 988dfb07bc7Smrg break; 989dfb07bc7Smrg } 990d4fba8b9Smrg for (list = reported; list != 0; list = list->next) { 991d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 992d4fba8b9Smrg return; 993d4fba8b9Smrg } 994d4fba8b9Smrg } 995d4fba8b9Smrg if ((list = TypeMalloc(NameList)) != 0) { 996d4fba8b9Smrg list->name = x_strdup(name); 997d4fba8b9Smrg list->next = reported; 998d4fba8b9Smrg reported = list; 999d4fba8b9Smrg } 1000d4fba8b9Smrg xtermWarning("cannot %s%s%s %sfont \"%s\"\n", 1001d4fba8b9Smrg who, *tag ? " " : "", tag, 1002d4fba8b9Smrg is_derived_font_name(name) ? "derived " : "", 1003d4fba8b9Smrg name); 1004dfb07bc7Smrg} 1005dfb07bc7Smrg 1006d4fba8b9Smrg#if OPT_RENDERFONT 1007d4fba8b9Smrgstatic void 1008d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name) 1009d4fba8b9Smrg{ 1010d4fba8b9Smrg switch (xw->misc.fontWarnings) { 1011d4fba8b9Smrg case fwNever: 1012d4fba8b9Smrg return; 1013d4fba8b9Smrg case fwResource: 1014d4fba8b9Smrg /* these combinations of wide/bold/italic are all "derived" */ 1015d4fba8b9Smrg return; 1016d4fba8b9Smrg case fwAlways: 1017d4fba8b9Smrg break; 1018d4fba8b9Smrg } 1019d4fba8b9Smrg xtermWarning("did not find a usable %s TrueType font\n", name); 1020d4fba8b9Smrg} 1021d4fba8b9Smrg#endif 1022d4fba8b9Smrg 10238f44fb3bSmrgXFontStruct * 10248f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name) 10258f44fb3bSmrg{ 10268f44fb3bSmrg XFontStruct *result = NULL; 10278f44fb3bSmrg size_t have = strlen(name); 10288f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 10298f44fb3bSmrg ; /* just ignore it */ 10308f44fb3bSmrg } else { 10318f44fb3bSmrg TScreen *screen = TScreenOf(xw); 10328f44fb3bSmrg result = XLoadQueryFont(screen->display, name); 10338f44fb3bSmrg } 10348f44fb3bSmrg return result; 10358f44fb3bSmrg} 10368f44fb3bSmrg 1037d522f475Smrg/* 1038d522f475Smrg * Open the given font and verify that it is non-empty. Return a null on 1039d522f475Smrg * failure. 1040d522f475Smrg */ 1041d522f475SmrgBool 1042956cc18dSsnjxtermOpenFont(XtermWidget xw, 1043956cc18dSsnj const char *name, 1044956cc18dSsnj XTermFonts * result, 1045956cc18dSsnj Bool force) 1046d522f475Smrg{ 1047d522f475Smrg Bool code = False; 1048d522f475Smrg 1049d4fba8b9Smrg TRACE(("xtermOpenFont %d:%d '%s'\n", 1050d4fba8b9Smrg result->warn, xw->misc.fontWarnings, NonNull(name))); 1051492d43a5Smrg if (!IsEmpty(name)) { 10528f44fb3bSmrg if ((result->fs = xtermLoadQueryFont(xw, name)) != 0) { 1053956cc18dSsnj code = True; 1054956cc18dSsnj if (EmptyFont(result->fs)) { 1055dfb07bc7Smrg xtermCloseFont(xw, result); 1056956cc18dSsnj code = False; 1057956cc18dSsnj } else { 1058956cc18dSsnj result->fn = x_strdup(name); 1059956cc18dSsnj } 106020d2c4d2Smrg } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 1061dfb07bc7Smrg if (result->warn <= xw->misc.fontWarnings 1062956cc18dSsnj#if OPT_RENDERFONT 1063956cc18dSsnj && !UsingRenderFont(xw) 1064956cc18dSsnj#endif 1065956cc18dSsnj ) { 1066dfb07bc7Smrg cannotFont(xw, "load", "", name); 1067956cc18dSsnj } else { 1068492d43a5Smrg TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 1069956cc18dSsnj } 1070956cc18dSsnj if (force) { 1071d4fba8b9Smrg NoFontWarning(result); 1072dfb07bc7Smrg code = xtermOpenFont(xw, DEFFONT, result, True); 1073956cc18dSsnj } 1074d522f475Smrg } 1075d522f475Smrg } 1076d4fba8b9Smrg NoFontWarning(result); 1077d522f475Smrg return code; 1078d522f475Smrg} 1079d522f475Smrg 1080d522f475Smrg/* 1081956cc18dSsnj * Close the font and free the font info. 1082d522f475Smrg */ 1083dfb07bc7Smrgvoid 1084d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt) 1085d522f475Smrg{ 1086d522f475Smrg if (fnt != 0 && fnt->fs != 0) { 1087d522f475Smrg TScreen *screen = TScreenOf(xw); 1088d522f475Smrg 1089d522f475Smrg clrCgsFonts(xw, WhichVWin(screen), fnt); 1090d522f475Smrg XFreeFont(screen->display, fnt->fs); 1091d522f475Smrg xtermFreeFontInfo(fnt); 1092d522f475Smrg } 1093d522f475Smrg} 1094d522f475Smrg 1095037a25ddSmrg/* 1096037a25ddSmrg * Close and free the font (as well as any aliases). 1097037a25ddSmrg */ 1098037a25ddSmrgstatic void 1099037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which) 1100037a25ddSmrg{ 1101037a25ddSmrg XFontStruct *thisFont = fnts[which].fs; 1102037a25ddSmrg 1103037a25ddSmrg if (thisFont != 0) { 1104037a25ddSmrg int k; 1105037a25ddSmrg 1106037a25ddSmrg xtermCloseFont(xw, &fnts[which]); 1107037a25ddSmrg for (k = 0; k < fMAX; ++k) { 1108037a25ddSmrg if (k != which) { 1109037a25ddSmrg if (thisFont == fnts[k].fs) { 1110037a25ddSmrg xtermFreeFontInfo(&fnts[k]); 1111037a25ddSmrg } 1112037a25ddSmrg } 1113037a25ddSmrg } 1114037a25ddSmrg } 1115037a25ddSmrg} 1116037a25ddSmrg 1117d522f475Smrg/* 1118d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer. 1119d522f475Smrg */ 1120d522f475Smrgvoid 1121d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 1122d522f475Smrg{ 1123037a25ddSmrg int j; 1124d522f475Smrg 1125d522f475Smrg for (j = 0; j < fMAX; ++j) { 1126037a25ddSmrg xtermCloseFont2(xw, fnts, j); 1127d522f475Smrg } 1128d522f475Smrg} 1129d522f475Smrg 1130d522f475Smrg/* 1131d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but 1132d522f475Smrg * ensuring that the names are reallocated to simplify freeing. 1133d522f475Smrg */ 1134d522f475Smrgvoid 1135d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 1136d522f475Smrg{ 1137d522f475Smrg xtermFreeFontInfo(target); 1138d522f475Smrg target->chrset = source->chrset; 1139d522f475Smrg target->flags = source->flags; 1140d522f475Smrg target->fn = x_strdup(source->fn); 1141d522f475Smrg target->fs = source->fs; 1142dfb07bc7Smrg target->warn = source->warn; 1143d522f475Smrg} 1144d522f475Smrg 1145d522f475Smrgvoid 1146d522f475SmrgxtermFreeFontInfo(XTermFonts * target) 1147d522f475Smrg{ 1148d522f475Smrg target->chrset = 0; 1149d522f475Smrg target->flags = 0; 1150d4fba8b9Smrg FreeAndNull(target->fn); 1151d522f475Smrg target->fs = 0; 1152d522f475Smrg} 1153d522f475Smrg 1154fa3f02f3Smrg#if OPT_REPORT_FONTS 1155fa3f02f3Smrgstatic void 1156fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs) 1157fa3f02f3Smrg{ 1158fa3f02f3Smrg printf("\t\t%s:\n", tag); 1159fa3f02f3Smrg printf("\t\t\tlbearing: %d\n", cs->lbearing); 1160fa3f02f3Smrg printf("\t\t\trbearing: %d\n", cs->rbearing); 1161fa3f02f3Smrg printf("\t\t\twidth: %d\n", cs->width); 1162fa3f02f3Smrg printf("\t\t\tascent: %d\n", cs->ascent); 1163fa3f02f3Smrg printf("\t\t\tdescent: %d\n", cs->descent); 1164fa3f02f3Smrg} 1165fa3f02f3Smrg 1166fa3f02f3Smrgstatic void 1167fa3f02f3SmrgreportOneVTFont(const char *tag, 1168fa3f02f3Smrg XTermFonts * fnt) 1169fa3f02f3Smrg{ 1170dfb07bc7Smrg if (!IsEmpty(fnt->fn) && fnt->fs != 0) { 1171fa3f02f3Smrg XFontStruct *fs = fnt->fs; 1172fa3f02f3Smrg unsigned first_char = 0; 1173fa3f02f3Smrg unsigned last_char = 0; 1174fa3f02f3Smrg 1175fa3f02f3Smrg if (fs->max_byte1 == 0) { 1176fa3f02f3Smrg first_char = fs->min_char_or_byte2; 1177fa3f02f3Smrg last_char = fs->max_char_or_byte2; 1178fa3f02f3Smrg } else { 1179fa3f02f3Smrg first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1180fa3f02f3Smrg last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1181fa3f02f3Smrg } 1182fa3f02f3Smrg 1183fa3f02f3Smrg printf("\t%s: %s\n", tag, NonNull(fnt->fn)); 1184fa3f02f3Smrg printf("\t\tall chars: %s\n", fs->all_chars_exist ? "yes" : "no"); 1185fa3f02f3Smrg printf("\t\tdefault char: %d\n", fs->default_char); 1186fa3f02f3Smrg printf("\t\tdirection: %d\n", fs->direction); 1187fa3f02f3Smrg printf("\t\tascent: %d\n", fs->ascent); 1188fa3f02f3Smrg printf("\t\tdescent: %d\n", fs->descent); 1189fa3f02f3Smrg printf("\t\tfirst char: %u\n", first_char); 1190fa3f02f3Smrg printf("\t\tlast char: %u\n", last_char); 1191fa3f02f3Smrg printf("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 11929a64e1c5Smrg if (FontLacksMetrics(fnt)) { 11939a64e1c5Smrg printf("\t\tmissing-chars: ?\n"); 11949a64e1c5Smrg printf("\t\tpresent-chars: ?\n"); 11959a64e1c5Smrg } else { 11969a64e1c5Smrg unsigned missing = 0; 1197037a25ddSmrg unsigned ch; 11989a64e1c5Smrg for (ch = first_char; ch <= last_char; ++ch) { 11999a64e1c5Smrg if (xtermMissingChar(ch, fnt)) { 12009a64e1c5Smrg ++missing; 12019a64e1c5Smrg } 12029a64e1c5Smrg } 12039a64e1c5Smrg printf("\t\tmissing-chars: %u\n", missing); 12049a64e1c5Smrg printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 12059a64e1c5Smrg } 1206fa3f02f3Smrg printf("\t\tmin_byte1: %d\n", fs->min_byte1); 1207fa3f02f3Smrg printf("\t\tmax_byte1: %d\n", fs->max_byte1); 1208fa3f02f3Smrg printf("\t\tproperties: %d\n", fs->n_properties); 1209fa3f02f3Smrg reportXCharStruct("min_bounds", &(fs->min_bounds)); 1210fa3f02f3Smrg reportXCharStruct("max_bounds", &(fs->max_bounds)); 1211fa3f02f3Smrg /* TODO: report fs->properties and fs->per_char */ 1212fa3f02f3Smrg } 1213fa3f02f3Smrg} 1214fa3f02f3Smrg 1215fa3f02f3Smrgstatic void 1216fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum) 1217fa3f02f3Smrg{ 1218fa3f02f3Smrg if (resource.reportFonts) { 1219fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 1220fa3f02f3Smrg 1221fa3f02f3Smrg if (fontnum) { 1222fa3f02f3Smrg printf("Loaded VTFonts(font%d)\n", fontnum); 1223fa3f02f3Smrg } else { 1224fa3f02f3Smrg printf("Loaded VTFonts(default)\n"); 1225fa3f02f3Smrg } 1226dfb07bc7Smrg 1227d4fba8b9Smrg reportOneVTFont("fNorm", GetNormalFont(screen, fNorm)); 1228d4fba8b9Smrg reportOneVTFont("fBold", GetNormalFont(screen, fBold)); 1229fa3f02f3Smrg#if OPT_WIDE_CHARS 1230d4fba8b9Smrg reportOneVTFont("fWide", GetNormalFont(screen, fWide)); 1231d4fba8b9Smrg reportOneVTFont("fWBold", GetNormalFont(screen, fWBold)); 1232fa3f02f3Smrg#endif 1233fa3f02f3Smrg } 1234fa3f02f3Smrg} 1235fa3f02f3Smrg#endif 1236fa3f02f3Smrg 12379a64e1c5Smrgvoid 1238d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc) 12399a64e1c5Smrg{ 12409a64e1c5Smrg TScreen *screen = TScreenOf(xw); 12419a64e1c5Smrg VTwin *win = WhichVWin(screen); 1242d4fba8b9Smrg Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground); 1243d4fba8b9Smrg Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background); 1244dfb07bc7Smrg 12459a64e1c5Smrg setCgsFore(xw, win, gcNorm, new_normal); 12469a64e1c5Smrg setCgsBack(xw, win, gcNorm, new_revers); 1247dfb07bc7Smrg setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm)); 12489a64e1c5Smrg 12499a64e1c5Smrg copyCgs(xw, win, gcBold, gcNorm); 1250d4fba8b9Smrg setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold); 12519a64e1c5Smrg 12529a64e1c5Smrg setCgsFore(xw, win, gcNormReverse, new_revers); 12539a64e1c5Smrg setCgsBack(xw, win, gcNormReverse, new_normal); 1254dfb07bc7Smrg setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm)); 12559a64e1c5Smrg 12569a64e1c5Smrg copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1257d4fba8b9Smrg setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold); 12589a64e1c5Smrg 12599a64e1c5Smrg if_OPT_WIDE_CHARS(screen, { 1260dfb07bc7Smrg XTermFonts *wide_xx = myfunc(screen, fWide); 1261dfb07bc7Smrg XTermFonts *bold_xx = myfunc(screen, fWBold); 1262dfb07bc7Smrg if (wide_xx->fs != 0 1263dfb07bc7Smrg && bold_xx->fs != 0) { 12649a64e1c5Smrg setCgsFore(xw, win, gcWide, new_normal); 12659a64e1c5Smrg setCgsBack(xw, win, gcWide, new_revers); 1266dfb07bc7Smrg setCgsFont(xw, win, gcWide, wide_xx); 12679a64e1c5Smrg 12689a64e1c5Smrg copyCgs(xw, win, gcWBold, gcWide); 1269dfb07bc7Smrg setCgsFont(xw, win, gcWBold, bold_xx); 12709a64e1c5Smrg 12719a64e1c5Smrg setCgsFore(xw, win, gcWideReverse, new_revers); 12729a64e1c5Smrg setCgsBack(xw, win, gcWideReverse, new_normal); 1273dfb07bc7Smrg setCgsFont(xw, win, gcWideReverse, wide_xx); 12749a64e1c5Smrg 12759a64e1c5Smrg copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1276dfb07bc7Smrg setCgsFont(xw, win, gcWBoldReverse, bold_xx); 12779a64e1c5Smrg } 12789a64e1c5Smrg }); 12799a64e1c5Smrg} 12809a64e1c5Smrg 1281d4fba8b9Smrg#if OPT_WIDE_ATTRS 1282d4fba8b9Smrgunsigned 1283d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs) 1284d4fba8b9Smrg{ 1285c48a5815Smrg TScreen *screen = TScreenOf(xw); 1286c48a5815Smrg 1287c48a5815Smrg if (UseItalicFont(screen)) { 1288c48a5815Smrg if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) { 1289c48a5815Smrg xtermLoadItalics(xw); 1290c48a5815Smrg xtermUpdateFontGCs(xw, getItalicFont); 1291c48a5815Smrg } else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) { 1292c48a5815Smrg xtermUpdateFontGCs(xw, getNormalFont); 1293c48a5815Smrg } 1294d4fba8b9Smrg } 1295d4fba8b9Smrg return new_attrs; 1296d4fba8b9Smrg} 1297d4fba8b9Smrg#endif 1298d4fba8b9Smrg 1299d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS 13009a64e1c5Smrgstatic void 13019a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp) 13029a64e1c5Smrg{ 13039a64e1c5Smrg if (fp->fs != 0) { 13049a64e1c5Smrg if (FontLacksMetrics(fp)) { 13059a64e1c5Smrg TRACE(("%s font lacks metrics\n", name)); 13069a64e1c5Smrg } else if (FontIsIncomplete(fp)) { 13079a64e1c5Smrg TRACE(("%s font is incomplete\n", name)); 13089a64e1c5Smrg } else { 13099a64e1c5Smrg TRACE(("%s font is complete\n", name)); 13109a64e1c5Smrg } 13119a64e1c5Smrg } else { 13129a64e1c5Smrg TRACE(("%s font is missing\n", name)); 13139a64e1c5Smrg } 13149a64e1c5Smrg} 13159a64e1c5Smrg#endif 13169a64e1c5Smrg 1317dfb07bc7Smrgstatic Bool 1318dfb07bc7SmrgloadNormFP(XtermWidget xw, 1319dfb07bc7Smrg char **nameOutP, 1320dfb07bc7Smrg XTermFonts * infoOut, 1321dfb07bc7Smrg int fontnum) 1322dfb07bc7Smrg{ 1323dfb07bc7Smrg Bool status = True; 1324dfb07bc7Smrg 1325dfb07bc7Smrg TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP))); 1326dfb07bc7Smrg 1327dfb07bc7Smrg if (!xtermOpenFont(xw, 1328dfb07bc7Smrg *nameOutP, 1329dfb07bc7Smrg infoOut, 1330dfb07bc7Smrg (fontnum == fontMenu_default))) { 1331dfb07bc7Smrg /* 1332dfb07bc7Smrg * If we are opening the default font, and it happens to be missing, 1333dfb07bc7Smrg * force that to the compiled-in default font, e.g., "fixed". If we 1334dfb07bc7Smrg * cannot open the font, disable it from the menu. 1335dfb07bc7Smrg */ 1336dfb07bc7Smrg if (fontnum != fontMenu_fontsel) { 1337dfb07bc7Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1338dfb07bc7Smrg } 1339dfb07bc7Smrg status = False; 1340dfb07bc7Smrg } 1341dfb07bc7Smrg return status; 1342dfb07bc7Smrg} 1343dfb07bc7Smrg 1344dfb07bc7Smrgstatic Bool 1345dfb07bc7SmrgloadBoldFP(XtermWidget xw, 1346dfb07bc7Smrg char **nameOutP, 1347dfb07bc7Smrg XTermFonts * infoOut, 1348dfb07bc7Smrg const char *nameRef, 1349dfb07bc7Smrg XTermFonts * infoRef, 1350dfb07bc7Smrg int fontnum) 1351dfb07bc7Smrg{ 1352dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1353dfb07bc7Smrg Bool status = True; 1354dfb07bc7Smrg 1355dfb07bc7Smrg TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP))); 1356dfb07bc7Smrg 1357dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1358dfb07bc7Smrg FontNameProperties *fp; 1359dfb07bc7Smrg char *normal = x_strdup(nameRef); 1360dfb07bc7Smrg 1361dfb07bc7Smrg fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1362dfb07bc7Smrg if (fp != 0) { 1363d4fba8b9Smrg NoFontWarning(infoOut); 1364dfb07bc7Smrg *nameOutP = bold_font_name(fp, fp->average_width); 1365dfb07bc7Smrg if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1366dfb07bc7Smrg free(*nameOutP); 1367dfb07bc7Smrg *nameOutP = bold_font_name(fp, -1); 1368dfb07bc7Smrg xtermOpenFont(xw, *nameOutP, infoOut, False); 1369dfb07bc7Smrg } 1370dfb07bc7Smrg TRACE(("...derived bold '%s'\n", NonNull(*nameOutP))); 1371dfb07bc7Smrg } 1372dfb07bc7Smrg if (fp == 0 || infoOut->fs == 0) { 1373dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1374dfb07bc7Smrg TRACE(("...cannot load a matching bold font\n")); 1375dfb07bc7Smrg } else if (comparable_metrics(infoRef->fs, infoOut->fs) 1376dfb07bc7Smrg && same_font_size(xw, infoRef->fs, infoOut->fs) 1377dfb07bc7Smrg && got_bold_font(screen->display, infoOut->fs, *nameOutP)) { 1378dfb07bc7Smrg TRACE(("...got a matching bold font\n")); 1379dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1380dfb07bc7Smrg } else { 1381dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1382dfb07bc7Smrg *infoOut = *infoRef; 1383dfb07bc7Smrg TRACE(("...did not get a matching bold font\n")); 1384dfb07bc7Smrg } 1385dfb07bc7Smrg free(normal); 1386dfb07bc7Smrg } else if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1387dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1388dfb07bc7Smrg TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP))); 1389dfb07bc7Smrg } else { 1390dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1391dfb07bc7Smrg } 1392dfb07bc7Smrg 1393dfb07bc7Smrg /* 1394dfb07bc7Smrg * Most of the time this call to load the font will succeed, even if 1395dfb07bc7Smrg * there is no wide font : the X server doubles the width of the 1396dfb07bc7Smrg * normal font, or similar. 1397dfb07bc7Smrg * 1398dfb07bc7Smrg * But if it did fail for some reason, then nevermind. 1399dfb07bc7Smrg */ 1400dfb07bc7Smrg if (EmptyFont(infoOut->fs)) 1401dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1402dfb07bc7Smrg 1403dfb07bc7Smrg if (!same_font_size(xw, infoRef->fs, infoOut->fs) 1404dfb07bc7Smrg && (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) { 1405dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold fonts\n")); 1406dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1407dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1408dfb07bc7Smrg } 1409dfb07bc7Smrg 1410dfb07bc7Smrg return status; 1411dfb07bc7Smrg} 1412dfb07bc7Smrg 1413dfb07bc7Smrg#if OPT_WIDE_CHARS 1414dfb07bc7Smrgstatic Bool 1415dfb07bc7SmrgloadWideFP(XtermWidget xw, 1416dfb07bc7Smrg char **nameOutP, 1417dfb07bc7Smrg XTermFonts * infoOut, 1418dfb07bc7Smrg const char *nameRef, 1419dfb07bc7Smrg XTermFonts * infoRef, 1420dfb07bc7Smrg int fontnum) 1421dfb07bc7Smrg{ 1422dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1423dfb07bc7Smrg Bool status = True; 1424dfb07bc7Smrg 1425dfb07bc7Smrg TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP))); 1426dfb07bc7Smrg 1427d4fba8b9Smrg if (!check_fontname(*nameOutP) 1428d4fba8b9Smrg && (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) { 1429dfb07bc7Smrg char *normal = x_strdup(nameRef); 1430d4fba8b9Smrg FontNameProperties *fp = get_font_name_props(screen->display, 1431d4fba8b9Smrg infoRef->fs, &normal); 1432dfb07bc7Smrg if (fp != 0) { 1433dfb07bc7Smrg *nameOutP = wide_font_name(fp); 1434d4fba8b9Smrg NoFontWarning(infoOut); 1435dfb07bc7Smrg } 1436dfb07bc7Smrg free(normal); 1437dfb07bc7Smrg } 1438dfb07bc7Smrg 1439dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1440d4fba8b9Smrg if (xtermOpenFont(xw, *nameOutP, infoOut, False) 1441d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1442d4fba8b9Smrg && EmptyFont(infoOut->fs)) { 1443d4fba8b9Smrg xtermCloseFont2(xw, infoOut - fWide, fWide); 1444d4fba8b9Smrg } 1445d4fba8b9Smrg if (infoOut->fs == 0) { 1446dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1447d4fba8b9Smrg } else { 1448d4fba8b9Smrg TRACE(("...%s wide %s\n", 1449d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1450d4fba8b9Smrg NonNull(*nameOutP))); 1451d4fba8b9Smrg cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1452dfb07bc7Smrg } 1453dfb07bc7Smrg } else { 1454dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1455dfb07bc7Smrg } 1456c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width 1457c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width 1458c48a5815Smrg xw->work.force_wideFont = False; 1459c48a5815Smrg if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) { 1460c48a5815Smrg TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs))); 1461c48a5815Smrg TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs))); 1462c48a5815Smrg TRACE(("...actual width %d\n", MaxWidthOf(infoOut->fs))); 1463c48a5815Smrg xw->work.force_wideFont = True; 1464c48a5815Smrg } 1465dfb07bc7Smrg return status; 1466dfb07bc7Smrg} 1467dfb07bc7Smrg 1468dfb07bc7Smrgstatic Bool 1469dfb07bc7SmrgloadWBoldFP(XtermWidget xw, 1470dfb07bc7Smrg char **nameOutP, 1471dfb07bc7Smrg XTermFonts * infoOut, 1472dfb07bc7Smrg const char *wideNameRef, XTermFonts * wideInfoRef, 1473dfb07bc7Smrg const char *boldNameRef, XTermFonts * boldInfoRef, 1474dfb07bc7Smrg int fontnum) 1475dfb07bc7Smrg{ 1476dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1477dfb07bc7Smrg Bool status = True; 1478dfb07bc7Smrg char *bold = NULL; 1479dfb07bc7Smrg 1480dfb07bc7Smrg TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP))); 1481dfb07bc7Smrg 1482dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1483dfb07bc7Smrg FontNameProperties *fp; 1484dfb07bc7Smrg fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold); 1485dfb07bc7Smrg if (fp != 0) { 1486dfb07bc7Smrg *nameOutP = widebold_font_name(fp); 1487d4fba8b9Smrg NoFontWarning(infoOut); 1488dfb07bc7Smrg } 1489dfb07bc7Smrg } 1490dfb07bc7Smrg 1491dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1492dfb07bc7Smrg 1493dfb07bc7Smrg if (xtermOpenFont(xw, *nameOutP, infoOut, False) 1494d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1495dfb07bc7Smrg && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) { 1496dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1497dfb07bc7Smrg } 1498dfb07bc7Smrg 1499dfb07bc7Smrg if (infoOut->fs == 0) { 1500d4fba8b9Smrg if (is_derived_font_name(*nameOutP)) 1501dfb07bc7Smrg free(*nameOutP); 1502dfb07bc7Smrg if (IsEmpty(wideNameRef)) { 1503dfb07bc7Smrg *nameOutP = x_strdup(boldNameRef); 1504dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1505dfb07bc7Smrg TRACE(("...cannot load wide-bold, use bold %s\n", 1506dfb07bc7Smrg NonNull(boldNameRef))); 1507dfb07bc7Smrg } else { 1508dfb07bc7Smrg *nameOutP = x_strdup(wideNameRef); 1509dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1510dfb07bc7Smrg TRACE(("...cannot load wide-bold, use wide %s\n", 1511dfb07bc7Smrg NonNull(wideNameRef))); 1512dfb07bc7Smrg } 1513dfb07bc7Smrg } else { 1514dfb07bc7Smrg TRACE(("...%s wide/bold %s\n", 1515d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1516dfb07bc7Smrg NonNull(*nameOutP))); 1517dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fWBold, *nameOutP); 1518dfb07bc7Smrg } 1519dfb07bc7Smrg } else if (is_double_width_font(boldInfoRef->fs)) { 1520dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1521dfb07bc7Smrg TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef))); 1522dfb07bc7Smrg } else { 1523dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1524dfb07bc7Smrg TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef))); 1525dfb07bc7Smrg } 1526dfb07bc7Smrg 1527dfb07bc7Smrg free(bold); 1528dfb07bc7Smrg 1529dfb07bc7Smrg if (EmptyFont(infoOut->fs)) { 1530dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1531dfb07bc7Smrg } else { 1532dfb07bc7Smrg if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs) 1533dfb07bc7Smrg || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs) 1534dfb07bc7Smrg && is_fixed_font(wideInfoRef->fs) 1535dfb07bc7Smrg && is_fixed_font(infoOut->fs)))) { 1536dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1537dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1538dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1539dfb07bc7Smrg } 1540dfb07bc7Smrg } 1541dfb07bc7Smrg 1542dfb07bc7Smrg return status; 1543dfb07bc7Smrg} 1544dfb07bc7Smrg#endif 1545dfb07bc7Smrg 1546d522f475Smrgint 1547d522f475SmrgxtermLoadFont(XtermWidget xw, 1548d522f475Smrg const VTFontNames * fonts, 1549d522f475Smrg Bool doresize, 1550d522f475Smrg int fontnum) 1551d522f475Smrg{ 1552956cc18dSsnj TScreen *screen = TScreenOf(xw); 1553d522f475Smrg VTwin *win = WhichVWin(screen); 1554d522f475Smrg 1555d522f475Smrg VTFontNames myfonts; 1556d522f475Smrg XTermFonts fnts[fMAX]; 1557d522f475Smrg char *tmpname = NULL; 1558956cc18dSsnj Boolean proportional = False; 1559d522f475Smrg 1560d522f475Smrg memset(&myfonts, 0, sizeof(myfonts)); 1561d522f475Smrg memset(fnts, 0, sizeof(fnts)); 1562d522f475Smrg 1563d522f475Smrg if (fonts != 0) 1564d522f475Smrg myfonts = *fonts; 1565956cc18dSsnj if (!check_fontname(myfonts.f_n)) 1566d522f475Smrg return 0; 1567d522f475Smrg 1568d522f475Smrg if (fontnum == fontMenu_fontescape 1569d522f475Smrg && myfonts.f_n != screen->MenuFontName(fontnum)) { 1570d522f475Smrg if ((tmpname = x_strdup(myfonts.f_n)) == 0) 1571d522f475Smrg return 0; 1572d522f475Smrg } 1573d522f475Smrg 1574d522f475Smrg TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n)); 1575d522f475Smrg releaseWindowGCs(xw, win); 1576d522f475Smrg 1577956cc18dSsnj#define DbgResource(name, field, index) \ 1578956cc18dSsnj TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1579956cc18dSsnj fontnum, \ 1580dfb07bc7Smrg (fnts[index].warn == fwResource) ? "*" : " ", \ 1581492d43a5Smrg NonNull(myfonts.field))) 1582956cc18dSsnj DbgResource("normal", f_n, fNorm); 1583956cc18dSsnj DbgResource("bold ", f_b, fBold); 1584d522f475Smrg#if OPT_WIDE_CHARS 1585956cc18dSsnj DbgResource("wide ", f_w, fWide); 1586956cc18dSsnj DbgResource("w/bold", f_wb, fWBold); 1587d522f475Smrg#endif 1588d522f475Smrg 1589dfb07bc7Smrg if (!loadNormFP(xw, 1590dfb07bc7Smrg &myfonts.f_n, 1591dfb07bc7Smrg &fnts[fNorm], 1592dfb07bc7Smrg fontnum)) 1593d522f475Smrg goto bad; 1594d522f475Smrg 1595dfb07bc7Smrg if (!loadBoldFP(xw, 1596dfb07bc7Smrg &myfonts.f_b, 1597dfb07bc7Smrg &fnts[fBold], 1598dfb07bc7Smrg myfonts.f_n, 1599dfb07bc7Smrg &fnts[fNorm], 1600dfb07bc7Smrg fontnum)) 1601dfb07bc7Smrg goto bad; 1602d522f475Smrg 1603d522f475Smrg /* 1604d522f475Smrg * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1605d522f475Smrg * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1606d522f475Smrg * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1607d522f475Smrg */ 1608d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1609d522f475Smrg 1610dfb07bc7Smrg if (!loadWideFP(xw, 1611dfb07bc7Smrg &myfonts.f_w, 1612dfb07bc7Smrg &fnts[fWide], 1613dfb07bc7Smrg myfonts.f_n, 1614dfb07bc7Smrg &fnts[fNorm], 1615dfb07bc7Smrg fontnum)) 1616dfb07bc7Smrg goto bad; 1617dfb07bc7Smrg 1618dfb07bc7Smrg if (!loadWBoldFP(xw, 1619dfb07bc7Smrg &myfonts.f_wb, 1620dfb07bc7Smrg &fnts[fWBold], 1621dfb07bc7Smrg myfonts.f_w, 1622dfb07bc7Smrg &fnts[fWide], 1623dfb07bc7Smrg myfonts.f_b, 1624dfb07bc7Smrg &fnts[fBold], 1625dfb07bc7Smrg fontnum)) 1626dfb07bc7Smrg goto bad; 1627d522f475Smrg 1628d522f475Smrg }); 1629d522f475Smrg 1630d522f475Smrg /* 1631d522f475Smrg * Normal/bold fonts should be the same width. Also, the min/max 1632d522f475Smrg * values should be the same. 1633d522f475Smrg */ 1634d4fba8b9Smrg if (fnts[fNorm].fs != 0 1635d4fba8b9Smrg && fnts[fBold].fs != 0 1636d4fba8b9Smrg && (!is_fixed_font(fnts[fNorm].fs) 1637d4fba8b9Smrg || !is_fixed_font(fnts[fBold].fs) 1638d4fba8b9Smrg || differing_widths(fnts[fNorm].fs, fnts[fBold].fs))) { 1639d522f475Smrg TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1640d522f475Smrg fnts[fNorm].fs->min_bounds.width, 1641d522f475Smrg fnts[fNorm].fs->max_bounds.width, 1642d522f475Smrg fnts[fBold].fs->min_bounds.width, 1643d522f475Smrg fnts[fBold].fs->max_bounds.width)); 1644d522f475Smrg proportional = True; 1645d522f475Smrg } 1646d522f475Smrg 1647d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1648d522f475Smrg if (fnts[fWide].fs != 0 1649d522f475Smrg && fnts[fWBold].fs != 0 1650d522f475Smrg && (!is_fixed_font(fnts[fWide].fs) 1651d522f475Smrg || !is_fixed_font(fnts[fWBold].fs) 1652d4fba8b9Smrg || differing_widths(fnts[fWide].fs, fnts[fWBold].fs))) { 1653d522f475Smrg TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1654d522f475Smrg fnts[fWide].fs->min_bounds.width, 1655d522f475Smrg fnts[fWide].fs->max_bounds.width, 1656d522f475Smrg fnts[fWBold].fs->min_bounds.width, 1657d522f475Smrg fnts[fWBold].fs->max_bounds.width)); 1658d522f475Smrg proportional = True; 1659d522f475Smrg } 1660d522f475Smrg }); 1661d522f475Smrg 1662d522f475Smrg /* TODO : enforce that the width of the wide font is 2* the width 1663d522f475Smrg of the narrow font */ 1664d522f475Smrg 1665d522f475Smrg /* 1666d522f475Smrg * If we're switching fonts, free the old ones. Otherwise we'll leak 1667d522f475Smrg * the memory that is associated with the old fonts. The 1668d522f475Smrg * XLoadQueryFont call allocates a new XFontStruct. 1669d522f475Smrg */ 1670d522f475Smrg xtermCloseFonts(xw, screen->fnts); 16719a64e1c5Smrg#if OPT_WIDE_ATTRS 16729a64e1c5Smrg xtermCloseFonts(xw, screen->ifnts); 16739a64e1c5Smrg screen->ifnts_ok = False; 16749a64e1c5Smrg#endif 1675d522f475Smrg 1676d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fNorm), &fnts[fNorm]); 1677d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fBold), &fnts[fBold]); 1678d522f475Smrg#if OPT_WIDE_CHARS 1679d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]); 1680d522f475Smrg if (fnts[fWBold].fs == NULL) 1681d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]); 1682d4fba8b9Smrg xtermCopyFontInfo(GetNormalFont(screen, fWBold), &fnts[fWBold]); 1683d522f475Smrg#endif 1684d522f475Smrg 1685d4fba8b9Smrg xtermUpdateFontGCs(xw, getNormalFont); 1686d522f475Smrg 168720d2c4d2Smrg#if OPT_BOX_CHARS 168820d2c4d2Smrg screen->allow_packing = proportional; 168920d2c4d2Smrg setupPackedFonts(xw); 169020d2c4d2Smrg#endif 169120d2c4d2Smrg screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1692d4fba8b9Smrg screen->fnt_boxes = 1; 1693d522f475Smrg 1694d522f475Smrg#if OPT_BOX_CHARS 1695d522f475Smrg /* 16969a64e1c5Smrg * xterm uses character positions 1-31 of a font for the line-drawing 1697d522f475Smrg * characters. Check that they are all present. The null character 1698d522f475Smrg * (0) is special, and is not used. 1699d522f475Smrg */ 1700d522f475Smrg#if OPT_RENDERFONT 1701d522f475Smrg if (UsingRenderFont(xw)) { 1702d522f475Smrg /* 1703d522f475Smrg * FIXME: we shouldn't even be here if we're using Xft. 1704d522f475Smrg */ 1705d4fba8b9Smrg screen->fnt_boxes = 0; 1706d522f475Smrg TRACE(("assume Xft missing line-drawing chars\n")); 1707d522f475Smrg } else 1708d522f475Smrg#endif 1709d522f475Smrg { 1710d522f475Smrg unsigned ch; 1711d522f475Smrg 17129a64e1c5Smrg#if OPT_TRACE 17139a64e1c5Smrg#define TRACE_MISS(index) show_font_misses(#index, &fnts[index]) 17149a64e1c5Smrg TRACE_MISS(fNorm); 17159a64e1c5Smrg TRACE_MISS(fBold); 17169a64e1c5Smrg#if OPT_WIDE_CHARS 17179a64e1c5Smrg TRACE_MISS(fWide); 17189a64e1c5Smrg TRACE_MISS(fWBold); 17199a64e1c5Smrg#endif 17209a64e1c5Smrg#endif 1721fa3f02f3Smrg 1722d522f475Smrg#if OPT_WIDE_CHARS 1723d4fba8b9Smrg if (screen->utf8_mode || screen->unicode_font) { 1724d4fba8b9Smrg UIntSet(screen->fnt_boxes, 2); 1725d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1726d4fba8b9Smrg unsigned n = dec2ucs(screen, ch); 1727d4fba8b9Smrg if ((n != UCS_REPL) 1728d4fba8b9Smrg && (n != ch) 1729d4fba8b9Smrg && (screen->fnt_boxes & 2)) { 1730d4fba8b9Smrg if (xtermMissingChar(n, &fnts[fNorm]) || 1731d4fba8b9Smrg xtermMissingChar(n, &fnts[fBold])) { 1732d4fba8b9Smrg UIntClr(screen->fnt_boxes, 2); 1733d4fba8b9Smrg TRACE(("missing graphics character #%d, U+%04X\n", 1734d4fba8b9Smrg ch, n)); 1735d4fba8b9Smrg break; 1736d4fba8b9Smrg } 1737d4fba8b9Smrg } 1738d522f475Smrg } 1739d4fba8b9Smrg } 1740d522f475Smrg#endif 1741d4fba8b9Smrg 1742d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1743d4fba8b9Smrg if (xtermMissingChar(ch, &fnts[fNorm])) { 1744d4fba8b9Smrg TRACE(("missing normal char #%d\n", ch)); 1745d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1746d522f475Smrg break; 1747d522f475Smrg } 1748d4fba8b9Smrg if (xtermMissingChar(ch, &fnts[fBold])) { 1749d4fba8b9Smrg TRACE(("missing bold char #%d\n", ch)); 1750d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1751d522f475Smrg break; 1752d522f475Smrg } 1753d522f475Smrg } 1754d4fba8b9Smrg 1755d4fba8b9Smrg TRACE(("Will %suse internal line-drawing characters (mode %d)\n", 1756d4fba8b9Smrg screen->fnt_boxes ? "not " : "", 1757d4fba8b9Smrg screen->fnt_boxes)); 1758d522f475Smrg } 1759d522f475Smrg#endif 1760d522f475Smrg 1761d522f475Smrg if (screen->always_bold_mode) { 1762d522f475Smrg screen->enbolden = screen->bold_mode; 1763d522f475Smrg } else { 1764d522f475Smrg screen->enbolden = screen->bold_mode 1765d522f475Smrg && ((fnts[fNorm].fs == fnts[fBold].fs) 1766dfb07bc7Smrg || same_font_name(myfonts.f_n, myfonts.f_b)); 1767d522f475Smrg } 1768d522f475Smrg TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1769d522f475Smrg screen->enbolden ? "" : "not ")); 1770d522f475Smrg 1771d522f475Smrg set_menu_font(False); 1772d522f475Smrg screen->menu_font_number = fontnum; 1773d522f475Smrg set_menu_font(True); 1774d522f475Smrg if (tmpname) { /* if setting escape or sel */ 1775d522f475Smrg if (screen->MenuFontName(fontnum)) 17769a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontnum)); 1777d522f475Smrg screen->MenuFontName(fontnum) = tmpname; 1778d522f475Smrg if (fontnum == fontMenu_fontescape) { 177994644356Smrg update_font_escape(); 1780d522f475Smrg } 1781d522f475Smrg#if OPT_SHIFT_FONTS 1782d522f475Smrg screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs); 1783d522f475Smrg#endif 1784d522f475Smrg } 1785d522f475Smrg set_cursor_gcs(xw); 1786d522f475Smrg xtermUpdateFontInfo(xw, doresize); 1787d522f475Smrg TRACE(("Success Cgs - xtermLoadFont\n")); 1788fa3f02f3Smrg#if OPT_REPORT_FONTS 1789fa3f02f3Smrg reportVTFontInfo(xw, fontnum); 17909a64e1c5Smrg#endif 17919a64e1c5Smrg FREE_FNAME(f_n); 17929a64e1c5Smrg FREE_FNAME(f_b); 17939a64e1c5Smrg#if OPT_WIDE_CHARS 17949a64e1c5Smrg FREE_FNAME(f_w); 17959a64e1c5Smrg FREE_FNAME(f_wb); 17969a64e1c5Smrg#endif 17979a64e1c5Smrg if (fnts[fNorm].fn == fnts[fBold].fn) { 17989a64e1c5Smrg free(fnts[fNorm].fn); 17999a64e1c5Smrg } else { 18009a64e1c5Smrg free(fnts[fNorm].fn); 18019a64e1c5Smrg free(fnts[fBold].fn); 18029a64e1c5Smrg } 18039a64e1c5Smrg#if OPT_WIDE_CHARS 18049a64e1c5Smrg free(fnts[fWide].fn); 18059a64e1c5Smrg free(fnts[fWBold].fn); 1806fa3f02f3Smrg#endif 1807dfb07bc7Smrg xtermSetWinSize(xw); 1808d522f475Smrg return 1; 1809d522f475Smrg 1810d522f475Smrg bad: 1811d4fba8b9Smrg free(tmpname); 18120bd37d32Smrg 18130bd37d32Smrg#if OPT_RENDERFONT 181494644356Smrg if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) { 18159a64e1c5Smrg int old_fontnum = screen->menu_font_number; 18169a64e1c5Smrg#if OPT_TOOLBAR 18179a64e1c5Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, True); 18189a64e1c5Smrg#endif 18199a64e1c5Smrg Bell(xw, XkbBI_MinorError, 0); 18209a64e1c5Smrg myfonts.f_n = screen->MenuFontName(old_fontnum); 18219a64e1c5Smrg return xtermLoadFont(xw, &myfonts, doresize, old_fontnum); 18229a64e1c5Smrg } else if (x_strcasecmp(myfonts.f_n, DEFFONT)) { 18230bd37d32Smrg int code; 18240bd37d32Smrg 1825dfb07bc7Smrg myfonts.f_n = x_strdup(DEFFONT); 18260bd37d32Smrg TRACE(("...recovering for TrueType fonts\n")); 18270bd37d32Smrg code = xtermLoadFont(xw, &myfonts, doresize, fontnum); 18280bd37d32Smrg if (code) { 182994644356Smrg if (fontnum != fontMenu_fontsel) { 183094644356Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, 183194644356Smrg UsingRenderFont(xw)); 183294644356Smrg } 18330bd37d32Smrg TRACE(("...recovered size %dx%d\n", 18340bd37d32Smrg FontHeight(screen), 18350bd37d32Smrg FontWidth(screen))); 18360bd37d32Smrg } 18370bd37d32Smrg return code; 18380bd37d32Smrg } 18390bd37d32Smrg#endif 18400bd37d32Smrg 1841d522f475Smrg releaseWindowGCs(xw, win); 1842d522f475Smrg 1843d522f475Smrg xtermCloseFonts(xw, fnts); 1844d522f475Smrg TRACE(("Fail Cgs - xtermLoadFont\n")); 1845d522f475Smrg return 0; 1846d522f475Smrg} 1847d522f475Smrg 18489a64e1c5Smrg#if OPT_WIDE_ATTRS 18499a64e1c5Smrg/* 18509a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts. 18519a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font. 18529a64e1c5Smrg */ 18539a64e1c5Smrgvoid 18549a64e1c5SmrgxtermLoadItalics(XtermWidget xw) 18559a64e1c5Smrg{ 18569a64e1c5Smrg TScreen *screen = TScreenOf(xw); 18579a64e1c5Smrg 1858c48a5815Smrg if (UseItalicFont(screen) && !screen->ifnts_ok) { 1859037a25ddSmrg int n; 1860dfb07bc7Smrg FontNameProperties *fp; 1861dfb07bc7Smrg XTermFonts *data; 1862037a25ddSmrg 18639a64e1c5Smrg screen->ifnts_ok = True; 18649a64e1c5Smrg for (n = 0; n < fMAX; ++n) { 1865dfb07bc7Smrg switch (n) { 1866dfb07bc7Smrg case fNorm: 1867dfb07bc7Smrg /* FALLTHRU */ 1868dfb07bc7Smrg case fBold: 1869dfb07bc7Smrg /* FALLTHRU */ 1870dfb07bc7Smrg#if OPT_WIDE_CHARS 1871dfb07bc7Smrg case fWide: 1872dfb07bc7Smrg /* FALLTHRU */ 1873dfb07bc7Smrg case fWBold: 1874dfb07bc7Smrg#endif 1875dfb07bc7Smrg /* FALLTHRU */ 1876dfb07bc7Smrg data = getItalicFont(screen, n); 1877037a25ddSmrg 1878dfb07bc7Smrg /* 1879dfb07bc7Smrg * FIXME - need to handle font-leaks 1880dfb07bc7Smrg */ 1881dfb07bc7Smrg data->fs = 0; 1882dfb07bc7Smrg if (getNormalFont(screen, n)->fs != 0 && 1883dfb07bc7Smrg (fp = get_font_name_props(screen->display, 1884dfb07bc7Smrg getNormalFont(screen, n)->fs, 1885dfb07bc7Smrg 0)) != 0) { 1886dfb07bc7Smrg if (!open_italic_font(xw, n, fp, data)) { 1887dfb07bc7Smrg if (n > 0) { 1888dfb07bc7Smrg xtermCopyFontInfo(data, 1889dfb07bc7Smrg getItalicFont(screen, n - 1)); 1890dfb07bc7Smrg } else { 1891dfb07bc7Smrg xtermOpenFont(xw, 1892dfb07bc7Smrg getNormalFont(screen, n)->fn, 1893dfb07bc7Smrg data, False); 18949a64e1c5Smrg } 18959a64e1c5Smrg } 18969a64e1c5Smrg } 1897dfb07bc7Smrg break; 18989a64e1c5Smrg } 18999a64e1c5Smrg } 19009a64e1c5Smrg } 19019a64e1c5Smrg} 19029a64e1c5Smrg#endif 19039a64e1c5Smrg 1904d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1905d522f475Smrg/* 1906d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action. 1907d522f475Smrg */ 1908dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \ 1909492d43a5Smrg if (IsEmpty(dst.name)) { \ 1910dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \ 19119a64e1c5Smrg dst.name = x_strdup(src.name); \ 1912d522f475Smrg } else { \ 1913dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1914dfb07bc7Smrg } 1915dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \ 1916dfb07bc7Smrg if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \ 1917dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \ 1918dfb07bc7Smrg } else { \ 1919dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \ 1920d522f475Smrg } 1921d522f475Smrg 1922dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \ 1923e39b573cSmrg if (IsEmpty(dst.name)) { \ 1924e39b573cSmrg TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1925e39b573cSmrg dst.name = x_strdup(""); \ 1926e39b573cSmrg } else { \ 1927dfb07bc7Smrg TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1928e39b573cSmrg } 1929e39b573cSmrg 19309a64e1c5Smrg#define FREE_MENU_FONTS(dst) \ 19319a64e1c5Smrg TRACE(("FREE_MENU_FONTS " #dst "\n")); \ 19329a64e1c5Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 19339a64e1c5Smrg for (m = 0; m < fMAX; ++m) { \ 19349a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 19359a64e1c5Smrg dst.menu_font_names[n][m] = 0; \ 19369a64e1c5Smrg } \ 19379a64e1c5Smrg } 19389a64e1c5Smrg 1939dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \ 1940d522f475Smrg TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1941d522f475Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1942d522f475Smrg for (m = 0; m < fMAX; ++m) { \ 19439a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 1944492d43a5Smrg dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1945d522f475Smrg } \ 194694644356Smrg TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \ 1947e39b573cSmrg } 1948e39b573cSmrg 19499a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \ 1950dfb07bc7Smrg TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \ 19519a64e1c5Smrg xtermCopyVTFontNames(&target.default_font, &source.default_font) 19529a64e1c5Smrg 1953dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \ 1954dfb07bc7Smrg TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \ 1955dfb07bc7Smrg xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11) 1956dfb07bc7Smrg 1957dfb07bc7Smrgstatic void 1958dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source) 1959dfb07bc7Smrg{ 1960dfb07bc7Smrg#define COPY_IT(name,field) \ 1961dfb07bc7Smrg TRACE((".. "#name" = %s\n", NonNull(source->field))); \ 1962dfb07bc7Smrg free(target->field); \ 1963dfb07bc7Smrg target->field = x_strdup(source->field) 1964dfb07bc7Smrg 1965dfb07bc7Smrg TRACE(("xtermCopyVTFontNames\n")); 1966dfb07bc7Smrg 1967dfb07bc7Smrg COPY_IT(font, f_n); 1968dfb07bc7Smrg COPY_IT(boldFont, f_b); 1969dfb07bc7Smrg 1970dfb07bc7Smrg#if OPT_WIDE_CHARS 1971dfb07bc7Smrg COPY_IT(wideFont, f_w); 1972dfb07bc7Smrg COPY_IT(wideBoldFont, f_wb); 1973dfb07bc7Smrg#endif 1974dfb07bc7Smrg#undef COPY_IT 1975dfb07bc7Smrg} 1976dfb07bc7Smrg 19779a64e1c5Smrgstatic void 1978dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source) 19799a64e1c5Smrg{ 1980dfb07bc7Smrg#define COPY_IT(name,field) \ 1981dfb07bc7Smrg copyFontList(&(target->field), source->field); \ 1982dfb07bc7Smrg TRACE_ARGV(".. " #name, source->field) 1983dfb07bc7Smrg 1984dfb07bc7Smrg (void) xw; 1985dfb07bc7Smrg TRACE(("xtermCopyFontLists %s ->%s\n", 1986dfb07bc7Smrg whichFontList(xw, source), 1987dfb07bc7Smrg whichFontList(xw, target))); 1988dfb07bc7Smrg 1989dfb07bc7Smrg COPY_IT(font, list_n); 1990dfb07bc7Smrg COPY_IT(fontBold, list_b); 1991dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 1992dfb07bc7Smrg COPY_IT(fontItal, list_i); 1993d4fba8b9Smrg COPY_IT(fontBtal, list_bi); 1994dfb07bc7Smrg#endif 19959a64e1c5Smrg#if OPT_WIDE_CHARS 1996dfb07bc7Smrg COPY_IT(wideFont, list_w); 1997dfb07bc7Smrg COPY_IT(wideBoldFont, list_wb); 1998dfb07bc7Smrg COPY_IT(wideItalFont, list_wi); 1999d4fba8b9Smrg COPY_IT(wideBtalFont, list_wbi); 20009a64e1c5Smrg#endif 2001dfb07bc7Smrg#undef COPY_IT 20029a64e1c5Smrg} 20039a64e1c5Smrg 2004e39b573cSmrgvoid 2005e39b573cSmrgxtermSaveVTFonts(XtermWidget xw) 2006e39b573cSmrg{ 2007e39b573cSmrg TScreen *screen = TScreenOf(xw); 2008e39b573cSmrg Cardinal n, m; 2009e39b573cSmrg 2010e39b573cSmrg if (!screen->savedVTFonts) { 2011e39b573cSmrg 2012e39b573cSmrg screen->savedVTFonts = True; 2013e39b573cSmrg TRACE(("xtermSaveVTFonts saving original\n")); 20149a64e1c5Smrg COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc); 2015dfb07bc7Smrg COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work); 2016dfb07bc7Smrg COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 2017e39b573cSmrg } 2018e39b573cSmrg} 2019e39b573cSmrg 2020e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 2021e39b573cSmrg#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 2022e39b573cSmrg 2023e39b573cSmrgstatic Boolean 2024e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b) 2025e39b573cSmrg{ 2026e39b573cSmrg Boolean result = True; 2027e39b573cSmrg 2028e39b573cSmrg if (!SAME_MEMBER(default_font.f_n) 2029e39b573cSmrg || !SAME_MEMBER(default_font.f_b) 20300bd37d32Smrg#if OPT_WIDE_CHARS 2031e39b573cSmrg || !SAME_MEMBER(default_font.f_w) 20320bd37d32Smrg || !SAME_MEMBER(default_font.f_wb) 20330bd37d32Smrg#endif 20340bd37d32Smrg ) { 2035e39b573cSmrg TRACE(("sameSubResources: default_font differs\n")); 2036e39b573cSmrg result = False; 2037e39b573cSmrg } else { 2038037a25ddSmrg int n; 2039037a25ddSmrg 2040e39b573cSmrg for (n = 0; n < NMENUFONTS; ++n) { 2041e39b573cSmrg if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 2042e39b573cSmrg TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 2043e39b573cSmrg result = False; 2044e39b573cSmrg break; 2045e39b573cSmrg } 2046d522f475Smrg } 2047e39b573cSmrg } 2048e39b573cSmrg 2049e39b573cSmrg return result; 2050e39b573cSmrg} 2051d522f475Smrg 2052d522f475Smrg/* 2053d522f475Smrg * Load the "VT" font names from the given subresource name/class. These 2054d522f475Smrg * correspond to the VT100 resources. 2055d522f475Smrg */ 2056d522f475Smrgstatic Bool 205720d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 2058d522f475Smrg{ 2059e39b573cSmrg SubResourceRec subresourceRec; 2060e39b573cSmrg SubResourceRec referenceRec; 2061d522f475Smrg 2062d522f475Smrg /* 2063d522f475Smrg * These are duplicates of the VT100 font resources, but with a special 2064d522f475Smrg * application/classname passed in to distinguish them. 2065d522f475Smrg */ 2066d522f475Smrg static XtResource font_resources[] = 2067d522f475Smrg { 2068d522f475Smrg Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 2069d522f475Smrg Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 2070d522f475Smrg#if OPT_WIDE_CHARS 2071d522f475Smrg Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 2072d522f475Smrg Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 2073d522f475Smrg#endif 2074d522f475Smrg Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 2075d522f475Smrg Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 2076d522f475Smrg Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 2077d522f475Smrg Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 2078d522f475Smrg Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 2079d522f475Smrg Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 2080d4fba8b9Smrg Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL), 2081d522f475Smrg }; 2082d522f475Smrg Cardinal n, m; 2083d522f475Smrg Bool status = True; 2084956cc18dSsnj TScreen *screen = TScreenOf(xw); 2085d522f475Smrg 2086e39b573cSmrg TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 2087e39b573cSmrg NonNull(myName), NonNull(myClass))); 2088d522f475Smrg 2089e39b573cSmrg xtermSaveVTFonts(xw); 2090d522f475Smrg 2091492d43a5Smrg if (IsEmpty(myName)) { 2092d522f475Smrg TRACE(("xtermLoadVTFonts restoring original\n")); 20939a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts); 2094dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts); 20959a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2096dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 2097d522f475Smrg } else { 2098d522f475Smrg TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 2099d522f475Smrg 2100e39b573cSmrg memset(&referenceRec, 0, sizeof(referenceRec)); 2101d522f475Smrg memset(&subresourceRec, 0, sizeof(subresourceRec)); 2102956cc18dSsnj XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 2103d522f475Smrg myName, myClass, 2104d522f475Smrg font_resources, 2105d522f475Smrg (Cardinal) XtNumber(font_resources), 2106d522f475Smrg NULL, (Cardinal) 0); 2107d522f475Smrg 2108e39b573cSmrg /* 2109e39b573cSmrg * XtGetSubresources returns no status, so we compare the returned 2110e39b573cSmrg * data against a zero'd struct to see if any data is returned. 2111e39b573cSmrg */ 2112e39b573cSmrg if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 2113e39b573cSmrg && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 2114e39b573cSmrg 2115e39b573cSmrg screen->mergedVTFonts = True; 2116d522f475Smrg 21179a64e1c5Smrg /* 21189a64e1c5Smrg * To make it simple, reallocate the strings returned by 21199a64e1c5Smrg * XtGetSubresources. We can free our own strings, but not theirs. 21209a64e1c5Smrg */ 21219a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_n); 21229a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_b); 21239a64e1c5Smrg#if OPT_WIDE_CHARS 21249a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_w); 21259a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_wb); 21269a64e1c5Smrg#endif 21279a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 21289a64e1c5Smrg ALLOC_STRING(subresourceRec.MenuFontName(n)); 21299a64e1c5Smrg } 21309a64e1c5Smrg 2131dfb07bc7Smrg /* 2132dfb07bc7Smrg * Now, save the string to a font-list for consistency 2133dfb07bc7Smrg */ 2134dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \ 2135dfb07bc7Smrg save2FontList(xw, "cached", \ 2136dfb07bc7Smrg &(subresourceRec.fonts), \ 2137dfb07bc7Smrg which, \ 2138dfb07bc7Smrg subresourceRec.default_font.field, False) 2139dfb07bc7Smrg 2140dfb07bc7Smrg ALLOC_SUBLIST(fNorm, f_n); 2141dfb07bc7Smrg ALLOC_SUBLIST(fBold, f_b); 2142dfb07bc7Smrg#if OPT_WIDE_CHARS 2143dfb07bc7Smrg ALLOC_SUBLIST(fWide, f_w); 2144dfb07bc7Smrg ALLOC_SUBLIST(fWBold, f_wb); 2145dfb07bc7Smrg#endif 2146dfb07bc7Smrg 2147d522f475Smrg /* 2148d522f475Smrg * If a particular resource value was not found, use the original. 2149d522f475Smrg */ 2150dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n); 2151dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b); 2152dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_n); 2153dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_b); 2154d522f475Smrg#if OPT_WIDE_CHARS 2155dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w); 2156dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb); 2157dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_w); 2158dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_wb); 2159d522f475Smrg#endif 21609a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2161dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n)); 21629a64e1c5Smrg } 2163d522f475Smrg 2164d522f475Smrg /* 2165d522f475Smrg * Finally, copy the subresource data to the widget. 2166d522f475Smrg */ 21679a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, subresourceRec); 2168dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, subresourceRec); 21699a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2170dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, subresourceRec); 21719a64e1c5Smrg 21729a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontMenu_default)); 21739a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fBold]); 2174dfb07bc7Smrg screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw)); 2175dfb07bc7Smrg screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw)); 2176d522f475Smrg#if OPT_WIDE_CHARS 21779a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWide]); 21789a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWBold]); 2179dfb07bc7Smrg screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw)); 2180dfb07bc7Smrg screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw)); 2181d522f475Smrg#endif 21829a64e1c5Smrg /* 21839a64e1c5Smrg * And remove our copies of strings. 21849a64e1c5Smrg */ 21859a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_n); 21869a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_b); 21879a64e1c5Smrg#if OPT_WIDE_CHARS 21889a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_w); 21899a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_wb); 21909a64e1c5Smrg#endif 21919a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 21929a64e1c5Smrg FREE_STRING(subresourceRec.MenuFontName(n)); 21939a64e1c5Smrg } 2194d522f475Smrg } else { 2195d522f475Smrg TRACE(("...no resources found\n")); 2196d522f475Smrg status = False; 2197d522f475Smrg } 2198d522f475Smrg } 2199dfb07bc7Smrg TRACE((".. xtermLoadVTFonts: %d\n", status)); 2200d522f475Smrg return status; 2201d522f475Smrg} 2202d522f475Smrg 2203d522f475Smrg#if OPT_WIDE_CHARS 2204d522f475Smrgstatic Bool 22059a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk) 2206d522f475Smrg{ 2207d522f475Smrg Bool result = False; 2208d522f475Smrg 2209d522f475Smrg (void) tag; 2210d522f475Smrg if (okFont(fp)) { 2211d522f475Smrg unsigned count = countGlyphs(fp); 2212d522f475Smrg TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 2213d522f475Smrg result = (count > 256) ? True : False; 2214d522f475Smrg } else { 2215d522f475Smrg result = nullOk; 2216d522f475Smrg } 2217d522f475Smrg return result; 2218d522f475Smrg} 2219d522f475Smrg 2220d522f475Smrg/* 2221d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts. 2222d522f475Smrg * 2223d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not 2224d522f475Smrg * been setup, so we pass nullOk=True to isWideFont(). 2225d522f475Smrg * 2226d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry 2227d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide. 2228d522f475Smrg */ 2229d522f475SmrgBool 2230d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk) 2231d522f475Smrg{ 2232956cc18dSsnj TScreen *screen = TScreenOf(xw); 2233d522f475Smrg Bool result; 2234d522f475Smrg 2235d4fba8b9Smrg if (EmptyFont(GetNormalFont(screen, fWide)->fs)) { 2236d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2237d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk)); 2238d522f475Smrg } else { 2239d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk) 2240d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fWBold)->fs, 2241dfb07bc7Smrg "wide-bold", nullOk)); 2242d522f475Smrg if (result && !screen->utf8_latin1) { 2243d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2244d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, 2245dfb07bc7Smrg "bold", nullOk)); 2246d522f475Smrg } 2247d522f475Smrg } 2248d522f475Smrg if (!result) { 2249d522f475Smrg TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 2250e39b573cSmrg result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 2251d522f475Smrg } 2252d522f475Smrg TRACE(("xtermLoadWideFonts:%d\n", result)); 2253d522f475Smrg return result; 2254d522f475Smrg} 2255d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2256d522f475Smrg 2257d522f475Smrg/* 2258d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts. 2259d522f475Smrg */ 2260d522f475SmrgBool 2261956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw) 2262d522f475Smrg{ 2263d522f475Smrg Bool result; 2264956cc18dSsnj result = xtermLoadVTFonts(xw, NULL, NULL); 2265d522f475Smrg TRACE(("xtermLoadDefaultFonts:%d\n", result)); 2266d522f475Smrg return result; 2267d522f475Smrg} 2268d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 2269d522f475Smrg 2270d522f475Smrg#if OPT_LOAD_VTFONTS 2271d522f475Smrgvoid 2272d522f475SmrgHandleLoadVTFonts(Widget w, 22739a64e1c5Smrg XEvent *event GCC_UNUSED, 2274d4fba8b9Smrg String *params, 2275d4fba8b9Smrg Cardinal *param_count) 2276d522f475Smrg{ 2277956cc18dSsnj XtermWidget xw; 2278956cc18dSsnj 2279956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2280037a25ddSmrg static char empty[] = ""; /* appease strict compilers */ 2281037a25ddSmrg 2282956cc18dSsnj TScreen *screen = TScreenOf(xw); 2283492d43a5Smrg char name_buf[80]; 2284492d43a5Smrg String name = (String) ((*param_count > 0) ? params[0] : empty); 228594644356Smrg char *myName = MyStackAlloc(strlen(name) + 1, name_buf); 2286d522f475Smrg 2287d522f475Smrg TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 228894644356Smrg if (myName != 0) { 2289037a25ddSmrg char class_buf[80]; 229094644356Smrg String convert = (String) ((*param_count > 1) ? params[1] : myName); 229194644356Smrg char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf); 229294644356Smrg 229394644356Smrg strcpy(myName, name); 229494644356Smrg if (myClass != 0) { 229594644356Smrg strcpy(myClass, convert); 229694644356Smrg if (*param_count == 1) 229794644356Smrg myClass[0] = x_toupper(myClass[0]); 229894644356Smrg 229994644356Smrg if (xtermLoadVTFonts(xw, myName, myClass)) { 2300037a25ddSmrg int n; 230194644356Smrg /* 230294644356Smrg * When switching fonts, try to preserve the font-menu 230394644356Smrg * selection, since it is less surprising to do that (if 230494644356Smrg * the font-switching can be undone) than to switch to 230594644356Smrg * "Default". 230694644356Smrg */ 230794644356Smrg int font_number = screen->menu_font_number; 230894644356Smrg if (font_number > fontMenu_lastBuiltin) 230994644356Smrg font_number = fontMenu_lastBuiltin; 231094644356Smrg for (n = 0; n < NMENUFONTS; ++n) { 231194644356Smrg screen->menu_font_sizes[n] = 0; 231294644356Smrg } 2313dfb07bc7Smrg if (font_number == fontMenu_default) { 2314dfb07bc7Smrg SetVTFont(xw, font_number, True, defaultVTFontNames(xw)); 2315dfb07bc7Smrg } else { 2316dfb07bc7Smrg SetVTFont(xw, font_number, True, NULL); 2317dfb07bc7Smrg } 231894644356Smrg } 231994644356Smrg MyStackFree(myClass, class_buf); 23209a64e1c5Smrg } 232194644356Smrg MyStackFree(myName, name_buf); 2322d522f475Smrg } 2323d522f475Smrg } 2324d522f475Smrg} 2325d522f475Smrg#endif /* OPT_LOAD_VTFONTS */ 2326d522f475Smrg 2327d522f475Smrg/* 2328d522f475Smrg * Set the limits for the box that outlines the cursor. 2329d522f475Smrg */ 2330d522f475Smrgvoid 2331fa3f02f3SmrgxtermSetCursorBox(TScreen *screen) 2332d522f475Smrg{ 2333d522f475Smrg static XPoint VTbox[NBOX]; 2334d522f475Smrg XPoint *vp; 23352eaa94a1Schristos int fw = FontWidth(screen) - 1; 23362eaa94a1Schristos int fh = FontHeight(screen) - 1; 23370bd37d32Smrg int ww = isCursorBar(screen) ? 1 : fw; 23380bd37d32Smrg int hh = isCursorUnderline(screen) ? 1 : fh; 2339d522f475Smrg 2340d522f475Smrg vp = &VTbox[1]; 23410bd37d32Smrg (vp++)->x = (short) ww; 23422eaa94a1Schristos (vp++)->y = (short) hh; 23430bd37d32Smrg (vp++)->x = (short) -ww; 23442eaa94a1Schristos vp->y = (short) -hh; 23452eaa94a1Schristos 2346d522f475Smrg screen->box = VTbox; 2347d522f475Smrg} 2348d522f475Smrg 2349d4fba8b9Smrg#if OPT_RENDERFONT 2350d4fba8b9Smrg 2351d4fba8b9Smrg#define CACHE_XFT(dst,src) if (src.font != 0) {\ 2352d4fba8b9Smrg int err = checkXftWidth(xw, &(dst[fontnum]), &src);\ 2353d4fba8b9Smrg TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\ 2354d522f475Smrg #dst,\ 2355d4fba8b9Smrg fontnum,\ 2356d4fba8b9Smrg src.font->height,\ 2357d4fba8b9Smrg src.font->ascent,\ 2358d4fba8b9Smrg src.font->descent,\ 2359d4fba8b9Smrg ((src.font->ascent + src.font->descent) > src.font->height ? "*" : ""),\ 2360d4fba8b9Smrg src.font->max_advance_width,\ 2361956cc18dSsnj dst[fontnum].map.min_width,\ 2362d4fba8b9Smrg dst[fontnum].map.mixed ? " mixed" : "",\ 2363d4fba8b9Smrg err ? " ERROR" : ""));\ 2364d4fba8b9Smrg if (err) {\ 2365d4fba8b9Smrg xtermCloseXft(screen, &src);\ 2366d4fba8b9Smrg memset((&dst[fontnum]), 0, sizeof(dst[fontnum]));\ 2367d4fba8b9Smrg failed += err;\ 2368d4fba8b9Smrg }\ 2369d522f475Smrg } 2370d522f475Smrg 2371dfb07bc7Smrg#if OPT_REPORT_FONTS 237220d2c4d2Smrgstatic FcChar32 23739a64e1c5SmrgxtermXftFirstChar(XftFont *xft) 237420d2c4d2Smrg{ 237520d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 237620d2c4d2Smrg FcChar32 next; 237720d2c4d2Smrg FcChar32 first; 237820d2c4d2Smrg int i; 237920d2c4d2Smrg 238020d2c4d2Smrg first = FcCharSetFirstPage(xft->charset, map, &next); 23819a64e1c5Smrg for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { 238220d2c4d2Smrg if (map[i]) { 238320d2c4d2Smrg FcChar32 bits = map[i]; 2384fa3f02f3Smrg first += (FcChar32) i *32; 238520d2c4d2Smrg while (!(bits & 0x1)) { 238620d2c4d2Smrg bits >>= 1; 238720d2c4d2Smrg first++; 238820d2c4d2Smrg } 238920d2c4d2Smrg break; 239020d2c4d2Smrg } 23919a64e1c5Smrg } 239220d2c4d2Smrg return first; 239320d2c4d2Smrg} 239420d2c4d2Smrg 239520d2c4d2Smrgstatic FcChar32 23969a64e1c5SmrgxtermXftLastChar(XftFont *xft) 239720d2c4d2Smrg{ 239820d2c4d2Smrg FcChar32 this, last, next; 239920d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 240020d2c4d2Smrg int i; 240120d2c4d2Smrg last = FcCharSetFirstPage(xft->charset, map, &next); 240220d2c4d2Smrg while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 240320d2c4d2Smrg last = this; 2404fa3f02f3Smrg last &= (FcChar32) ~ 0xff; 24059a64e1c5Smrg for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) { 240620d2c4d2Smrg if (map[i]) { 240720d2c4d2Smrg FcChar32 bits = map[i]; 2408fa3f02f3Smrg last += (FcChar32) i *32 + 31; 240920d2c4d2Smrg while (!(bits & 0x80000000)) { 241020d2c4d2Smrg last--; 241120d2c4d2Smrg bits <<= 1; 241220d2c4d2Smrg } 241320d2c4d2Smrg break; 241420d2c4d2Smrg } 24159a64e1c5Smrg } 2416dfb07bc7Smrg return (FcChar32) last; 241720d2c4d2Smrg} 2418dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 241920d2c4d2Smrg 2420d4fba8b9Smrg#if OPT_TRACE 2421d4fba8b9Smrg 2422d4fba8b9Smrg#if !OPT_WIDE_CHARS 2423d4fba8b9Smrgstatic Char * 2424d4fba8b9SmrgconvertToUTF8(Char *buffer, int c) 2425d4fba8b9Smrg{ 2426d4fba8b9Smrg buffer[0] = (Char) c; 2427d4fba8b9Smrg buffer[1] = 0; 2428d4fba8b9Smrg return buffer; 2429d4fba8b9Smrg} 2430d4fba8b9Smrg#endif 2431d4fba8b9Smrg 243220d2c4d2Smrgstatic void 24339a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data) 243420d2c4d2Smrg{ 243520d2c4d2Smrg XftFont *xft = data->font; 243620d2c4d2Smrg TScreen *screen = TScreenOf(xw); 243720d2c4d2Smrg VTwin *win = WhichVWin(screen); 243820d2c4d2Smrg 243920d2c4d2Smrg FcChar32 c; 244020d2c4d2Smrg FcChar32 first = xtermXftFirstChar(xft); 244120d2c4d2Smrg FcChar32 last = xtermXftLastChar(xft); 2442d4fba8b9Smrg FcChar32 dump; 244320d2c4d2Smrg unsigned count = 0; 2444d4fba8b9Smrg unsigned too_high = 0; 2445d4fba8b9Smrg unsigned too_wide = 0; 2446d4fba8b9Smrg Boolean skip = False; 2447d4fba8b9Smrg 2448d4fba8b9Smrg TRACE(("dumpXft " TRACE_L "\n")); 2449d4fba8b9Smrg TRACE(("\tdata range U+%04X..U+%04X\n", first, last)); 2450d4fba8b9Smrg TRACE(("\tcode\tcells\tdimensions\n")); 2451d4fba8b9Smrg#if OPT_TRACE < 2 2452d4fba8b9Smrg dump = 255; 2453d4fba8b9Smrg#else 2454d4fba8b9Smrg dump = last; 2455d4fba8b9Smrg#endif 245620d2c4d2Smrg for (c = first; c <= last; ++c) { 245720d2c4d2Smrg if (FcCharSetHasChar(xft->charset, c)) { 2458c48a5815Smrg int width = CharWidth(screen, c); 245920d2c4d2Smrg XGlyphInfo extents; 2460d4fba8b9Smrg Boolean big_x; 2461d4fba8b9Smrg Boolean big_y; 246220d2c4d2Smrg 246320d2c4d2Smrg XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2464d4fba8b9Smrg big_x = (extents.width > win->f_width); 2465d4fba8b9Smrg big_y = (extents.height > win->f_height); 2466d4fba8b9Smrg 2467d4fba8b9Smrg if (c <= dump) { 2468d4fba8b9Smrg Char buffer[80]; 2469d4fba8b9Smrg 2470d4fba8b9Smrg *convertToUTF8(buffer, c) = '\0'; 2471d4fba8b9Smrg TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n", 2472d4fba8b9Smrg (big_y ? "y" : ""), 2473d4fba8b9Smrg (big_x ? "x" : ""), 2474d4fba8b9Smrg c, width, 2475d4fba8b9Smrg ((double) extents.height) / win->f_height, 2476d4fba8b9Smrg ((double) extents.width) / win->f_width, 2477d4fba8b9Smrg buffer)); 2478d4fba8b9Smrg } else if (!skip) { 2479d4fba8b9Smrg skip = True; 2480d4fba8b9Smrg TRACE(("\t...skipping\n")); 2481d4fba8b9Smrg } 2482d4fba8b9Smrg if (big_y) 2483d4fba8b9Smrg ++too_high; 2484d4fba8b9Smrg if (big_x) 2485d4fba8b9Smrg ++too_wide; 248620d2c4d2Smrg ++count; 248720d2c4d2Smrg } 248820d2c4d2Smrg } 2489d4fba8b9Smrg TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide)); 249020d2c4d2Smrg} 249120d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data) 249220d2c4d2Smrg#else 249320d2c4d2Smrg#define DUMP_XFT(xw, data) /* nothing */ 249420d2c4d2Smrg#endif 249520d2c4d2Smrg 2496d4fba8b9Smrg/* 2497d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a 2498d4fba8b9Smrg * problem with web browsers. As of 2018/12 (4 years later), Xft does not work 2499d4fba8b9Smrg * with that. Even with this workaround, fontconfig has at least one bug which 2500d4fba8b9Smrg * causes it to crash (Debian #917034). 2501d4fba8b9Smrg */ 2502d4fba8b9Smrg#ifdef FC_COLOR 2503d4fba8b9Smrg#define GetFcBool(pattern, what) \ 2504d4fba8b9Smrg (FcPatternGetBool(pattern, what, 0, &fcbogus) == FcResultMatch) 2505d4fba8b9Smrg 2506d4fba8b9Smrgstatic Boolean 2507d4fba8b9SmrgisBogusXft(XftFont *font) 2508d4fba8b9Smrg{ 2509d4fba8b9Smrg Boolean result = False; 2510d4fba8b9Smrg if (font != 0) { 2511d4fba8b9Smrg FcBool fcbogus; 2512d4fba8b9Smrg if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) { 2513d4fba8b9Smrg TRACE(("...matched color-bitmap font\n")); 2514d4fba8b9Smrg result = True; 2515d4fba8b9Smrg } else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) { 2516d4fba8b9Smrg TRACE(("...matched non-outline font\n")); 2517d4fba8b9Smrg /* This is legal for regular bitmap fonts - fontconfig attempts to 2518d4fba8b9Smrg * find a match - but problematic for misencoded color-bitmap fonts. 2519d4fba8b9Smrg */ 2520d4fba8b9Smrg } 2521d4fba8b9Smrg } 2522d4fba8b9Smrg return result; 2523d4fba8b9Smrg} 2524d4fba8b9Smrg#endif 2525d4fba8b9Smrg 2526d4fba8b9Smrg#if OPT_BOX_CHARS 2527956cc18dSsnjstatic void 2528d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state) 2529d4fba8b9Smrg{ 2530d4fba8b9Smrg TRACE(("setBrokenBoxChars %s\n", BtoS(state))); 2531d4fba8b9Smrg term->work.broken_box_chars = (Boolean) state; 2532d4fba8b9Smrg TScreenOf(xw)->broken_box_chars = (Boolean) state; 2533d4fba8b9Smrg update_font_boxchars(); 2534d4fba8b9Smrg} 2535d4fba8b9Smrg 2536d4fba8b9Smrg#else 2537d4fba8b9Smrg#define setBrokenBoxChars(xw, state) /* nothing */ 2538d4fba8b9Smrg#endif 2539d4fba8b9Smrg 2540d4fba8b9Smrgstatic Boolean 2541d4fba8b9SmrgcheckedXftWidth(Display *dpy, 2542d4fba8b9Smrg XTermXftFonts *source, 2543d4fba8b9Smrg unsigned limit, 2544d4fba8b9Smrg Dimension *width, 2545d4fba8b9Smrg FcChar32 c) 2546d4fba8b9Smrg{ 2547d4fba8b9Smrg Boolean result = False; 2548d4fba8b9Smrg 2549d4fba8b9Smrg if (FcCharSetHasChar(source->font->charset, c)) { 2550d4fba8b9Smrg XGlyphInfo extents; 2551d4fba8b9Smrg 2552d4fba8b9Smrg result = True; 2553d4fba8b9Smrg XftTextExtents32(dpy, source->font, &c, 1, &extents); 2554d4fba8b9Smrg if (*width < extents.width && extents.width <= limit) { 2555d4fba8b9Smrg *width = extents.width; 2556d4fba8b9Smrg } 2557d4fba8b9Smrg } 2558d4fba8b9Smrg return result; 2559d4fba8b9Smrg} 2560d4fba8b9Smrg 2561d4fba8b9Smrgstatic int 2562d4fba8b9SmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *target, XTermXftFonts *source) 2563956cc18dSsnj{ 2564956cc18dSsnj FcChar32 c; 2565d4fba8b9Smrg FcChar32 last = xtermXftLastChar(source->font); 2566d4fba8b9Smrg Dimension limit = (Dimension) source->font->max_advance_width; 2567956cc18dSsnj Dimension width = 0; 2568d4fba8b9Smrg Dimension width2 = 0; 2569d4fba8b9Smrg int failed = 0; 2570d4fba8b9Smrg#if OPT_WIDE_CHARS 2571d4fba8b9Smrg Cardinal n; 2572d4fba8b9Smrg#endif 2573956cc18dSsnj 2574d4fba8b9Smrg target->font = source->font; 2575d4fba8b9Smrg target->pattern = source->pattern; 2576d4fba8b9Smrg target->map.min_width = 0; 2577d4fba8b9Smrg target->map.max_width = limit; 2578d4fba8b9Smrg 2579d4fba8b9Smrg#if OPT_WIDE_CHARS 2580d4fba8b9Smrg /* 2581d4fba8b9Smrg * Check if the line-drawing characters are all provided in the font. 2582d4fba8b9Smrg * If so, take that into account for the cell-widths. 2583d4fba8b9Smrg */ 2584d4fba8b9Smrg for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) { 2585d4fba8b9Smrg if (!checkedXftWidth(XtDisplay(xw), 2586d4fba8b9Smrg source, 2587d4fba8b9Smrg limit, 2588d4fba8b9Smrg &width2, unicode_boxes[n].code)) { 2589d4fba8b9Smrg width2 = 0; 2590d4fba8b9Smrg TRACE(("font omits U+%04X line-drawing symbol\n", 2591d4fba8b9Smrg unicode_boxes[n].code)); 2592d4fba8b9Smrg break; 2593d4fba8b9Smrg } 2594d4fba8b9Smrg } 2595d4fba8b9Smrg#else 2596d4fba8b9Smrg (void) width2; 2597d4fba8b9Smrg#endif 2598d4fba8b9Smrg 2599d4fba8b9Smrg if (width2 > 0) { 2600d4fba8b9Smrg Dimension check = (Dimension) (limit + 1) / 2; 2601d4fba8b9Smrg TRACE(("font provides VT100-style line-drawing\n")); 2602d4fba8b9Smrg /* 2603d4fba8b9Smrg * The "VT100 line-drawing" characters happen to be all "ambiguous 2604d4fba8b9Smrg * width" in Unicode's scheme. That means that they could be twice as 2605d4fba8b9Smrg * wide as the Latin-1 characters. 2606d4fba8b9Smrg */ 2607d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n)) 2608d4fba8b9Smrg if (width2 > FC_ERR(check)) { 2609d4fba8b9Smrg TRACE(("line-drawing characters appear to be double-width (ignore)\n")); 2610d4fba8b9Smrg setBrokenBoxChars(xw, True); 2611d4fba8b9Smrg } else if (width2 > width) { 2612d4fba8b9Smrg width = width2; 2613d4fba8b9Smrg } 2614d4fba8b9Smrg } else { 2615d4fba8b9Smrg TRACE(("font does NOT provide VT100-style line-drawing\n")); 2616d4fba8b9Smrg setBrokenBoxChars(xw, True); 2617d4fba8b9Smrg } 2618956cc18dSsnj 261920d2c4d2Smrg /* 2620d4fba8b9Smrg * For each printable code, ask what its width is. Given the maximum width 2621d4fba8b9Smrg * for those, we have a reasonable estimate of the single-column width. 262220d2c4d2Smrg * 262320d2c4d2Smrg * Ignore control characters - their extent information is misleading. 262420d2c4d2Smrg */ 2625956cc18dSsnj for (c = 32; c < 256; ++c) { 2626c48a5815Smrg if (CharWidth(TScreenOf(xw), c) <= 0) 262720d2c4d2Smrg continue; 2628d4fba8b9Smrg if (FcCharSetHasChar(source->font->charset, c)) { 2629d4fba8b9Smrg (void) checkedXftWidth(XtDisplay(xw), 2630d4fba8b9Smrg source, 2631d4fba8b9Smrg target->map.max_width, 2632d4fba8b9Smrg &width, c); 2633d4fba8b9Smrg } 2634d4fba8b9Smrg } 2635956cc18dSsnj 2636d4fba8b9Smrg /* 2637d4fba8b9Smrg * Sometimes someone uses a symbol font which has no useful ASCII or 2638d4fba8b9Smrg * Latin-1 characters. Allow that, in case they did it intentionally. 2639d4fba8b9Smrg */ 2640d4fba8b9Smrg if (width == 0) { 2641d4fba8b9Smrg failed = 1; 2642d4fba8b9Smrg if (last >= 256) { 2643d4fba8b9Smrg width = target->map.max_width; 2644956cc18dSsnj } 2645956cc18dSsnj } 2646d4fba8b9Smrg target->map.min_width = width; 2647d4fba8b9Smrg target->map.mixed = (target->map.max_width >= (target->map.min_width + 1)); 2648d4fba8b9Smrg return failed; 2649956cc18dSsnj} 2650956cc18dSsnj 2651dfb07bc7Smrg#if OPT_REPORT_FONTS 2652fa3f02f3Smrgstatic void 2653fa3f02f3SmrgreportXftFonts(XtermWidget xw, 26549a64e1c5Smrg XftFont *fp, 2655fa3f02f3Smrg const char *name, 2656fa3f02f3Smrg const char *tag, 26579a64e1c5Smrg XftPattern *match) 2658fa3f02f3Smrg{ 2659fa3f02f3Smrg if (resource.reportFonts) { 2660fa3f02f3Smrg char buffer[1024]; 2661fa3f02f3Smrg FcChar32 first_char = xtermXftFirstChar(fp); 2662fa3f02f3Smrg FcChar32 last_char = xtermXftLastChar(fp); 2663fa3f02f3Smrg FcChar32 ch; 2664fa3f02f3Smrg unsigned missing = 0; 2665fa3f02f3Smrg 266694644356Smrg printf("Loaded XftFonts(%s[%s])\n", name, tag); 2667fa3f02f3Smrg 2668fa3f02f3Smrg for (ch = first_char; ch <= last_char; ++ch) { 2669fa3f02f3Smrg if (xtermXftMissing(xw, fp, ch)) { 2670fa3f02f3Smrg ++missing; 2671fa3f02f3Smrg } 2672fa3f02f3Smrg } 2673fa3f02f3Smrg printf("\t\tfirst char: %u\n", first_char); 2674fa3f02f3Smrg printf("\t\tlast char: %u\n", last_char); 2675fa3f02f3Smrg printf("\t\tmissing-chars: %u\n", missing); 2676fa3f02f3Smrg printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing); 2677fa3f02f3Smrg 2678fa3f02f3Smrg if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 2679fa3f02f3Smrg char *target; 2680fa3f02f3Smrg char *source = buffer; 2681fa3f02f3Smrg while ((target = strtok(source, ":")) != 0) { 2682fa3f02f3Smrg printf("\t%s\n", target); 2683fa3f02f3Smrg source = 0; 2684fa3f02f3Smrg } 2685fa3f02f3Smrg } 2686d4fba8b9Smrg fflush(stdout); 2687fa3f02f3Smrg } 2688fa3f02f3Smrg} 2689dfb07bc7Smrg#else 2690dfb07bc7Smrg#define reportXftFonts(xw, result, name, tag, match) /* empty */ 2691dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 2692fa3f02f3Smrg 2693d4fba8b9Smrg/* 2694d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to 2695d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does 2696d4fba8b9Smrg * this. That is, closing a font-file may leave the data in Xft's cache, while 2697d4fba8b9Smrg * opening a file may free the data used for the match. 2698d4fba8b9Smrg * 2699d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data 2700d4fba8b9Smrg * if it may have been seen before. 2701d4fba8b9Smrg */ 2702d4fba8b9SmrgBoolean 2703d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font) 2704d4fba8b9Smrg{ 2705d4fba8b9Smrg Boolean result = False; 2706d4fba8b9Smrg if (font != 0) { 2707d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2708d4fba8b9Smrg ListXftFonts *p; 2709d4fba8b9Smrg for (p = screen->list_xft_fonts; p != 0; p = p->next) { 2710d4fba8b9Smrg if (p->font == font) { 2711d4fba8b9Smrg result = True; 2712d4fba8b9Smrg break; 2713d4fba8b9Smrg } 2714d4fba8b9Smrg } 2715d4fba8b9Smrg if (!result) { 2716d4fba8b9Smrg p = TypeXtMalloc(ListXftFonts); 2717d4fba8b9Smrg if (p != 0) { 2718d4fba8b9Smrg p->font = font; 2719d4fba8b9Smrg p->next = screen->list_xft_fonts; 2720d4fba8b9Smrg screen->list_xft_fonts = p; 2721d4fba8b9Smrg } 2722d4fba8b9Smrg } 2723d4fba8b9Smrg } 2724d4fba8b9Smrg return result; 2725d4fba8b9Smrg} 2726d4fba8b9Smrg 2727d4fba8b9Smrg/* 2728d4fba8b9Smrg * Drop an entry from the cache, and close the font. 2729d4fba8b9Smrg */ 2730d4fba8b9Smrgvoid 2731d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font) 2732d4fba8b9Smrg{ 2733d4fba8b9Smrg if (font != 0) { 2734d4fba8b9Smrg ListXftFonts *p, *q; 2735d4fba8b9Smrg 2736d4fba8b9Smrg for (p = screen->list_xft_fonts, q = 0; p != 0; q = p, p = p->next) { 2737d4fba8b9Smrg if (p->font == font) { 2738d4fba8b9Smrg XftFontClose(screen->display, font); 2739d4fba8b9Smrg if (q != 0) { 2740d4fba8b9Smrg q->next = p->next; 2741d4fba8b9Smrg } else { 2742d4fba8b9Smrg screen->list_xft_fonts = p->next; 2743d4fba8b9Smrg } 2744d4fba8b9Smrg free(p); 2745d4fba8b9Smrg break; 2746d4fba8b9Smrg } 2747d4fba8b9Smrg } 2748d4fba8b9Smrg } 2749d4fba8b9Smrg} 2750d4fba8b9Smrg 2751d522f475Smrgstatic XftFont * 27529a64e1c5SmrgxtermOpenXft(XtermWidget xw, const char *name, XftPattern *pat, const char *tag) 2753d522f475Smrg{ 2754956cc18dSsnj TScreen *screen = TScreenOf(xw); 2755956cc18dSsnj Display *dpy = screen->display; 2756d522f475Smrg XftResult status; 2757d522f475Smrg XftFont *result = 0; 2758d522f475Smrg 2759d4fba8b9Smrg TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag)); 2760d522f475Smrg if (pat != 0) { 2761d4fba8b9Smrg XftPattern *match; 2762d4fba8b9Smrg 2763d4fba8b9Smrg FcConfigSubstitute(NULL, pat, FcMatchPattern); 2764d4fba8b9Smrg XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat); 2765d4fba8b9Smrg 2766d4fba8b9Smrg match = FcFontMatch(NULL, pat, &status); 2767d522f475Smrg if (match != 0) { 2768d4fba8b9Smrg Boolean maybeReopened = False; 2769d522f475Smrg result = XftFontOpenPattern(dpy, match); 2770d4fba8b9Smrg#ifdef FC_COLOR 2771d4fba8b9Smrg if (result != 0) { 2772d4fba8b9Smrg if (isBogusXft(result)) { 2773d4fba8b9Smrg XftFontClose(dpy, result); 2774d4fba8b9Smrg result = 0; 2775d4fba8b9Smrg maybeReopened = True; 2776d4fba8b9Smrg } 2777d4fba8b9Smrg } 2778d4fba8b9Smrg#endif 2779d522f475Smrg if (result != 0) { 2780d522f475Smrg TRACE(("...matched %s font\n", tag)); 2781d4fba8b9Smrg if (!maybeXftCache(xw, result)) { 2782d4fba8b9Smrg reportXftFonts(xw, result, name, tag, match); 2783d4fba8b9Smrg } 2784d522f475Smrg } else { 2785d4fba8b9Smrg TRACE(("...could not open %s font\n", tag)); 2786d4fba8b9Smrg if (!maybeReopened) 2787d4fba8b9Smrg XftPatternDestroy(match); 2788956cc18dSsnj if (xw->misc.fontWarnings >= fwAlways) { 2789dfb07bc7Smrg cannotFont(xw, "open", tag, name); 2790956cc18dSsnj } 2791d522f475Smrg } 2792d522f475Smrg } else { 2793d522f475Smrg TRACE(("...did not match %s font\n", tag)); 2794956cc18dSsnj if (xw->misc.fontWarnings >= fwResource) { 2795dfb07bc7Smrg cannotFont(xw, "match", tag, name); 2796956cc18dSsnj } 2797d522f475Smrg } 2798d522f475Smrg } 2799d522f475Smrg return result; 2800d522f475Smrg} 2801d522f475Smrg 2802d522f475Smrg#if OPT_SHIFT_FONTS 2803d522f475Smrg/* 2804d522f475Smrg * Don't make a dependency on the math library for a single function. 2805d522f475Smrg * (Newton Raphson). 2806d522f475Smrg */ 2807d522f475Smrgstatic double 28080bd37d32SmrgdimSquareRoot(double value) 2809d522f475Smrg{ 2810d522f475Smrg double result = 0.0; 2811d522f475Smrg if (value > 0.0) { 2812d522f475Smrg int n; 2813d522f475Smrg double older = value; 2814d522f475Smrg for (n = 0; n < 10; ++n) { 2815d522f475Smrg double delta = (older * older - value) / (2.0 * older); 2816d522f475Smrg double newer = older - delta; 2817d522f475Smrg older = newer; 2818d522f475Smrg result = newer; 2819d522f475Smrg if (delta > -0.001 && delta < 0.001) 2820d522f475Smrg break; 2821d522f475Smrg } 2822d522f475Smrg } 2823d522f475Smrg return result; 2824d522f475Smrg} 2825d522f475Smrg#endif 2826d522f475Smrg 2827d4fba8b9Smrg#ifdef DEBUG_XFT 2828d4fba8b9Smrgstatic void 2829d4fba8b9Smrgtrace_xft_glyph(TScreen *screen, XftFont *font, FT_Face face, int code, const char *name) 2830d4fba8b9Smrg{ 2831d4fba8b9Smrg if (!XftGlyphExists(screen->display, font, code)) { 2832d4fba8b9Smrg TRACE(("Xft glyph U+%04X missing :%s\n", code, name)); 2833d4fba8b9Smrg } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 2834d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 2835d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 2836d4fba8b9Smrg code, 2837d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 2838d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 2839d4fba8b9Smrg name)); 2840d4fba8b9Smrg } 2841d4fba8b9Smrg} 2842d4fba8b9Smrg 2843d4fba8b9Smrg#if OPT_WIDE_CHARS 2844d4fba8b9Smrgstatic void 2845d4fba8b9Smrgtrace_xft_line_drawing(TScreen *screen, XftFont *font, FT_Face face) 2846d4fba8b9Smrg{ 2847d4fba8b9Smrg int n; 2848d4fba8b9Smrg for (n = 0; unicode_boxes[n].code != 0; ++n) { 2849d4fba8b9Smrg trace_xft_glyph(screen, font, face, unicode_boxes[n].code, 2850d4fba8b9Smrg unicode_boxes[n].name); 2851d4fba8b9Smrg } 2852d4fba8b9Smrg} 2853d4fba8b9Smrg#else 2854d4fba8b9Smrg#define trace_xft_line_drawing(screen, font, face) /* nothing */ 2855d4fba8b9Smrg#endif 2856d4fba8b9Smrg#endif /* DEBUG_XFT */ 2857d4fba8b9Smrg 2858d4fba8b9Smrg/* 2859d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box. If so, 2860d4fba8b9Smrg * they're not useful. 2861d4fba8b9Smrg */ 2862d4fba8b9Smrg#if OPT_BOX_CHARS 2863d4fba8b9Smrgstatic void 2864d4fba8b9Smrglinedrawing_gaps(XtermWidget xw, XftFont *font) 2865d4fba8b9Smrg{ 2866d4fba8b9Smrg Boolean broken; 2867d4fba8b9Smrg 2868d4fba8b9Smrg#if OPT_WIDE_CHARS 2869d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2870d4fba8b9Smrg int n; 2871d4fba8b9Smrg FT_Face face; 2872d4fba8b9Smrg face = XftLockFace(font); 2873d4fba8b9Smrg broken = False; 2874d4fba8b9Smrg for (n = 0; unicode_boxes[n].code; ++n) { 2875d4fba8b9Smrg unsigned code = unicode_boxes[n].code; 2876d4fba8b9Smrg 2877d4fba8b9Smrg if (!XftGlyphExists(screen->display, font, code)) { 2878d4fba8b9Smrg TRACE(("Xft glyph U+%04X is missing\n", code)); 2879d4fba8b9Smrg broken = True; 2880d4fba8b9Smrg break; 2881d4fba8b9Smrg } 2882d4fba8b9Smrg 2883d4fba8b9Smrg if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 2884d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 2885d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 2886d4fba8b9Smrg code, 2887d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 2888d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 2889d4fba8b9Smrg unicode_boxes[n].name)); 2890d4fba8b9Smrg /* 2891d4fba8b9Smrg * While it is possible for badly-designed fonts to have line 2892d4fba8b9Smrg * drawing characters which do not meet, FreeType aggravates the 2893d4fba8b9Smrg * situation with its rounding. Check for an obvious case where 2894d4fba8b9Smrg * the weights at the ends of a vertical line do not add up. That 2895d4fba8b9Smrg * shows up as two under-weight rows at the beginning/end of the 2896d4fba8b9Smrg * bitmap. 2897d4fba8b9Smrg */ 2898d4fba8b9Smrg if (code == 0x2502) { 2899d4fba8b9Smrg unsigned r, c; 2900d4fba8b9Smrg unsigned mids = 0, ends = 0; 2901d4fba8b9Smrg unsigned char *data = g->bitmap.buffer; 2902d4fba8b9Smrg 2903d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 2904d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 2905d4fba8b9Smrg /* FALLTHRU */ 2906d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 2907d4fba8b9Smrg for (r = 0; r < (unsigned) g->bitmap.rows; ++r) { 2908d4fba8b9Smrg unsigned k = r * (unsigned) g->bitmap.pitch; 2909d4fba8b9Smrg unsigned sum = 0; 2910d4fba8b9Smrg for (c = 0; c < (unsigned) g->bitmap.width; ++c) { 2911d4fba8b9Smrg unsigned xx = 0; 2912d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 2913d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 2914d4fba8b9Smrg xx = (unsigned) ((data[k + (c / 8)] 2915d4fba8b9Smrg >> (c % 8)) & 1); 2916d4fba8b9Smrg break; 2917d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 2918d4fba8b9Smrg xx = data[k + c]; 2919d4fba8b9Smrg break; 2920d4fba8b9Smrg } 2921d4fba8b9Smrg sum += xx; 2922d4fba8b9Smrg TRACE2((" %2x", xx)); 2923d4fba8b9Smrg } 2924d4fba8b9Smrg TRACE2((" = %u\n", sum)); 2925d4fba8b9Smrg if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) { 2926d4fba8b9Smrg mids = sum; 2927d4fba8b9Smrg } else { 2928d4fba8b9Smrg ends += sum; 2929d4fba8b9Smrg } 2930d4fba8b9Smrg } 2931d4fba8b9Smrg TRACE(("...compare middle %u vs ends %u\n", mids, ends)); 2932d4fba8b9Smrg if ((mids > ends) && (g->bitmap.rows < 16)) 2933d4fba8b9Smrg broken = True; 2934d4fba8b9Smrg break; 2935d4fba8b9Smrg default: 2936d4fba8b9Smrg TRACE(("FIXME pixel_mode %d not handled\n", 2937d4fba8b9Smrg g->bitmap.pixel_mode)); 2938d4fba8b9Smrg break; 2939d4fba8b9Smrg } 2940d4fba8b9Smrg if (broken) 2941d4fba8b9Smrg break; 2942d4fba8b9Smrg } 2943d4fba8b9Smrg /* 2944d4fba8b9Smrg * The factor of two accounts for line-drawing that goes through 2945d4fba8b9Smrg * the middle of a cell, possibly leaving half of the cell unused. 2946d4fba8b9Smrg * A horizontal line has to extend the full width of the cell. 2947d4fba8b9Smrg */ 2948d4fba8b9Smrg switch (unicode_boxes[n].high) { 2949d4fba8b9Smrg case 1: 2950d4fba8b9Smrg if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) { 2951d4fba8b9Smrg TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n", 2952d4fba8b9Smrg (unsigned) g->bitmap.rows, 2953d4fba8b9Smrg (unsigned) FontHeight(screen))); 2954d4fba8b9Smrg broken = True; 2955d4fba8b9Smrg } 2956d4fba8b9Smrg break; 2957d4fba8b9Smrg case 2: 2958d4fba8b9Smrg if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) { 2959d4fba8b9Smrg TRACE(("...bitmap is too short for half-cell (%u vs %u)\n", 2960d4fba8b9Smrg (unsigned) (g->bitmap.rows * 2), 2961d4fba8b9Smrg (unsigned) FontHeight(screen))); 2962d4fba8b9Smrg broken = True; 2963d4fba8b9Smrg } 2964d4fba8b9Smrg break; 2965d4fba8b9Smrg } 2966d4fba8b9Smrg switch (unicode_boxes[n].wide) { 2967d4fba8b9Smrg case 1: 2968d4fba8b9Smrg if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) { 2969d4fba8b9Smrg TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n", 2970d4fba8b9Smrg (unsigned) g->bitmap.width, 2971d4fba8b9Smrg (unsigned) FontWidth(screen))); 2972d4fba8b9Smrg broken = True; 2973d4fba8b9Smrg } 2974d4fba8b9Smrg break; 2975d4fba8b9Smrg case 2: 2976d4fba8b9Smrg if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) { 2977d4fba8b9Smrg TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n", 2978d4fba8b9Smrg (unsigned) (g->bitmap.width * 2), 2979d4fba8b9Smrg (unsigned) FontWidth(screen))); 2980d4fba8b9Smrg broken = True; 2981d4fba8b9Smrg } 2982d4fba8b9Smrg break; 2983d4fba8b9Smrg } 2984d4fba8b9Smrg if (broken) 2985d4fba8b9Smrg break; 2986d4fba8b9Smrg } 2987d4fba8b9Smrg } 2988d4fba8b9Smrg XftUnlockFace(font); 2989d4fba8b9Smrg#else 2990d4fba8b9Smrg (void) font; 2991d4fba8b9Smrg broken = True; 2992d4fba8b9Smrg#endif 2993d4fba8b9Smrg 2994d4fba8b9Smrg if (broken) { 2995d4fba8b9Smrg TRACE(("Xft line-drawing would not work\n")); 2996d4fba8b9Smrg setBrokenBoxChars(xw, True); 2997d4fba8b9Smrg } 2998d4fba8b9Smrg} 2999d4fba8b9Smrg#endif /* OPT_BOX_CHARS */ 3000d4fba8b9Smrg 3001d522f475Smrg/* 3002d522f475Smrg * Given the Xft font metrics, determine the actual font size. This is used 3003d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same 3004d522f475Smrg * rule. 3005d522f475Smrg */ 3006d522f475Smrgstatic void 3007d4fba8b9SmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XftFont *font, const char *tag) 3008d522f475Smrg{ 3009d522f475Smrg if (font != 0) { 3010d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3011d522f475Smrg int width, height, ascent, descent; 3012d4fba8b9Smrg#ifdef DEBUG_XFT 3013d4fba8b9Smrg int n; 3014d4fba8b9Smrg FT_Face face; 3015d4fba8b9Smrg FT_Size size; 3016d4fba8b9Smrg FT_Size_Metrics metrics; 3017d4fba8b9Smrg Boolean scalable; 3018d4fba8b9Smrg Boolean is_fixed; 3019d4fba8b9Smrg Boolean debug_xft = False; 3020d4fba8b9Smrg 3021d4fba8b9Smrg face = XftLockFace(font); 3022d4fba8b9Smrg size = face->size; 3023d4fba8b9Smrg metrics = size->metrics; 3024d4fba8b9Smrg is_fixed = FT_IS_FIXED_WIDTH(face); 3025d4fba8b9Smrg scalable = FT_IS_SCALABLE(face); 3026d4fba8b9Smrg trace_xft_line_drawing(screen, font, face); 3027d4fba8b9Smrg for (n = 32; n < 127; ++n) { 3028d4fba8b9Smrg char name[80]; 3029d4fba8b9Smrg sprintf(name, "letter \"%c\"", n); 3030d4fba8b9Smrg trace_xft_glyph(screen, font, face, n, name); 3031d4fba8b9Smrg } 3032d4fba8b9Smrg XftUnlockFace(font); 3033d4fba8b9Smrg 3034d4fba8b9Smrg /* freetype's inconsistent for this sign */ 3035d4fba8b9Smrg metrics.descender = -metrics.descender; 3036d4fba8b9Smrg 3037d4fba8b9Smrg#define TR_XFT "Xft metrics: " 3038d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0) 3039d4fba8b9Smrg#define M_64(a,b) ((font->a * 64) != metrics.b) 3040d4fba8b9Smrg#define BOTH(a,b) D_64(b), M_64(a,b) ? "*" : "" 3041d4fba8b9Smrg 3042d4fba8b9Smrg debug_xft = (M_64(ascent, ascender) 3043d4fba8b9Smrg || M_64(descent, descender) 3044d4fba8b9Smrg || M_64(height, height) 3045d4fba8b9Smrg || M_64(max_advance_width, max_advance)); 3046d4fba8b9Smrg 3047d4fba8b9Smrg TRACE(("Xft font is %sscalable, %sfixed-width\n", 3048d4fba8b9Smrg is_fixed ? "" : "not ", 3049d4fba8b9Smrg scalable ? "" : "not ")); 3050d4fba8b9Smrg 3051d4fba8b9Smrg if (debug_xft) { 3052d4fba8b9Smrg TRACE(("Xft font size %d+%d vs %d by %d\n", 3053d4fba8b9Smrg font->ascent, 3054d4fba8b9Smrg font->descent, 3055d4fba8b9Smrg font->height, 3056d4fba8b9Smrg font->max_advance_width)); 3057d4fba8b9Smrg TRACE((TR_XFT "ascender %6.2f%s\n", BOTH(ascent, ascender))); 3058d4fba8b9Smrg TRACE((TR_XFT "descender %6.2f%s\n", BOTH(descent, descender))); 3059d4fba8b9Smrg TRACE((TR_XFT "height %6.2f%s\n", BOTH(height, height))); 3060d4fba8b9Smrg TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance))); 3061d4fba8b9Smrg } else { 3062d4fba8b9Smrg TRACE((TR_XFT "matches font\n")); 3063d4fba8b9Smrg } 3064d4fba8b9Smrg#endif 3065d522f475Smrg 3066d522f475Smrg width = font->max_advance_width; 3067d522f475Smrg height = font->height; 3068d522f475Smrg ascent = font->ascent; 3069d522f475Smrg descent = font->descent; 3070d4fba8b9Smrg if (screen->force_xft_height && height < ascent + descent) { 3071d4fba8b9Smrg TRACE(("...height is less than ascent + descent (%u vs %u)\n", 3072d4fba8b9Smrg height, ascent + descent)); 3073d4fba8b9Smrg if ((ascent + descent) > (height + 1)) { 3074d4fba8b9Smrg /* this happens less than 10% of the time */ 3075d4fba8b9Smrg --ascent; 3076d4fba8b9Smrg --descent; 3077d4fba8b9Smrg TRACE(("...decrement both ascent and descent before retry\n")); 3078d4fba8b9Smrg } else if (ascent > descent) { 3079d4fba8b9Smrg /* this is the usual case */ 3080d4fba8b9Smrg --ascent; 3081d4fba8b9Smrg TRACE(("...decrement ascent before retry\n")); 3082d4fba8b9Smrg } else { 3083d4fba8b9Smrg /* this could happen, though rare... */ 3084d4fba8b9Smrg --descent; 3085d4fba8b9Smrg TRACE(("...decrement descent before retry\n")); 3086d4fba8b9Smrg } 3087d522f475Smrg height = ascent + descent; 3088d4fba8b9Smrg font->ascent = ascent; 3089d4fba8b9Smrg font->descent = descent; 3090d4fba8b9Smrg TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n", 3091d4fba8b9Smrg height, ascent + descent, ascent, descent)); 3092d522f475Smrg } 3093d522f475Smrg if (is_double_width_font_xft(screen->display, font)) { 3094d4fba8b9Smrg TRACE(("...reduce width from %d to %d\n", width, width >> 1)); 3095d522f475Smrg width >>= 1; 3096d522f475Smrg } 3097d522f475Smrg if (tag == 0) { 30980bd37d32Smrg SetFontWidth(screen, win, width); 30990bd37d32Smrg SetFontHeight(screen, win, height); 3100d522f475Smrg win->f_ascent = ascent; 3101d522f475Smrg win->f_descent = descent; 3102d522f475Smrg TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 3103d522f475Smrg width, height, ascent, descent)); 3104d522f475Smrg } else if (win->f_width < width || 3105d522f475Smrg win->f_height < height || 3106d522f475Smrg win->f_ascent < ascent || 3107d522f475Smrg win->f_descent < descent) { 3108d522f475Smrg TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 3109d522f475Smrg tag, 3110d522f475Smrg win->f_width, win->f_height, win->f_ascent, win->f_descent, 3111d522f475Smrg width, height, ascent, descent)); 3112d522f475Smrg 31130bd37d32Smrg SetFontWidth(screen, win, width); 31140bd37d32Smrg SetFontHeight(screen, win, height); 3115d522f475Smrg win->f_ascent = ascent; 3116d522f475Smrg win->f_descent = descent; 3117d522f475Smrg } else { 3118d522f475Smrg TRACE(("setRenderFontsize %s unchanged\n", tag)); 3119d522f475Smrg } 3120d4fba8b9Smrg#if OPT_BOX_CHARS 3121d4fba8b9Smrg if (!screen->broken_box_chars && (tag == 0)) { 3122d4fba8b9Smrg linedrawing_gaps(xw, font); 3123d4fba8b9Smrg } 3124d4fba8b9Smrg#endif 3125d522f475Smrg } 3126d522f475Smrg} 3127d522f475Smrg#endif 3128d522f475Smrg 312920d2c4d2Smrgstatic void 3130d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed) 313120d2c4d2Smrg{ 3132d4fba8b9Smrg if (value == 0 || failed) { 3133d4fba8b9Smrg if (value == 0) { 3134d4fba8b9Smrg xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 3135d4fba8b9Smrg exit(1); 3136d4fba8b9Smrg } else { 3137d4fba8b9Smrg xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag); 3138d4fba8b9Smrg } 313920d2c4d2Smrg } 314020d2c4d2Smrg} 314120d2c4d2Smrg 314220d2c4d2Smrg#if OPT_RENDERFONT 314320d2c4d2Smrgvoid 31449a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub) 314520d2c4d2Smrg{ 314620d2c4d2Smrg if (pub->font != 0) { 3147d4fba8b9Smrg Cardinal n; 3148d4fba8b9Smrg 3149d4fba8b9Smrg closeCachedXft(screen, pub->font); 315020d2c4d2Smrg pub->font = 0; 3151d4fba8b9Smrg 3152d4fba8b9Smrg if (pub->pattern) { 3153d4fba8b9Smrg XftPatternDestroy(pub->pattern); 3154d4fba8b9Smrg pub->pattern = 0; 3155d4fba8b9Smrg } 3156d4fba8b9Smrg if (pub->fontset) { 3157d4fba8b9Smrg XftFontSetDestroy(pub->fontset); 3158d4fba8b9Smrg pub->fontset = 0; 3159d4fba8b9Smrg } 3160d4fba8b9Smrg 3161d4fba8b9Smrg for (n = 0; n < pub->limit; ++n) { 3162d4fba8b9Smrg if (pub->cache[n].font) { 3163d4fba8b9Smrg closeCachedXft(screen, pub->cache[n].font); 3164d4fba8b9Smrg pub->cache[n].font = 0; 3165d4fba8b9Smrg } 3166d4fba8b9Smrg } 3167d4fba8b9Smrg free(pub->cache); 3168d4fba8b9Smrg pub->cache = NULL; 316920d2c4d2Smrg } 317020d2c4d2Smrg} 317120d2c4d2Smrg 317220d2c4d2Smrg/* 3173d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting. 317420d2c4d2Smrg */ 3175492d43a5SmrgString 3176d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName) 317720d2c4d2Smrg{ 317820d2c4d2Smrg#if OPT_RENDERWIDE 3179492d43a5Smrg String result = (wideName 3180dfb07bc7Smrg ? FirstItemOf(xw->work.fonts.xft.list_w) 3181dfb07bc7Smrg : CurrentXftFont(xw)); 318220d2c4d2Smrg#else 3183dfb07bc7Smrg String result = CurrentXftFont(xw); 3184d4fba8b9Smrg (void) wideName; 318520d2c4d2Smrg#endif 318620d2c4d2Smrg return x_nonempty(result); 318720d2c4d2Smrg} 318820d2c4d2Smrg 318920d2c4d2Smrg/* 319020d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that 319120d2c4d2Smrg * are derived from it. 319220d2c4d2Smrg */ 319320d2c4d2Smrgvoid 319420d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value) 319520d2c4d2Smrg{ 319620d2c4d2Smrg TScreen *screen = TScreenOf(xw); 3197dfb07bc7Smrg Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0) 3198dfb07bc7Smrg || strcmp(CurrentXftFont(xw), value)); 319920d2c4d2Smrg 32000bd37d32Smrg if (changed) { 3201037a25ddSmrg int n; 3202037a25ddSmrg 3203dfb07bc7Smrg CurrentXftFont(xw) = x_strdup(value); 32040bd37d32Smrg for (n = 0; n < NMENUFONTS; ++n) { 3205dfb07bc7Smrg int e; 32060bd37d32Smrg xw->misc.face_size[n] = -1.0; 3207dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 3208dfb07bc7Smrg xtermCloseXft(screen, getMyXftFont(xw, e, n)); 3209dfb07bc7Smrg } 32100bd37d32Smrg } 321120d2c4d2Smrg } 321220d2c4d2Smrg} 321320d2c4d2Smrg#endif 321420d2c4d2Smrg 3215d522f475Smrg/* 3216d522f475Smrg * Compute useful values for the font/window sizes 3217d522f475Smrg */ 3218d522f475Smrgvoid 3219d522f475SmrgxtermComputeFontInfo(XtermWidget xw, 32209a64e1c5Smrg VTwin *win, 32219a64e1c5Smrg XFontStruct *font, 3222d522f475Smrg int sbwidth) 3223d522f475Smrg{ 3224956cc18dSsnj TScreen *screen = TScreenOf(xw); 3225d522f475Smrg 3226d522f475Smrg int i, j, width, height; 3227492d43a5Smrg#if OPT_RENDERFONT 3228492d43a5Smrg int fontnum = screen->menu_font_number; 3229492d43a5Smrg#endif 3230d4fba8b9Smrg int failed = 0; 3231d522f475Smrg 3232d522f475Smrg#if OPT_RENDERFONT 3233d522f475Smrg /* 3234d522f475Smrg * xterm contains a lot of references to fonts, assuming they are fixed 3235d522f475Smrg * size. This chunk of code overrides the actual font-selection (see 3236d522f475Smrg * drawXtermText()), if the user has selected render-font. All of the 3237d522f475Smrg * font-loading for fixed-fonts still goes on whether or not this chunk 3238d522f475Smrg * overrides it. 3239d522f475Smrg */ 3240492d43a5Smrg if (UsingRenderFont(xw) && fontnum >= 0) { 3241492d43a5Smrg String face_name = getFaceName(xw, False); 3242d4fba8b9Smrg XTermXftFonts norm = screen->renderFontNorm[fontnum]; 3243d4fba8b9Smrg XTermXftFonts bold = screen->renderFontBold[fontnum]; 3244d4fba8b9Smrg XTermXftFonts ital = screen->renderFontItal[fontnum]; 3245d4fba8b9Smrg XTermXftFonts btal = screen->renderFontBtal[fontnum]; 3246d522f475Smrg#if OPT_RENDERWIDE 3247d4fba8b9Smrg XTermXftFonts wnorm = screen->renderWideNorm[fontnum]; 3248d4fba8b9Smrg XTermXftFonts wbold = screen->renderWideBold[fontnum]; 3249d4fba8b9Smrg XTermXftFonts wital = screen->renderWideItal[fontnum]; 3250d4fba8b9Smrg XTermXftFonts wbtal = screen->renderWideBtal[fontnum]; 3251d522f475Smrg#endif 3252d522f475Smrg 3253d4fba8b9Smrg if (norm.font == 0 && !IsEmpty(face_name)) { 3254d522f475Smrg XftPattern *pat; 32550bd37d32Smrg double face_size; 3256d522f475Smrg 32570bd37d32Smrg TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 3258492d43a5Smrg fontnum, face_name, 3259d522f475Smrg xw->misc.face_size[fontnum])); 3260d522f475Smrg 3261d4fba8b9Smrg TRACE(("Using Xft %d\n", XftVersion)); 3262d4fba8b9Smrg TRACE(("Using FontConfig %d\n", FC_VERSION)); 3263d4fba8b9Smrg 32640bd37d32Smrg fillInFaceSize(xw, fontnum); 3265d4fba8b9Smrg face_size = (double) xw->misc.face_size[fontnum]; 3266d522f475Smrg 3267d522f475Smrg /* 3268d522f475Smrg * By observation (there is no documentation), XftPatternBuild is 3269d522f475Smrg * cumulative. Build the bold- and italic-patterns on top of the 3270d522f475Smrg * normal pattern. 3271d522f475Smrg */ 3272d4fba8b9Smrg#ifdef FC_COLOR 3273d522f475Smrg#define NormXftPattern \ 3274d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3275d4fba8b9Smrg FC_COLOR, XftTypeBool, FcFalse, \ 3276d4fba8b9Smrg FC_OUTLINE, XftTypeBool, FcTrue, \ 3277d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3278d4fba8b9Smrg#else 3279d4fba8b9Smrg#define NormXftPattern \ 3280d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3281d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3282d4fba8b9Smrg#endif 3283d522f475Smrg 3284d522f475Smrg#define BoldXftPattern(norm) \ 3285d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3286d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width 3287d522f475Smrg 3288d522f475Smrg#define ItalXftPattern(norm) \ 3289d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3290d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width 3291d4fba8b9Smrg 3292d4fba8b9Smrg#define BtalXftPattern(norm) \ 3293d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3294d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3295d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width 3296d522f475Smrg 32979a64e1c5Smrg#if OPT_WIDE_ATTRS 32989a64e1c5Smrg#define HAVE_ITALICS 1 32999a64e1c5Smrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0) 33009a64e1c5Smrg#elif OPT_ISO_COLORS 33019a64e1c5Smrg#define HAVE_ITALICS 1 33029a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0) 33039a64e1c5Smrg#else 33049a64e1c5Smrg#define HAVE_ITALICS 0 33059a64e1c5Smrg#endif 33069a64e1c5Smrg 3307d4fba8b9Smrg#if OPT_DEC_CHRSET 3308d4fba8b9Smrg freeall_DoubleFT(xw); 3309d4fba8b9Smrg#endif 331020d2c4d2Smrg if ((pat = XftNameParse(face_name)) != 0) { 3311d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag) 3312d4fba8b9Smrg norm.pattern = XftPatternDuplicate(pat); 3313d4fba8b9Smrg XftPatternBuild(norm.pattern, 3314d522f475Smrg NormXftPattern, 3315d522f475Smrg (void *) 0); 3316d4fba8b9Smrg OPEN_XFT(norm, "normal"); 3317d522f475Smrg 3318d4fba8b9Smrg if (norm.font != 0) { 3319d4fba8b9Smrg bold.pattern = XftPatternDuplicate(pat); 3320d4fba8b9Smrg XftPatternBuild(bold.pattern, 3321d4fba8b9Smrg NormXftPattern, 3322d522f475Smrg BoldXftPattern(norm), 3323d522f475Smrg (void *) 0); 3324d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3325d522f475Smrg 33269a64e1c5Smrg#if HAVE_ITALICS 33279a64e1c5Smrg if (FIND_ITALICS) { 3328d4fba8b9Smrg ital.pattern = XftPatternDuplicate(pat); 3329d4fba8b9Smrg XftPatternBuild(ital.pattern, 3330d522f475Smrg NormXftPattern, 3331d522f475Smrg ItalXftPattern(norm), 3332d522f475Smrg (void *) 0); 3333d4fba8b9Smrg OPEN_XFT(ital, "italic"); 3334d4fba8b9Smrg btal.pattern = XftPatternDuplicate(pat); 3335d4fba8b9Smrg XftPatternBuild(btal.pattern, 3336d4fba8b9Smrg NormXftPattern, 3337d4fba8b9Smrg BtalXftPattern(norm), 3338d4fba8b9Smrg (void *) 0); 3339d4fba8b9Smrg OPEN_XFT(btal, "bold-italic"); 3340d522f475Smrg } 33419a64e1c5Smrg#endif 3342d522f475Smrg 3343d522f475Smrg /* 3344d522f475Smrg * FIXME: just assume that the corresponding font has no 3345d522f475Smrg * graphics characters. 3346d522f475Smrg */ 3347d522f475Smrg if (screen->fnt_boxes) { 3348d4fba8b9Smrg screen->fnt_boxes = 0; 3349d522f475Smrg TRACE(("Xft opened - will %suse internal line-drawing characters\n", 3350d522f475Smrg screen->fnt_boxes ? "not " : "")); 3351d522f475Smrg } 3352d522f475Smrg } 3353d522f475Smrg 3354d4fba8b9Smrg CACHE_XFT(screen->renderFontNorm, norm); 3355d4fba8b9Smrg 3356d4fba8b9Smrg CACHE_XFT(screen->renderFontBold, bold); 3357d4fba8b9Smrg if (norm.font != 0 && !bold.font) { 3358d4fba8b9Smrg noUsableXft(xw, "bold"); 3359d4fba8b9Smrg XftPatternDestroy(bold.pattern); 3360d4fba8b9Smrg bold.pattern = XftPatternDuplicate(pat); 3361d4fba8b9Smrg XftPatternBuild(bold.pattern, 3362d4fba8b9Smrg NormXftPattern, 3363d4fba8b9Smrg (void *) 0); 3364d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3365d4fba8b9Smrg failed = 0; 3366d4fba8b9Smrg CACHE_XFT(screen->renderFontBold, bold); 3367d4fba8b9Smrg } 3368d4fba8b9Smrg#if HAVE_ITALICS 3369d4fba8b9Smrg CACHE_XFT(screen->renderFontItal, ital); 3370d4fba8b9Smrg if (norm.font != 0 && !ital.font) { 3371d4fba8b9Smrg noUsableXft(xw, "italic"); 3372d4fba8b9Smrg XftPatternDestroy(ital.pattern); 3373d4fba8b9Smrg ital.pattern = XftPatternDuplicate(pat); 3374d4fba8b9Smrg XftPatternBuild(ital.pattern, 3375d4fba8b9Smrg NormXftPattern, 3376d4fba8b9Smrg (void *) 0); 3377d4fba8b9Smrg OPEN_XFT(ital, "italics"); 3378d4fba8b9Smrg failed = 0; 3379d4fba8b9Smrg CACHE_XFT(screen->renderFontItal, ital); 3380d4fba8b9Smrg } 3381d4fba8b9Smrg CACHE_XFT(screen->renderFontBtal, btal); 3382d4fba8b9Smrg if (norm.font != 0 && !btal.font) { 3383d4fba8b9Smrg noUsableXft(xw, "bold italic"); 3384d4fba8b9Smrg XftPatternDestroy(btal.pattern); 3385d4fba8b9Smrg btal.pattern = XftPatternDuplicate(pat); 3386d4fba8b9Smrg XftPatternBuild(btal.pattern, 3387d4fba8b9Smrg NormXftPattern, 3388d4fba8b9Smrg (void *) 0); 3389d4fba8b9Smrg OPEN_XFT(btal, "bold-italics"); 3390d4fba8b9Smrg failed = 0; 3391d4fba8b9Smrg CACHE_XFT(screen->renderFontBtal, btal); 3392d4fba8b9Smrg } 3393d4fba8b9Smrg#endif 3394d522f475Smrg XftPatternDestroy(pat); 3395d4fba8b9Smrg } else { 3396d4fba8b9Smrg failed = 1; 3397d522f475Smrg } 3398d4fba8b9Smrg#undef OPEN_XFT 3399d522f475Smrg 3400d522f475Smrg /* 3401d4fba8b9Smrg * See xtermXftDrawString(). A separate double-width font is nice 3402d4fba8b9Smrg * to have, but not essential. 3403d522f475Smrg */ 3404d522f475Smrg#if OPT_RENDERWIDE 3405d4fba8b9Smrg if (norm.font != 0 && screen->wide_chars) { 3406d4fba8b9Smrg int char_width = norm.font->max_advance_width * 2; 3407dfb07bc7Smrg double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w) 3408956cc18dSsnj || screen->renderFontNorm[fontnum].map.mixed) 3409956cc18dSsnj ? 1.0 3410956cc18dSsnj : 2.0); 3411d522f475Smrg 341220d2c4d2Smrg face_name = getFaceName(xw, True); 3413d522f475Smrg TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 341420d2c4d2Smrg NonNull(face_name), 3415d522f475Smrg char_width)); 3416d522f475Smrg 3417d522f475Smrg#define WideXftPattern \ 3418d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3419d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size, \ 3420d4fba8b9Smrg XFT_SPACING, XftTypeInteger, XFT_MONO, \ 3421d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, char_width, \ 3422d4fba8b9Smrg FC_ASPECT, XftTypeDouble, aspect 3423d4fba8b9Smrg 3424d4fba8b9Smrg if (!IsEmpty(face_name) && (pat = XftNameParse(face_name)) 3425d4fba8b9Smrg != 0) { 3426d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag) 3427d4fba8b9Smrg wnorm.pattern = XftPatternDuplicate(pat); 3428d4fba8b9Smrg XftPatternBuild(wnorm.pattern, 3429d522f475Smrg WideXftPattern, 3430d522f475Smrg (void *) 0); 3431d4fba8b9Smrg OPEN_XFT(wnorm, "wide"); 3432d522f475Smrg 3433d4fba8b9Smrg if (wnorm.font != 0) { 3434d4fba8b9Smrg wbold.pattern = XftPatternDuplicate(pat); 3435d4fba8b9Smrg XftPatternBuild(wbold.pattern, 3436d522f475Smrg WideXftPattern, 3437d522f475Smrg BoldXftPattern(wnorm), 3438d522f475Smrg (void *) 0); 3439d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3440d522f475Smrg 34419a64e1c5Smrg#if HAVE_ITALICS 34429a64e1c5Smrg if (FIND_ITALICS) { 3443d4fba8b9Smrg wital.pattern = XftPatternDuplicate(pat); 3444d4fba8b9Smrg XftPatternBuild(wital.pattern, 3445d522f475Smrg WideXftPattern, 3446d522f475Smrg ItalXftPattern(wnorm), 3447d522f475Smrg (void *) 0); 3448d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3449d4fba8b9Smrg } 3450d4fba8b9Smrg CACHE_XFT(screen->renderWideBtal, wbtal); 3451d4fba8b9Smrg if (!wbtal.font) { 3452d4fba8b9Smrg noUsableXft(xw, "wide bold"); 3453d4fba8b9Smrg XftPatternDestroy(wbtal.pattern); 3454d4fba8b9Smrg wbtal.pattern = XftPatternDuplicate(pat); 3455d4fba8b9Smrg XftPatternBuild(wbtal.pattern, 3456d4fba8b9Smrg WideXftPattern, 3457d4fba8b9Smrg (void *) 0); 3458d4fba8b9Smrg OPEN_XFT(wbtal, "wide-bold-italics"); 3459d4fba8b9Smrg failed = 0; 3460d4fba8b9Smrg CACHE_XFT(screen->renderWideBtal, wbtal); 3461d522f475Smrg } 3462d522f475Smrg#endif 3463d522f475Smrg } 3464d4fba8b9Smrg 3465d4fba8b9Smrg CACHE_XFT(screen->renderWideNorm, wnorm); 3466d4fba8b9Smrg 3467d4fba8b9Smrg CACHE_XFT(screen->renderWideBold, wbold); 3468d4fba8b9Smrg if (wnorm.font != 0 && !wbold.font) { 3469d4fba8b9Smrg noUsableXft(xw, "wide-bold"); 3470d4fba8b9Smrg XftPatternDestroy(wbold.pattern); 3471d4fba8b9Smrg wbold.pattern = XftPatternDuplicate(pat); 3472d4fba8b9Smrg XftPatternBuild(bold.pattern, 3473d4fba8b9Smrg WideXftPattern, 3474d4fba8b9Smrg (void *) 0); 3475d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3476d4fba8b9Smrg failed = 0; 3477d4fba8b9Smrg CACHE_XFT(screen->renderWideBold, bold); 3478d4fba8b9Smrg } 3479d4fba8b9Smrg 3480d4fba8b9Smrg CACHE_XFT(screen->renderWideItal, wital); 3481d4fba8b9Smrg if (wnorm.font != 0 && !wital.font) { 3482d4fba8b9Smrg noUsableXft(xw, "wide-italic"); 3483d4fba8b9Smrg XftPatternDestroy(wital.pattern); 3484d4fba8b9Smrg wital.pattern = XftPatternDuplicate(pat); 3485d4fba8b9Smrg XftPatternBuild(wital.pattern, 3486d4fba8b9Smrg WideXftPattern, 3487d4fba8b9Smrg (void *) 0); 3488d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3489d4fba8b9Smrg failed = 0; 3490d4fba8b9Smrg CACHE_XFT(screen->renderWideItal, wital); 3491d4fba8b9Smrg } 3492d4fba8b9Smrg 3493d522f475Smrg XftPatternDestroy(pat); 3494d522f475Smrg } 3495d4fba8b9Smrg#undef OPEN_XFT 3496d522f475Smrg } 3497d522f475Smrg#endif /* OPT_RENDERWIDE */ 3498d522f475Smrg } 3499d4fba8b9Smrg if (norm.font == 0) { 35002eaa94a1Schristos TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 35010bd37d32Smrg xw->work.render_font = False; 3502d522f475Smrg update_font_renderfont(); 3503d522f475Smrg /* now we will fall through into the bitmap fonts */ 3504d522f475Smrg } else { 3505d4fba8b9Smrg setBrokenBoxChars(xw, False); 3506d4fba8b9Smrg setRenderFontsize(xw, win, norm.font, NULL); 3507d4fba8b9Smrg setRenderFontsize(xw, win, bold.font, "bold"); 3508d4fba8b9Smrg setRenderFontsize(xw, win, ital.font, "ital"); 3509d4fba8b9Smrg setRenderFontsize(xw, win, btal.font, "btal"); 351020d2c4d2Smrg#if OPT_BOX_CHARS 351120d2c4d2Smrg setupPackedFonts(xw); 351220d2c4d2Smrg 351320d2c4d2Smrg if (screen->force_packed) { 351420d2c4d2Smrg XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 35150bd37d32Smrg SetFontHeight(screen, win, use->font->ascent + use->font->descent); 35160bd37d32Smrg SetFontWidth(screen, win, use->map.min_width); 351720d2c4d2Smrg TRACE(("...packed TrueType font %dx%d vs %d\n", 351820d2c4d2Smrg win->f_height, 351920d2c4d2Smrg win->f_width, 352020d2c4d2Smrg use->map.max_width)); 352120d2c4d2Smrg } 352220d2c4d2Smrg#endif 352320d2c4d2Smrg DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 3524d522f475Smrg } 3525d522f475Smrg } 3526d522f475Smrg /* 3527d522f475Smrg * Are we handling a bitmap font? 3528d522f475Smrg */ 3529492d43a5Smrg else 3530d522f475Smrg#endif /* OPT_RENDERFONT */ 3531d522f475Smrg { 353220d2c4d2Smrg if (is_double_width_font(font) && !(screen->fnt_prop)) { 35330bd37d32Smrg SetFontWidth(screen, win, font->min_bounds.width); 3534d522f475Smrg } else { 35350bd37d32Smrg SetFontWidth(screen, win, font->max_bounds.width); 3536d522f475Smrg } 35370bd37d32Smrg SetFontHeight(screen, win, font->ascent + font->descent); 3538d522f475Smrg win->f_ascent = font->ascent; 3539d522f475Smrg win->f_descent = font->descent; 3540d522f475Smrg } 3541d522f475Smrg i = 2 * screen->border + sbwidth; 3542d522f475Smrg j = 2 * screen->border; 3543d522f475Smrg width = MaxCols(screen) * win->f_width + i; 3544d522f475Smrg height = MaxRows(screen) * win->f_height + j; 3545956cc18dSsnj win->fullwidth = (Dimension) width; 3546956cc18dSsnj win->fullheight = (Dimension) height; 3547d522f475Smrg win->width = width - i; 3548d522f475Smrg win->height = height - j; 3549d522f475Smrg 3550d522f475Smrg TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 3551d522f475Smrg win->height, 3552d522f475Smrg win->width, 3553d522f475Smrg win->fullheight, 3554d522f475Smrg win->fullwidth, 3555d522f475Smrg win->f_height, 3556d522f475Smrg win->f_width, 3557d522f475Smrg win->f_ascent, 3558d522f475Smrg win->f_descent)); 355920d2c4d2Smrg 3560d4fba8b9Smrg checkFontInfo(win->f_height, "height", failed); 3561d4fba8b9Smrg checkFontInfo(win->f_width, "width", failed); 3562d522f475Smrg} 3563d522f475Smrg 3564d522f475Smrg/* save this information as a side-effect for double-sized characters */ 3565d4fba8b9Smrgstatic void 35669a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font) 3567d522f475Smrg{ 3568956cc18dSsnj screen->fnt_wide = (Dimension) (font->max_bounds.width); 3569956cc18dSsnj screen->fnt_high = (Dimension) (font->ascent + font->descent); 3570d522f475Smrg TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 3571d522f475Smrg} 3572d522f475Smrg 3573d522f475Smrg/* 3574d522f475Smrg * After loading a new font, update the structures that use its size. 3575d522f475Smrg */ 3576d522f475Smrgvoid 3577d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize) 3578d522f475Smrg{ 3579956cc18dSsnj TScreen *screen = TScreenOf(xw); 3580d522f475Smrg 3581d522f475Smrg int scrollbar_width; 3582d522f475Smrg VTwin *win = &(screen->fullVwin); 3583d522f475Smrg 3584d4fba8b9Smrg#if USE_DOUBLE_BUFFER 3585d4fba8b9Smrg discardRenderDraw(TScreenOf(xw)); 3586d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */ 3587d4fba8b9Smrg 3588d522f475Smrg scrollbar_width = (xw->misc.scrollbar 3589d522f475Smrg ? (screen->scrollWidget->core.width + 3590d522f475Smrg BorderWidth(screen->scrollWidget)) 3591d522f475Smrg : 0); 3592d4fba8b9Smrg xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width); 3593d4fba8b9Smrg xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs); 3594d522f475Smrg 3595d522f475Smrg if (doresize) { 3596d522f475Smrg if (VWindow(screen)) { 3597d522f475Smrg xtermClear(xw); 3598d522f475Smrg } 3599d4fba8b9Smrg TRACE(("xtermUpdateFontInfo " TRACE_L "\n")); 3600d522f475Smrg DoResizeScreen(xw); /* set to the new natural size */ 3601d522f475Smrg ResizeScrollBar(xw); 3602d522f475Smrg Redraw(); 3603d4fba8b9Smrg TRACE((TRACE_R " xtermUpdateFontInfo\n")); 3604d522f475Smrg#ifdef SCROLLBAR_RIGHT 3605d522f475Smrg updateRightScrollbar(xw); 3606d522f475Smrg#endif 3607d522f475Smrg } 3608d522f475Smrg xtermSetCursorBox(screen); 3609d522f475Smrg} 3610d522f475Smrg 3611fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS 3612d522f475Smrg 3613d522f475Smrg/* 3614d522f475Smrg * Returns true if the given character is missing from the specified font. 3615d522f475Smrg */ 3616d522f475SmrgBool 3617956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font) 3618d522f475Smrg{ 3619956cc18dSsnj Bool result = False; 3620956cc18dSsnj XFontStruct *fs = font->fs; 3621fa3f02f3Smrg XCharStruct *pc = 0; 3622d522f475Smrg 3623d4fba8b9Smrg if (fs == NULL) { 3624d4fba8b9Smrg result = True; 3625d4fba8b9Smrg } else if (fs->max_byte1 == 0) { 3626d522f475Smrg#if OPT_WIDE_CHARS 3627fa3f02f3Smrg if (ch < 256) 3628956cc18dSsnj#endif 3629fa3f02f3Smrg { 3630fa3f02f3Smrg CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc); 3631fa3f02f3Smrg } 3632956cc18dSsnj } 3633d522f475Smrg#if OPT_WIDE_CHARS 3634956cc18dSsnj else { 3635fa3f02f3Smrg unsigned row = (ch >> 8); 3636fa3f02f3Smrg unsigned col = (ch & 0xff); 3637fa3f02f3Smrg CI_GET_CHAR_INFO_2D(fs, row, col, pc); 3638956cc18dSsnj } 3639d522f475Smrg#endif 3640d522f475Smrg 3641fa3f02f3Smrg if (pc == 0 || CI_NONEXISTCHAR(pc)) { 3642c48a5815Smrg TRACE2(("xtermMissingChar %#04x (!exists)\n", ch)); 3643956cc18dSsnj result = True; 3644d522f475Smrg } 3645fa3f02f3Smrg if (ch < KNOWN_MISSING) { 3646956cc18dSsnj font->known_missing[ch] = (Char) (result ? 2 : 1); 3647d522f475Smrg } 3648956cc18dSsnj return result; 3649d522f475Smrg} 3650fa3f02f3Smrg#endif 3651d522f475Smrg 3652fa3f02f3Smrg#if OPT_BOX_CHARS 3653d522f475Smrg/* 3654d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in 3655d522f475Smrg * initialization. 3656d522f475Smrg */ 3657d522f475Smrg#define BOX_HIGH 60 3658d522f475Smrg#define BOX_WIDE 60 3659d522f475Smrg 3660d522f475Smrg#define MID_HIGH (BOX_HIGH/2) 3661d522f475Smrg#define MID_WIDE (BOX_WIDE/2) 3662d522f475Smrg 3663d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10) 3664d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10) 3665d522f475Smrg 3666d522f475Smrg/* 3667d522f475Smrg * ...since we'll scale the values anyway. 3668d522f475Smrg */ 3669d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d) 3670d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width) 3671d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height) 3672e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n) 3673e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n) 3674d522f475Smrg 3675d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 3676d522f475Smrg 3677d522f475Smrg/* 3678d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a 3679d522f475Smrg * line-drawing character). 3680d522f475Smrg */ 3681d522f475Smrgvoid 3682d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params, 3683d522f475Smrg unsigned ch, 3684d522f475Smrg GC gc, 3685d522f475Smrg int x, 3686d522f475Smrg int y, 3687d4fba8b9Smrg int cells, 3688d4fba8b9Smrg Bool xftords) 3689d522f475Smrg{ 3690d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 3691d522f475Smrg /* *INDENT-OFF* */ 3692d522f475Smrg static const short glyph_ht[] = { 3693d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 3694d522f475Smrg SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 3695d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 3696d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3697d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3698d522f475Smrg -1 3699d522f475Smrg }, glyph_ff[] = { 3700d522f475Smrg SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 3701d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 3702d522f475Smrg SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 3703d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3704d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3705d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3706d522f475Smrg -1 3707d522f475Smrg }, glyph_lf[] = { 3708d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 3709d522f475Smrg SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 3710d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3711d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3712d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3713d522f475Smrg -1 3714d522f475Smrg }, glyph_nl[] = { 3715d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 3716d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 3717d522f475Smrg SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3718d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 3719d522f475Smrg SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 3720d522f475Smrg -1 3721d522f475Smrg }, glyph_vt[] = { 3722d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 3723d522f475Smrg SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3724d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3725d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3726d522f475Smrg -1 3727d522f475Smrg }, plus_or_minus[] = 3728d522f475Smrg { 3729d522f475Smrg SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 3730d522f475Smrg SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 3731d522f475Smrg SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 3732d522f475Smrg -1 3733d522f475Smrg }, lower_right_corner[] = 3734d522f475Smrg { 3735d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3736d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 3737d522f475Smrg -1 3738d522f475Smrg }, upper_right_corner[] = 3739d522f475Smrg { 3740d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3741d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3742d522f475Smrg -1 3743d522f475Smrg }, upper_left_corner[] = 3744d522f475Smrg { 3745d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3746d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3747d522f475Smrg -1 3748d522f475Smrg }, lower_left_corner[] = 3749d522f475Smrg { 3750d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3751d522f475Smrg SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 3752d522f475Smrg -1 3753d522f475Smrg }, cross[] = 3754d522f475Smrg { 3755d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3756d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3757d522f475Smrg -1 3758d522f475Smrg }, scan_line_1[] = 3759d522f475Smrg { 3760d522f475Smrg SEG( 0, 0, BOX_WIDE, 0), 3761d522f475Smrg -1 3762d522f475Smrg }, scan_line_3[] = 3763d522f475Smrg { 3764d522f475Smrg SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 3765d522f475Smrg -1 3766d522f475Smrg }, scan_line_7[] = 3767d522f475Smrg { 3768d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3769d522f475Smrg -1 3770d522f475Smrg }, scan_line_9[] = 3771d522f475Smrg { 3772d522f475Smrg SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 3773d522f475Smrg -1 3774d522f475Smrg }, horizontal_line[] = 3775d522f475Smrg { 3776d522f475Smrg SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 3777d522f475Smrg -1 3778d522f475Smrg }, left_tee[] = 3779d522f475Smrg { 3780d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3781d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3782d522f475Smrg -1 3783d522f475Smrg }, right_tee[] = 3784d522f475Smrg { 3785d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3786d522f475Smrg SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 3787d522f475Smrg -1 3788d522f475Smrg }, bottom_tee[] = 3789d522f475Smrg { 3790d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3791d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3792d522f475Smrg -1 3793d522f475Smrg }, top_tee[] = 3794d522f475Smrg { 3795d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3796d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3797d522f475Smrg -1 3798d522f475Smrg }, vertical_line[] = 3799d522f475Smrg { 3800d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3801d522f475Smrg -1 3802d522f475Smrg }, less_than_or_equal[] = 3803d522f475Smrg { 3804d522f475Smrg SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 3805d522f475Smrg SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 3806d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3807d522f475Smrg -1 3808d522f475Smrg }, greater_than_or_equal[] = 3809d522f475Smrg { 3810d522f475Smrg SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3811d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3812d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3813d522f475Smrg -1 3814d522f475Smrg }, greek_pi[] = 3815d522f475Smrg { 3816d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3817d522f475Smrg SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 3818d522f475Smrg SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 3819d522f475Smrg -1 3820d522f475Smrg }, not_equal_to[] = 3821d522f475Smrg { 3822d522f475Smrg SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 3823d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 3824d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3825d522f475Smrg -1 3826d522f475Smrg }; 3827d522f475Smrg 3828d4fba8b9Smrg static const struct { 3829d4fba8b9Smrg const int mode; /* 1=y, 2=x, 3=both */ 3830d4fba8b9Smrg const short *data; 3831d4fba8b9Smrg } lines[] = 3832d522f475Smrg { 3833d4fba8b9Smrg { 0, 0 }, /* 00 (unused) */ 3834d4fba8b9Smrg { 0, 0 }, /* 01 diamond */ 3835d4fba8b9Smrg { 0, 0 }, /* 02 box */ 3836d4fba8b9Smrg { 0, glyph_ht }, /* 03 HT */ 3837d4fba8b9Smrg { 0, glyph_ff }, /* 04 FF */ 3838d4fba8b9Smrg { 0, 0 }, /* 05 CR */ 3839d4fba8b9Smrg { 0, glyph_lf }, /* 06 LF */ 3840d4fba8b9Smrg { 0, 0 }, /* 07 degrees (small circle) */ 3841d4fba8b9Smrg { 3, plus_or_minus }, /* 08 */ 3842d4fba8b9Smrg { 0, glyph_nl }, /* 09 */ 3843d4fba8b9Smrg { 0, glyph_vt }, /* 0A */ 3844d4fba8b9Smrg { 3, lower_right_corner }, /* 0B */ 3845d4fba8b9Smrg { 3, upper_right_corner }, /* 0C */ 3846d4fba8b9Smrg { 3, upper_left_corner }, /* 0D */ 3847d4fba8b9Smrg { 3, lower_left_corner }, /* 0E */ 3848d4fba8b9Smrg { 3, cross }, /* 0F */ 3849d4fba8b9Smrg { 2, scan_line_1 }, /* 10 */ 3850d4fba8b9Smrg { 2, scan_line_3 }, /* 11 */ 3851d4fba8b9Smrg { 2, scan_line_7 }, /* 12 */ 3852d4fba8b9Smrg { 2, scan_line_9 }, /* 13 */ 3853d4fba8b9Smrg { 2, horizontal_line }, /* 14 */ 3854d4fba8b9Smrg { 3, left_tee }, /* 15 */ 3855d4fba8b9Smrg { 3, right_tee }, /* 16 */ 3856d4fba8b9Smrg { 3, bottom_tee }, /* 17 */ 3857d4fba8b9Smrg { 3, top_tee }, /* 18 */ 3858d4fba8b9Smrg { 1, vertical_line }, /* 19 */ 3859d4fba8b9Smrg { 0, less_than_or_equal }, /* 1A */ 3860d4fba8b9Smrg { 0, greater_than_or_equal }, /* 1B */ 3861d4fba8b9Smrg { 0, greek_pi }, /* 1C */ 3862d4fba8b9Smrg { 0, not_equal_to }, /* 1D */ 3863d4fba8b9Smrg { 0, 0 }, /* 1E LB */ 3864d4fba8b9Smrg { 0, 0 }, /* 1F bullet */ 3865d522f475Smrg }; 3866d4fba8b9Smrg /* *INDENT-ON* */ 3867d522f475Smrg 3868d522f475Smrg GC gc2; 3869d522f475Smrg CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 3870d522f475Smrg VTwin *cgsWin = WhichVWin(screen); 3871d522f475Smrg const short *p; 3872d4fba8b9Smrg unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U) 3873d4fba8b9Smrg * screen->fnt_wide); 3874d4fba8b9Smrg unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U) 3875d4fba8b9Smrg * screen->fnt_high); 3876d522f475Smrg 3877d522f475Smrg if (cells > 1) 3878956cc18dSsnj font_width *= (unsigned) cells; 3879d522f475Smrg 3880d522f475Smrg#if OPT_WIDE_CHARS 3881d522f475Smrg /* 3882d522f475Smrg * Try to show line-drawing characters if we happen to be in UTF-8 3883d522f475Smrg * mode, but have gotten an old-style font. 3884d522f475Smrg */ 3885d522f475Smrg if (screen->utf8_mode 3886d522f475Smrg#if OPT_RENDERFONT 3887d4fba8b9Smrg && !UsingRenderFont(params->xw) 3888d522f475Smrg#endif 3889d522f475Smrg && (ch > 127) 3890d522f475Smrg && (ch != UCS_REPL)) { 3891d4fba8b9Smrg int which = (params->attr_flags & BOLD) ? fBold : fNorm; 3892d522f475Smrg unsigned n; 3893d522f475Smrg for (n = 1; n < 32; n++) { 3894d4fba8b9Smrg if (xtermMissingChar(n, getNormalFont(screen, which))) 3895d4fba8b9Smrg continue; 3896d4fba8b9Smrg if (dec2ucs(screen, n) != ch) 3897d4fba8b9Smrg continue; 3898d4fba8b9Smrg TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n)); 3899d4fba8b9Smrg ch = n; 3900d4fba8b9Smrg break; 3901d522f475Smrg } 3902d522f475Smrg } 3903d522f475Smrg#endif 3904d522f475Smrg 3905d4fba8b9Smrg#if OPT_VT52_MODE 3906d4fba8b9Smrg if (!(screen->vtXX_level)) { 3907d4fba8b9Smrg switch (ch) { 3908d4fba8b9Smrg case 6: 3909d4fba8b9Smrg ch = 7; 3910d4fba8b9Smrg break; 3911d4fba8b9Smrg default: 3912d4fba8b9Smrg ch = 256; 3913d4fba8b9Smrg break; 3914d4fba8b9Smrg } 3915d4fba8b9Smrg } 3916d4fba8b9Smrg#endif 3917d4fba8b9Smrg 3918d4fba8b9Smrg /* 3919d4fba8b9Smrg * Line-drawing characters show use the full (scaled) cellsize, while 3920d4fba8b9Smrg * other characters should be shifted to center them vertically. 3921d4fba8b9Smrg */ 3922d4fba8b9Smrg if (!xftords) { 3923d4fba8b9Smrg if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) { 3924d4fba8b9Smrg font_height = (unsigned) ((float) font_height * screen->scale_height); 3925d4fba8b9Smrg } else { 3926d4fba8b9Smrg y += ScaleShift(screen); 3927d4fba8b9Smrg } 3928d4fba8b9Smrg } 3929d4fba8b9Smrg 3930d4fba8b9Smrg TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n", 3931d522f475Smrg ch, font_height, font_width, y, x, 3932d4fba8b9Smrg ((ch >= XtNumber(lines)) 3933d522f475Smrg ? "-BAD" 3934d522f475Smrg : ""))); 3935d522f475Smrg 3936d522f475Smrg if (cgsId == gcDots) { 3937d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 3938d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 3939d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3940d522f475Smrg } else { 3941d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 3942d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3943d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3944d522f475Smrg } 3945d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 3946d522f475Smrg 3947d4fba8b9Smrg if (!(params->draw_flags & NOBACKGROUND)) { 39480bd37d32Smrg XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 3949d522f475Smrg font_width, 3950d522f475Smrg font_height); 3951d522f475Smrg } 3952d522f475Smrg 3953d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 3954d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 3955d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 3956d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 3957d522f475Smrg 3958d522f475Smrg XSetLineAttributes(screen->display, gc2, 3959d4fba8b9Smrg (params->attr_flags & BOLD) 3960d522f475Smrg ? ((font_height > 12) 3961d522f475Smrg ? font_height / 12 3962d522f475Smrg : 1) 3963d522f475Smrg : ((font_height > 16) 3964d522f475Smrg ? font_height / 16 3965d522f475Smrg : 1), 3966d522f475Smrg LineSolid, 3967d522f475Smrg CapProjecting, 3968d522f475Smrg JoinMiter); 3969d522f475Smrg 3970d522f475Smrg if (ch == 1) { /* diamond */ 3971d522f475Smrg XPoint points[5]; 3972d522f475Smrg int npoints = 5, n; 3973d522f475Smrg 3974d522f475Smrg points[0].x = MID_WIDE; 3975d522f475Smrg points[0].y = BOX_HIGH / 4; 3976d522f475Smrg 3977d522f475Smrg points[1].x = 8 * BOX_WIDE / 8; 3978d522f475Smrg points[1].y = MID_HIGH; 3979d522f475Smrg 3980d522f475Smrg points[2].x = points[0].x; 3981d522f475Smrg points[2].y = 3 * BOX_HIGH / 4; 3982d522f475Smrg 3983d522f475Smrg points[3].x = 0 * BOX_WIDE / 8; 3984d522f475Smrg points[3].y = points[1].y; 3985d522f475Smrg 3986d522f475Smrg points[4].x = points[0].x; 3987d522f475Smrg points[4].y = points[0].y; 3988d522f475Smrg 3989d522f475Smrg for (n = 0; n < npoints; ++n) { 3990d4fba8b9Smrg points[n].x = (short) (SCALED_X(points[n].x)); 3991d4fba8b9Smrg points[n].y = (short) (SCALED_Y(points[n].y)); 3992e39b573cSmrg points[n].x = (short) (points[n].x + x); 3993e39b573cSmrg points[n].y = (short) (points[n].y + y); 3994d522f475Smrg } 3995d522f475Smrg 3996d522f475Smrg XFillPolygon(screen->display, 39970bd37d32Smrg VDrawable(screen), gc2, 3998d522f475Smrg points, npoints, 3999d522f475Smrg Convex, CoordModeOrigin); 4000d522f475Smrg } else if (ch == 7) { /* degrees */ 4001d522f475Smrg unsigned width = (BOX_WIDE / 3); 4002956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 2); 4003956cc18dSsnj int y_coord = MID_HIGH - (int) width; 4004d522f475Smrg 4005d522f475Smrg SCALE_X(x_coord); 4006d522f475Smrg SCALE_Y(y_coord); 4007e39b573cSmrg width = (unsigned) SCALED_X(width); 4008d522f475Smrg 4009d522f475Smrg XDrawArc(screen->display, 40100bd37d32Smrg VDrawable(screen), gc2, 4011d522f475Smrg x + x_coord, y + y_coord, width, width, 4012d522f475Smrg 0, 4013d522f475Smrg 360 * 64); 4014d522f475Smrg } else if (ch == 0x1f) { /* bullet */ 4015d522f475Smrg unsigned width = 7 * BOX_WIDE / 10; 4016956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 3); 4017956cc18dSsnj int y_coord = MID_HIGH - (int) (width / 3); 4018d522f475Smrg 4019d522f475Smrg SCALE_X(x_coord); 4020d522f475Smrg SCALE_Y(y_coord); 4021e39b573cSmrg width = (unsigned) SCALED_X(width); 4022d522f475Smrg 4023d522f475Smrg XDrawArc(screen->display, 40240bd37d32Smrg VDrawable(screen), gc2, 4025d522f475Smrg x + x_coord, y + y_coord, width, width, 4026d522f475Smrg 0, 4027d522f475Smrg 360 * 64); 4028d4fba8b9Smrg } else if (ch < XtNumber(lines) 4029d4fba8b9Smrg && (p = lines[ch].data) != 0) { 4030956cc18dSsnj int coord[4]; 4031d522f475Smrg int n = 0; 4032d522f475Smrg while (*p >= 0) { 4033d522f475Smrg coord[n++] = *p++; 4034d522f475Smrg if (n == 4) { 4035d522f475Smrg SCALE_X(coord[0]); 4036d522f475Smrg SCALE_Y(coord[1]); 4037d522f475Smrg SCALE_X(coord[2]); 4038d522f475Smrg SCALE_Y(coord[3]); 4039d522f475Smrg XDrawLine(screen->display, 40400bd37d32Smrg VDrawable(screen), gc2, 4041d522f475Smrg x + coord[0], y + coord[1], 4042d522f475Smrg x + coord[2], y + coord[3]); 4043d522f475Smrg n = 0; 4044d522f475Smrg } 4045d522f475Smrg } 4046d522f475Smrg } else if (screen->force_all_chars) { 4047d522f475Smrg /* bounding rectangle, for debugging */ 40480bd37d32Smrg XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y, 4049d522f475Smrg font_width - 1, 4050d522f475Smrg font_height - 1); 4051d522f475Smrg } 4052d522f475Smrg} 4053fa3f02f3Smrg#endif /* OPT_BOX_CHARS */ 4054d522f475Smrg 4055d522f475Smrg#if OPT_RENDERFONT 4056d4fba8b9Smrg/* 4057d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out 4058d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline. 4059d4fba8b9Smrg */ 4060d4fba8b9Smrgstatic Boolean 4061d4fba8b9SmrgfoundXftGlyph(XtermWidget xw, XftFont *font, unsigned wc) 4062d4fba8b9Smrg{ 4063d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4064d4fba8b9Smrg Boolean result = False; 4065d4fba8b9Smrg 4066d4fba8b9Smrg if (font != 0 && XftGlyphExists(screen->display, font, wc)) { 4067d4fba8b9Smrg int expect; 4068d4fba8b9Smrg 4069c48a5815Smrg if ((expect = CharWidth(screen, wc)) > 0) { 4070d4fba8b9Smrg XGlyphInfo gi; 4071d4fba8b9Smrg int actual; 4072d4fba8b9Smrg 4073d4fba8b9Smrg XftTextExtents32(screen->display, font, &wc, 1, &gi); 4074d4fba8b9Smrg /* 4075d4fba8b9Smrg * Some (more than a few) fonts are sloppy; allow 10% outside 4076d4fba8b9Smrg * the bounding box to accommodate them. 4077d4fba8b9Smrg */ 4078d4fba8b9Smrg actual = ((gi.xOff * 10) >= (11 * FontWidth(screen))) ? 2 : 1; 4079d4fba8b9Smrg if (actual <= expect) { 4080d4fba8b9Smrg /* allow double-cell if wcwidth agrees */ 4081d4fba8b9Smrg result = True; 4082d4fba8b9Smrg } else { 4083d4fba8b9Smrg TRACE(("SKIP U+%04X %d vs %d (%d vs %d)\n", 4084d4fba8b9Smrg wc, gi.xOff, FontWidth(screen), actual, expect)); 4085d4fba8b9Smrg } 4086d4fba8b9Smrg } else { 4087d4fba8b9Smrg result = True; 4088d4fba8b9Smrg } 4089d4fba8b9Smrg } 4090d4fba8b9Smrg return result; 4091d4fba8b9Smrg} 4092d4fba8b9Smrg 4093d4fba8b9Smrgstatic void 4094d4fba8b9SmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, Cardinal n, unsigned wc) 4095d4fba8b9Smrg{ 4096d4fba8b9Smrg if (which->cache[n].usage != xcOpened) { 4097d4fba8b9Smrg which->opened++; 4098d4fba8b9Smrg which->cache[n].usage = xcOpened; 4099d4fba8b9Smrg /* XFT_DEBUG=3 will show useful context for this */ 4100d4fba8b9Smrg if (getenv("XFT_DEBUG") != 0) { 4101d4fba8b9Smrg printf("xterm: matched U+%04X in fontset #%d [%u:%u]\n", 4102d4fba8b9Smrg wc, n + 1, 4103d4fba8b9Smrg which->opened, 4104d4fba8b9Smrg xw->work.max_fontsets); 4105d4fba8b9Smrg } 4106d4fba8b9Smrg } 4107d4fba8b9Smrg} 4108d4fba8b9Smrg 4109d4fba8b9Smrg/* 4110d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4111d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph. 4112d4fba8b9Smrg */ 4113d4fba8b9SmrgXftFont * 4114d4fba8b9SmrgfindXftGlyph(XtermWidget xw, XftFont *given, unsigned wc) 4115d4fba8b9Smrg{ 4116d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4117d4fba8b9Smrg XTermXftFonts *which = 0; 4118d4fba8b9Smrg XftFont *result = 0; 4119d4fba8b9Smrg /* workaround for interface changes... */ 4120d4fba8b9Smrg int fontnum = screen->menu_font_number; 4121d4fba8b9Smrg static int table[] = 4122d4fba8b9Smrg { 4123d4fba8b9Smrg offsetof(TScreen, renderFontNorm), 4124d4fba8b9Smrg offsetof(TScreen, renderFontBold), 4125d4fba8b9Smrg offsetof(TScreen, renderFontItal), 4126d4fba8b9Smrg offsetof(TScreen, renderFontBtal), 4127d4fba8b9Smrg#if OPT_RENDERWIDE 4128d4fba8b9Smrg offsetof(TScreen, renderWideNorm), 4129d4fba8b9Smrg offsetof(TScreen, renderWideBold), 4130d4fba8b9Smrg offsetof(TScreen, renderWideItal), 4131d4fba8b9Smrg offsetof(TScreen, renderWideBtal), 4132d4fba8b9Smrg#endif 4133d4fba8b9Smrg }; 4134d4fba8b9Smrg Cardinal n; 4135d4fba8b9Smrg FcResult status; 4136d4fba8b9Smrg const char *tag = 0; 4137d4fba8b9Smrg 4138d4fba8b9Smrg /* if fontsets are not wanted, just leave */ 4139d4fba8b9Smrg if (xw->work.max_fontsets == 0) { 4140d4fba8b9Smrg return 0; 4141d4fba8b9Smrg } 4142d4fba8b9Smrg 4143d4fba8b9Smrg /* ignore codes in private use areas */ 4144d4fba8b9Smrg if ((wc >= 0xe000 && wc <= 0xf8ff) 4145d4fba8b9Smrg || (wc >= 0xf0000 && wc <= 0xffffd) 4146d4fba8b9Smrg || (wc >= 0x100000 && wc <= 0x10fffd)) { 4147d4fba8b9Smrg return 0; 4148d4fba8b9Smrg } 4149d4fba8b9Smrg /* the end of the BMP is reserved for non-characters */ 4150d4fba8b9Smrg if (wc >= 0xfff0 && wc <= 0xffff) { 4151d4fba8b9Smrg return 0; 4152d4fba8b9Smrg } 4153d4fba8b9Smrg 4154d4fba8b9Smrg for (n = 0; n < XtNumber(table); ++n) { 4155d4fba8b9Smrg XTermXftFonts *check = (XTermXftFonts *) ((void *) ((char *) screen 4156d4fba8b9Smrg + table[n])); 4157d4fba8b9Smrg if (check[fontnum].font == given) { 4158d4fba8b9Smrg which = &check[fontnum]; 4159d4fba8b9Smrg tag = whichFontEnum((VTFontEnum) n); 4160d4fba8b9Smrg break; 4161d4fba8b9Smrg } 4162d4fba8b9Smrg } 4163d4fba8b9Smrg if (which != 0) { 4164d4fba8b9Smrg if (which->fontset == 0) { 4165d4fba8b9Smrg FcFontSet *sortedFonts; 4166d4fba8b9Smrg FcPattern *myPattern; 4167d4fba8b9Smrg int j; 4168d4fba8b9Smrg 4169d4fba8b9Smrg myPattern = FcPatternDuplicate(which->pattern); 4170d4fba8b9Smrg 4171d4fba8b9Smrg FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4172d4fba8b9Smrg FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4173d4fba8b9Smrg 4174d4fba8b9Smrg FcConfigSubstitute(FcConfigGetCurrent(), 4175d4fba8b9Smrg myPattern, 4176d4fba8b9Smrg FcMatchPattern); 4177d4fba8b9Smrg FcDefaultSubstitute(myPattern); 4178d4fba8b9Smrg 4179d4fba8b9Smrg which->fontset = FcFontSetCreate(); 4180d4fba8b9Smrg 4181d4fba8b9Smrg sortedFonts = FcFontSort(0, myPattern, FcTrue, 0, &status); 4182d4fba8b9Smrg 4183d4fba8b9Smrg if (!sortedFonts || sortedFonts->nfont <= 0) { 4184d4fba8b9Smrg xtermWarning("did not find any usable TrueType font\n"); 4185d4fba8b9Smrg return 0; 4186d4fba8b9Smrg } 4187d4fba8b9Smrg which->limit = (unsigned) sortedFonts->nfont; 4188d4fba8b9Smrg which->cache = TypeCallocN(XTermXftCache, (which->limit + 1)); 4189d4fba8b9Smrg for (j = 0; j < sortedFonts->nfont; j++) { 4190d4fba8b9Smrg FcPattern *font_pattern; 4191d4fba8b9Smrg 4192d4fba8b9Smrg font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(), 4193d4fba8b9Smrg myPattern, 4194d4fba8b9Smrg sortedFonts->fonts[j]); 4195d4fba8b9Smrg if (font_pattern) 4196d4fba8b9Smrg FcFontSetAdd(which->fontset, font_pattern); 4197d4fba8b9Smrg } 4198d4fba8b9Smrg 4199d4fba8b9Smrg FcFontSetSortDestroy(sortedFonts); 4200d4fba8b9Smrg FcPatternDestroy(myPattern); 4201d4fba8b9Smrg } 4202d4fba8b9Smrg if (which->fontset != 0) { 4203d4fba8b9Smrg XftFont *check; 4204d4fba8b9Smrg Cardinal empty = which->limit; 4205d4fba8b9Smrg 4206d4fba8b9Smrg for (n = 0; n < which->limit; ++n) { 4207d4fba8b9Smrg XftCache usage = which->cache[n].usage; 4208d4fba8b9Smrg if (usage == xcEmpty) { 4209d4fba8b9Smrg if (empty > n) 4210d4fba8b9Smrg empty = n; 4211d4fba8b9Smrg } else if (usage == xcOpened 4212d4fba8b9Smrg || (usage == xcUnused 4213d4fba8b9Smrg && (which->opened < xw->work.max_fontsets))) { 4214d4fba8b9Smrg check = which->cache[n].font; 4215d4fba8b9Smrg if (foundXftGlyph(xw, check, wc)) { 4216d4fba8b9Smrg markXftOpened(xw, which, n, wc); 4217d4fba8b9Smrg result = check; 4218d4fba8b9Smrg TRACE_FALLBACK(xw, "old", wc, (int) n, result); 4219d4fba8b9Smrg break; 4220d4fba8b9Smrg } 4221d4fba8b9Smrg } 4222d4fba8b9Smrg } 4223d4fba8b9Smrg 4224d4fba8b9Smrg if ((result == 0) 4225d4fba8b9Smrg && (empty < which->limit) 4226d4fba8b9Smrg && (which->opened < xw->work.max_fontsets)) { 4227d4fba8b9Smrg FcPattern *myPattern = 0; 4228d4fba8b9Smrg FcPattern *myReport = 0; 4229d4fba8b9Smrg 4230d4fba8b9Smrg for (n = empty; n < which->limit; ++n) { 4231d4fba8b9Smrg if (which->cache[n].usage >= xcBogus) 4232d4fba8b9Smrg continue; 4233d4fba8b9Smrg if (resource.reportFonts) { 4234d4fba8b9Smrg myReport = FcPatternDuplicate(which->fontset->fonts[n]); 4235d4fba8b9Smrg } 4236d4fba8b9Smrg myPattern = FcPatternDuplicate(which->fontset->fonts[n]); 4237d4fba8b9Smrg check = XftFontOpenPattern(screen->display, myPattern); 4238d4fba8b9Smrg closeCachedXft(screen, which->cache[n].font); 4239d4fba8b9Smrg (void) maybeXftCache(xw, check); 4240d4fba8b9Smrg which->cache[n].font = check; 4241d4fba8b9Smrg which->cache[n].usage = xcBogus; 4242d4fba8b9Smrg if (check == 0) 4243d4fba8b9Smrg continue; /* shouldn't happen... */ 4244d4fba8b9Smrg#ifdef FC_COLOR 4245d4fba8b9Smrg if (isBogusXft(check)) { 4246d4fba8b9Smrg continue; 4247d4fba8b9Smrg } 4248d4fba8b9Smrg#endif 4249d4fba8b9Smrg if (foundXftGlyph(xw, check, wc)) { 4250d4fba8b9Smrg markXftOpened(xw, which, n, wc); 4251d4fba8b9Smrg reportXftFonts(xw, check, "fallback", tag, myReport); 4252d4fba8b9Smrg result = check; 4253d4fba8b9Smrg TRACE_FALLBACK(xw, "new", wc, (int) n, result); 4254d4fba8b9Smrg break; 4255d4fba8b9Smrg } 4256d4fba8b9Smrg /* 4257d4fba8b9Smrg * The slot is opened, but we are not using it. 4258d4fba8b9Smrg */ 4259d4fba8b9Smrg which->cache[n].usage = xcUnused; 4260d4fba8b9Smrg } 4261d4fba8b9Smrg } 4262d4fba8b9Smrg } 4263d4fba8b9Smrg } 4264d4fba8b9Smrg return result; 4265d4fba8b9Smrg} 4266d522f475Smrg 4267d522f475Smrg/* 4268d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4269d4fba8b9Smrg * return true. 4270d522f475Smrg * 4271d522f475Smrg * see xc/lib/Xft/xftglyphs.c 4272d522f475Smrg */ 4273d522f475SmrgBool 42749a64e1c5SmrgxtermXftMissing(XtermWidget xw, XftFont *font, unsigned wc) 4275d522f475Smrg{ 4276d522f475Smrg Bool result = False; 4277d522f475Smrg 4278d522f475Smrg if (font != 0) { 4279956cc18dSsnj TScreen *screen = TScreenOf(xw); 4280956cc18dSsnj if (!XftGlyphExists(screen->display, font, wc)) { 4281d522f475Smrg#if OPT_WIDE_CHARS 4282dfb07bc7Smrg TRACE2(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 4283d4fba8b9Smrg wc, ucs2dec(screen, wc), dec2ucs(screen, wc))); 4284d522f475Smrg#else 4285dfb07bc7Smrg TRACE2(("xtermXftMissing %d\n", wc)); 4286d522f475Smrg#endif 4287d522f475Smrg result = True; 4288d522f475Smrg } 4289d522f475Smrg } 4290d522f475Smrg return result; 4291d522f475Smrg} 4292fa3f02f3Smrg#endif /* OPT_RENDERFONT */ 4293d522f475Smrg 4294d522f475Smrg#if OPT_WIDE_CHARS 4295d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break 4296d522f475Smrgunsigned 4297d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch) 4298d522f475Smrg{ 4299d522f475Smrg unsigned result = ch; 4300d4fba8b9Smrg 4301d4fba8b9Smrg (void) screen; 4302d522f475Smrg if ((ch > 127) 4303d522f475Smrg && (ch != UCS_REPL)) { 4304d4fba8b9Smrg#if OPT_VT52_MODE 4305d4fba8b9Smrg if (screen != 0 && !(screen->vtXX_level)) { 4306d4fba8b9Smrg /* 4307d4fba8b9Smrg * Intentionally empty: it would be possible to use the built-in 4308d4fba8b9Smrg * line-drawing fallback in xtermDrawBoxChar(), but for testing 4309d4fba8b9Smrg * ncurses, this is good enough. 4310d4fba8b9Smrg */ 4311d4fba8b9Smrg ; 4312d4fba8b9Smrg } else 4313d4fba8b9Smrg#endif 4314d4fba8b9Smrg switch (ch) { 4315d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4316d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4317d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4318d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4319d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4320d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4321d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4322d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4323d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4324d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4325d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4326d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4327d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4328d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4329d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4330d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4331d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4332d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4333d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4334d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4335d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4336d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4337d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4338d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4339d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4340d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4341d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4342d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4343d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4344d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4345d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4346d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4347d4fba8b9Smrg } 4348d522f475Smrg } 4349d522f475Smrg return result; 4350d522f475Smrg} 4351d522f475Smrg 4352d522f475Smrg#undef MY_UCS 4353d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break 4354d522f475Smrg 4355d522f475Smrgunsigned 4356d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch) 4357d522f475Smrg{ 4358d522f475Smrg unsigned result = ch; 4359d4fba8b9Smrg 4360d4fba8b9Smrg (void) screen; 4361d522f475Smrg if (xtermIsDecGraphic(ch)) { 4362d4fba8b9Smrg#if OPT_VT52_MODE 4363d4fba8b9Smrg if (screen != 0 && !(screen->vtXX_level)) { 4364d4fba8b9Smrg switch (ch) { 4365d4fba8b9Smrg MY_UCS(0x0020, 0); /* nbsp, treat as blank */ 4366d4fba8b9Smrg MY_UCS(0x0020, 1); /* reserved, treat as blank */ 4367d4fba8b9Smrg MY_UCS(0x25ae, 2); /* black vertical rectangle */ 4368d4fba8b9Smrg MY_UCS(0x215f, 3); /* "1/" */ 4369d4fba8b9Smrg MY_UCS(0x0020, 4); /* "3/", not in Unicode, ignore */ 4370d4fba8b9Smrg MY_UCS(0x0020, 5); /* "5/", not in Unicode, ignore */ 4371d4fba8b9Smrg MY_UCS(0x0020, 6); /* "7/", not in Unicode, ignore */ 4372d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4373d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4374d4fba8b9Smrg MY_UCS(0x2192, 9); /* right-arrow */ 4375d4fba8b9Smrg MY_UCS(0x2026, 10); /* ellipsis */ 4376d4fba8b9Smrg MY_UCS(0x00f7, 11); /* divide by */ 4377d4fba8b9Smrg MY_UCS(0x2193, 12); /* down arrow */ 4378d4fba8b9Smrg MY_UCS(0x23ba, 13); /* bar at scan 0 */ 4379d4fba8b9Smrg MY_UCS(0x23ba, 14); /* bar at scan 1 */ 4380d4fba8b9Smrg MY_UCS(0x23bb, 15); /* bar at scan 2 */ 4381d4fba8b9Smrg MY_UCS(0x23bb, 16); /* bar at scan 3 */ 4382d4fba8b9Smrg MY_UCS(0x23bc, 17); /* bar at scan 4 */ 4383d4fba8b9Smrg MY_UCS(0x23bc, 18); /* bar at scan 5 */ 4384d4fba8b9Smrg MY_UCS(0x23bd, 19); /* bar at scan 6 */ 4385d4fba8b9Smrg MY_UCS(0x23bd, 20); /* bar at scan 7 */ 4386d4fba8b9Smrg MY_UCS(0x2080, 21); /* subscript 0 */ 4387d4fba8b9Smrg MY_UCS(0x2081, 22); /* subscript 1 */ 4388d4fba8b9Smrg MY_UCS(0x2082, 23); /* subscript 2 */ 4389d4fba8b9Smrg MY_UCS(0x2083, 24); /* subscript 3 */ 4390d4fba8b9Smrg MY_UCS(0x2084, 25); /* subscript 4 */ 4391d4fba8b9Smrg MY_UCS(0x2085, 26); /* subscript 5 */ 4392d4fba8b9Smrg MY_UCS(0x2086, 27); /* subscript 6 */ 4393d4fba8b9Smrg MY_UCS(0x2087, 28); /* subscript 7 */ 4394d4fba8b9Smrg MY_UCS(0x2088, 29); /* subscript 8 */ 4395d4fba8b9Smrg MY_UCS(0x2089, 30); /* subscript 9 */ 4396d4fba8b9Smrg MY_UCS(0x00b6, 31); /* paragraph */ 4397d4fba8b9Smrg } 4398d4fba8b9Smrg } else 4399d4fba8b9Smrg#endif 4400d4fba8b9Smrg switch (ch) { 4401d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4402d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4403d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4404d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4405d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4406d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4407d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4408d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4409d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4410d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4411d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4412d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4413d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4414d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4415d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4416d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4417d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4418d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4419d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4420d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4421d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4422d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4423d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4424d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4425d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4426d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4427d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4428d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4429d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4430d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4431d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4432d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4433d4fba8b9Smrg } 4434d522f475Smrg } 4435d522f475Smrg return result; 4436d522f475Smrg} 4437d522f475Smrg 4438d522f475Smrg#endif /* OPT_WIDE_CHARS */ 4439d522f475Smrg 4440b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS 44410bd37d32Smrgstatic int 4442d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum) 4443d522f475Smrg{ 4444d522f475Smrg TScreen *screen = TScreenOf(xw); 4445d522f475Smrg 4446d522f475Smrg if (screen->menu_font_sizes[fontnum] == 0) { 4447d522f475Smrg XTermFonts fnt; 4448d522f475Smrg 4449d522f475Smrg memset(&fnt, 0, sizeof(fnt)); 4450d522f475Smrg screen->menu_font_sizes[fontnum] = -1; 4451dfb07bc7Smrg if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, True)) { 445220d2c4d2Smrg if (fontnum <= fontMenu_lastBuiltin 44530bd37d32Smrg || strcmp(fnt.fn, DEFFONT)) { 445420d2c4d2Smrg screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 44550bd37d32Smrg if (screen->menu_font_sizes[fontnum] <= 0) 44560bd37d32Smrg screen->menu_font_sizes[fontnum] = -1; 44570bd37d32Smrg } 4458d522f475Smrg xtermCloseFont(xw, &fnt); 4459d522f475Smrg } 4460d522f475Smrg } 44610bd37d32Smrg return (screen->menu_font_sizes[fontnum] > 0); 4462d522f475Smrg} 4463d522f475Smrg 4464d522f475Smrg/* 4465d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 4466d522f475Smrg */ 4467d522f475Smrgstatic void 4468d522f475SmrglookupFontSizes(XtermWidget xw) 4469d522f475Smrg{ 4470d522f475Smrg int n; 4471d522f475Smrg 4472d522f475Smrg for (n = 0; n < NMENUFONTS; n++) { 44730bd37d32Smrg (void) lookupOneFontSize(xw, n); 4474d522f475Smrg } 4475d522f475Smrg} 4476b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 4477d522f475Smrg 44782eaa94a1Schristos#if OPT_RENDERFONT 44799a64e1c5Smrgstatic double 44809a64e1c5SmrgdefaultFaceSize(void) 44819a64e1c5Smrg{ 44829a64e1c5Smrg double result; 44839a64e1c5Smrg float value; 44849a64e1c5Smrg 44859a64e1c5Smrg if (sscanf(DEFFACESIZE, "%f", &value) == 1) 4486d4fba8b9Smrg result = (double) value; 44879a64e1c5Smrg else 44889a64e1c5Smrg result = 14.0; 44899a64e1c5Smrg return result; 44909a64e1c5Smrg} 44919a64e1c5Smrg 44920bd37d32Smrgstatic void 44930bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum) 44940bd37d32Smrg{ 44950bd37d32Smrg TScreen *screen = TScreenOf(xw); 4496d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 44970bd37d32Smrg 44980bd37d32Smrg if (face_size <= 0.0) { 44990bd37d32Smrg#if OPT_SHIFT_FONTS 45000bd37d32Smrg /* 45010bd37d32Smrg * If the user is switching font-sizes, make it follow by 45020bd37d32Smrg * default the same ratios to the default as the fixed fonts 45030bd37d32Smrg * would, for easy comparison. There will be some differences 45040bd37d32Smrg * since the fixed fonts have a variety of height/width ratios, 45050bd37d32Smrg * but this is simpler than adding another resource value - and 45060bd37d32Smrg * as noted above, the data for the fixed fonts are available. 45070bd37d32Smrg */ 45080bd37d32Smrg (void) lookupOneFontSize(xw, 0); 45090bd37d32Smrg if (fontnum == fontMenu_default) { 45109a64e1c5Smrg face_size = defaultFaceSize(); 45110bd37d32Smrg } else if (lookupOneFontSize(xw, fontnum) 45120bd37d32Smrg && (screen->menu_font_sizes[0] 45130bd37d32Smrg != screen->menu_font_sizes[fontnum])) { 45140bd37d32Smrg double ratio; 45150bd37d32Smrg long num = screen->menu_font_sizes[fontnum]; 45160bd37d32Smrg long den = screen->menu_font_sizes[0]; 45170bd37d32Smrg 45180bd37d32Smrg if (den <= 0) 45190bd37d32Smrg den = 1; 45200bd37d32Smrg ratio = dimSquareRoot((double) num / (double) den); 45210bd37d32Smrg 4522d4fba8b9Smrg face_size = (ratio * (double) xw->misc.face_size[0]); 45230bd37d32Smrg TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 45240bd37d32Smrg fontnum, num, den, ratio, face_size)); 45250bd37d32Smrg } else 45260bd37d32Smrg#endif 45270bd37d32Smrg { 4528d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default]) 45290bd37d32Smrg switch (fontnum) { 45300bd37d32Smrg case fontMenu_font1: 45310bd37d32Smrg face_size = LikeBitmap(2.0); 45320bd37d32Smrg break; 45330bd37d32Smrg case fontMenu_font2: 45340bd37d32Smrg face_size = LikeBitmap(35.0); 45350bd37d32Smrg break; 45360bd37d32Smrg case fontMenu_font3: 45370bd37d32Smrg face_size = LikeBitmap(60.0); 45380bd37d32Smrg break; 45390bd37d32Smrg default: 45409a64e1c5Smrg face_size = defaultFaceSize(); 45410bd37d32Smrg break; 45420bd37d32Smrg case fontMenu_font4: 45430bd37d32Smrg face_size = LikeBitmap(90.0); 45440bd37d32Smrg break; 45450bd37d32Smrg case fontMenu_font5: 45460bd37d32Smrg face_size = LikeBitmap(135.0); 45470bd37d32Smrg break; 45480bd37d32Smrg case fontMenu_font6: 45490bd37d32Smrg face_size = LikeBitmap(200.0); 45500bd37d32Smrg break; 4551d4fba8b9Smrg case fontMenu_font7: 4552d4fba8b9Smrg face_size = LikeBitmap(240.0); 4553d4fba8b9Smrg break; 45540bd37d32Smrg } 45550bd37d32Smrg TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 45560bd37d32Smrg } 45570bd37d32Smrg xw->misc.face_size[fontnum] = (float) face_size; 45580bd37d32Smrg } 45590bd37d32Smrg} 45600bd37d32Smrg 45610bd37d32Smrg/* no selection or escape */ 45620bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 45630bd37d32Smrg 45640bd37d32Smrg/* 45650bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font 45660bd37d32Smrg * sizes are the same, and if we're using TrueType fonts. 45670bd37d32Smrg */ 45682eaa94a1Schristosstatic Boolean 45692eaa94a1SchristosuseFaceSizes(XtermWidget xw) 45702eaa94a1Schristos{ 45712eaa94a1Schristos Boolean result = False; 45722eaa94a1Schristos 4573d4fba8b9Smrg TRACE(("useFaceSizes " TRACE_L "\n")); 45742eaa94a1Schristos if (UsingRenderFont(xw)) { 45750bd37d32Smrg Boolean nonzero = True; 4576037a25ddSmrg int n; 45770bd37d32Smrg 45782eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 4579d4fba8b9Smrg if (xw->misc.face_size[n] <= 0.0f) { 45800bd37d32Smrg nonzero = False; 45812eaa94a1Schristos break; 45822eaa94a1Schristos } 45832eaa94a1Schristos } 45840bd37d32Smrg if (!nonzero) { 4585956cc18dSsnj Boolean broken_fonts = True; 4586956cc18dSsnj TScreen *screen = TScreenOf(xw); 45870bd37d32Smrg long first; 4588956cc18dSsnj 4589956cc18dSsnj lookupFontSizes(xw); 45900bd37d32Smrg first = screen->menu_font_sizes[0]; 4591956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 4592956cc18dSsnj if (screen->menu_font_sizes[n] > 0 4593956cc18dSsnj && screen->menu_font_sizes[n] != first) { 4594956cc18dSsnj broken_fonts = False; 4595956cc18dSsnj break; 4596956cc18dSsnj } 4597956cc18dSsnj } 4598956cc18dSsnj 4599956cc18dSsnj if (broken_fonts) { 4600956cc18dSsnj 4601956cc18dSsnj TRACE(("bitmap fonts are broken - set faceSize resources\n")); 4602956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 46030bd37d32Smrg fillInFaceSize(xw, n); 4604956cc18dSsnj } 4605956cc18dSsnj 4606956cc18dSsnj } 4607956cc18dSsnj } 46080bd37d32Smrg result = True; 46092eaa94a1Schristos } 4610d4fba8b9Smrg TRACE((TRACE_R " useFaceSizes %d\n", result)); 46112eaa94a1Schristos return result; 46122eaa94a1Schristos} 46130bd37d32Smrg#endif /* OPT_RENDERFONT */ 46142eaa94a1Schristos 4615b6fea0ceSmrg#if OPT_SHIFT_FONTS 4616d522f475Smrg/* 4617d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative' 4618d522f475Smrg * and its magnitude), starting from the 'old' index. 4619d522f475Smrg */ 4620d522f475Smrgint 4621d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative) 4622d522f475Smrg{ 4623d522f475Smrg TScreen *screen = TScreenOf(xw); 4624037a25ddSmrg int m = -1; 4625d522f475Smrg 46262eaa94a1Schristos TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 4627d522f475Smrg if (!IsIcon(screen)) { 46282eaa94a1Schristos#if OPT_RENDERFONT 46292eaa94a1Schristos if (useFaceSizes(xw)) { 46302eaa94a1Schristos TRACE(("...using FaceSize\n")); 46312eaa94a1Schristos if (relative != 0) { 4632037a25ddSmrg int n; 46332eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 46340bd37d32Smrg fillInFaceSize(xw, n); 46352eaa94a1Schristos if (xw->misc.face_size[n] > 0 && 46362eaa94a1Schristos xw->misc.face_size[n] != xw->misc.face_size[old]) { 46372eaa94a1Schristos int cmp_0 = ((xw->misc.face_size[n] > 46382eaa94a1Schristos xw->misc.face_size[old]) 46392eaa94a1Schristos ? relative 46402eaa94a1Schristos : -relative); 46412eaa94a1Schristos int cmp_m = ((m < 0) 46422eaa94a1Schristos ? 1 46432eaa94a1Schristos : ((xw->misc.face_size[n] < 46442eaa94a1Schristos xw->misc.face_size[m]) 46452eaa94a1Schristos ? relative 46462eaa94a1Schristos : -relative)); 46472eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 46482eaa94a1Schristos m = n; 46492eaa94a1Schristos } 4650d522f475Smrg } 4651d522f475Smrg } 4652d522f475Smrg } 46532eaa94a1Schristos } else 46542eaa94a1Schristos#endif 46552eaa94a1Schristos { 46562eaa94a1Schristos TRACE(("...using bitmap areas\n")); 46572eaa94a1Schristos lookupFontSizes(xw); 46582eaa94a1Schristos if (relative != 0) { 4659037a25ddSmrg int n; 46602eaa94a1Schristos for (n = 0; n < NMENUFONTS; ++n) { 46612eaa94a1Schristos if (screen->menu_font_sizes[n] > 0 && 46622eaa94a1Schristos screen->menu_font_sizes[n] != 46632eaa94a1Schristos screen->menu_font_sizes[old]) { 46642eaa94a1Schristos int cmp_0 = ((screen->menu_font_sizes[n] > 46652eaa94a1Schristos screen->menu_font_sizes[old]) 46662eaa94a1Schristos ? relative 46672eaa94a1Schristos : -relative); 46682eaa94a1Schristos int cmp_m = ((m < 0) 46692eaa94a1Schristos ? 1 46702eaa94a1Schristos : ((screen->menu_font_sizes[n] < 46712eaa94a1Schristos screen->menu_font_sizes[m]) 46722eaa94a1Schristos ? relative 46732eaa94a1Schristos : -relative)); 46742eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 46752eaa94a1Schristos m = n; 46762eaa94a1Schristos } 46772eaa94a1Schristos } 46782eaa94a1Schristos } 4679d522f475Smrg } 4680d522f475Smrg } 46812eaa94a1Schristos TRACE(("...new index %d\n", m)); 46822eaa94a1Schristos if (m >= 0) { 46832eaa94a1Schristos if (relative > 1) 46842eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative - 1); 46852eaa94a1Schristos else if (relative < -1) 46862eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative + 1); 46872eaa94a1Schristos } 4688d522f475Smrg } 4689d522f475Smrg return m; 4690d522f475Smrg} 4691d522f475Smrg 4692d522f475Smrg/* ARGSUSED */ 4693d522f475Smrgvoid 4694d4fba8b9SmrgHandleLargerFont(Widget w, 46959a64e1c5Smrg XEvent *event GCC_UNUSED, 4696fa3f02f3Smrg String *params GCC_UNUSED, 4697d522f475Smrg Cardinal *param_count GCC_UNUSED) 4698d522f475Smrg{ 4699956cc18dSsnj XtermWidget xw; 4700d522f475Smrg 470120d2c4d2Smrg TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 4702956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 4703d522f475Smrg if (xw->misc.shift_fonts) { 4704956cc18dSsnj TScreen *screen = TScreenOf(xw); 4705d522f475Smrg int m; 4706d522f475Smrg 4707d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 4708d522f475Smrg if (m >= 0) { 4709d522f475Smrg SetVTFont(xw, m, True, NULL); 4710d522f475Smrg } else { 471120d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4712d522f475Smrg } 4713d522f475Smrg } 4714d522f475Smrg } 4715d522f475Smrg} 4716d522f475Smrg 4717d522f475Smrg/* ARGSUSED */ 4718d522f475Smrgvoid 4719d4fba8b9SmrgHandleSmallerFont(Widget w, 47209a64e1c5Smrg XEvent *event GCC_UNUSED, 4721fa3f02f3Smrg String *params GCC_UNUSED, 4722d522f475Smrg Cardinal *param_count GCC_UNUSED) 4723d522f475Smrg{ 4724956cc18dSsnj XtermWidget xw; 4725d522f475Smrg 472620d2c4d2Smrg TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 4727956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 4728d522f475Smrg if (xw->misc.shift_fonts) { 4729956cc18dSsnj TScreen *screen = TScreenOf(xw); 4730d522f475Smrg int m; 4731d522f475Smrg 4732d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 4733d522f475Smrg if (m >= 0) { 4734d522f475Smrg SetVTFont(xw, m, True, NULL); 4735d522f475Smrg } else { 473620d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4737d522f475Smrg } 4738d522f475Smrg } 4739d522f475Smrg } 4740d522f475Smrg} 4741b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */ 4742d522f475Smrg 4743d522f475Smrgint 4744d522f475SmrgxtermGetFont(const char *param) 4745d522f475Smrg{ 4746d522f475Smrg int fontnum; 4747d522f475Smrg 4748d522f475Smrg switch (param[0]) { 4749d522f475Smrg case 'd': 4750d522f475Smrg case 'D': 4751d522f475Smrg case '0': 4752d522f475Smrg fontnum = fontMenu_default; 4753d522f475Smrg break; 4754d522f475Smrg case '1': 4755d522f475Smrg fontnum = fontMenu_font1; 4756d522f475Smrg break; 4757d522f475Smrg case '2': 4758d522f475Smrg fontnum = fontMenu_font2; 4759d522f475Smrg break; 4760d522f475Smrg case '3': 4761d522f475Smrg fontnum = fontMenu_font3; 4762d522f475Smrg break; 4763d522f475Smrg case '4': 4764d522f475Smrg fontnum = fontMenu_font4; 4765d522f475Smrg break; 4766d522f475Smrg case '5': 4767d522f475Smrg fontnum = fontMenu_font5; 4768d522f475Smrg break; 4769d522f475Smrg case '6': 4770d522f475Smrg fontnum = fontMenu_font6; 4771d522f475Smrg break; 4772d4fba8b9Smrg case '7': 4773d4fba8b9Smrg fontnum = fontMenu_font7; 4774d4fba8b9Smrg break; 4775d522f475Smrg case 'e': 4776d522f475Smrg case 'E': 4777d522f475Smrg fontnum = fontMenu_fontescape; 4778d522f475Smrg break; 4779d522f475Smrg case 's': 4780d522f475Smrg case 'S': 4781d522f475Smrg fontnum = fontMenu_fontsel; 4782d522f475Smrg break; 4783d522f475Smrg default: 4784d522f475Smrg fontnum = -1; 4785d522f475Smrg break; 4786d522f475Smrg } 4787d4fba8b9Smrg TRACE(("xtermGetFont(%s) ->%d\n", NonNull(param), fontnum)); 4788d522f475Smrg return fontnum; 4789d522f475Smrg} 4790d522f475Smrg 4791d522f475Smrg/* ARGSUSED */ 4792d522f475Smrgvoid 4793d4fba8b9SmrgHandleSetFont(Widget w, 47949a64e1c5Smrg XEvent *event GCC_UNUSED, 4795fa3f02f3Smrg String *params, 4796d522f475Smrg Cardinal *param_count) 4797d522f475Smrg{ 4798956cc18dSsnj XtermWidget xw; 4799956cc18dSsnj 4800956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 4801d522f475Smrg int fontnum; 4802d522f475Smrg VTFontNames fonts; 4803d522f475Smrg 4804d522f475Smrg memset(&fonts, 0, sizeof(fonts)); 4805d522f475Smrg 4806d522f475Smrg if (*param_count == 0) { 4807d522f475Smrg fontnum = fontMenu_default; 4808d522f475Smrg } else { 4809d522f475Smrg Cardinal maxparams = 1; /* total number of params allowed */ 4810d522f475Smrg int result = xtermGetFont(params[0]); 4811d522f475Smrg 4812d522f475Smrg switch (result) { 4813d522f475Smrg case fontMenu_default: /* FALLTHRU */ 4814d522f475Smrg case fontMenu_font1: /* FALLTHRU */ 4815d522f475Smrg case fontMenu_font2: /* FALLTHRU */ 4816d522f475Smrg case fontMenu_font3: /* FALLTHRU */ 4817d522f475Smrg case fontMenu_font4: /* FALLTHRU */ 4818d522f475Smrg case fontMenu_font5: /* FALLTHRU */ 4819d522f475Smrg case fontMenu_font6: /* FALLTHRU */ 4820d4fba8b9Smrg case fontMenu_font7: /* FALLTHRU */ 4821d522f475Smrg break; 4822d522f475Smrg case fontMenu_fontescape: 4823d522f475Smrg#if OPT_WIDE_CHARS 4824d522f475Smrg maxparams = 5; 4825d522f475Smrg#else 4826d522f475Smrg maxparams = 3; 4827d522f475Smrg#endif 4828d522f475Smrg break; 4829d522f475Smrg case fontMenu_fontsel: 4830d522f475Smrg maxparams = 2; 4831d522f475Smrg break; 4832d522f475Smrg default: 483320d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4834d522f475Smrg return; 4835d522f475Smrg } 4836d522f475Smrg fontnum = result; 4837d522f475Smrg 4838d522f475Smrg if (*param_count > maxparams) { /* see if extra args given */ 483920d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4840d522f475Smrg return; 4841d522f475Smrg } 4842d522f475Smrg switch (*param_count) { /* assign 'em */ 4843d522f475Smrg#if OPT_WIDE_CHARS 4844d522f475Smrg case 5: 4845dfb07bc7Smrg fonts.f_wb = x_strdup(params[4]); 4846d522f475Smrg /* FALLTHRU */ 4847d522f475Smrg case 4: 4848dfb07bc7Smrg fonts.f_w = x_strdup(params[3]); 4849d522f475Smrg#endif 4850dfb07bc7Smrg /* FALLTHRU */ 4851d522f475Smrg case 3: 4852dfb07bc7Smrg fonts.f_b = x_strdup(params[2]); 4853d522f475Smrg /* FALLTHRU */ 4854d522f475Smrg case 2: 4855dfb07bc7Smrg fonts.f_n = x_strdup(params[1]); 4856d522f475Smrg break; 4857d522f475Smrg } 4858d522f475Smrg } 4859d522f475Smrg 4860956cc18dSsnj SetVTFont(xw, fontnum, True, &fonts); 4861d522f475Smrg } 4862d522f475Smrg} 4863d522f475Smrg 4864d522f475Smrgvoid 4865d522f475SmrgSetVTFont(XtermWidget xw, 4866d522f475Smrg int which, 4867d522f475Smrg Bool doresize, 4868d522f475Smrg const VTFontNames * fonts) 4869d522f475Smrg{ 4870956cc18dSsnj TScreen *screen = TScreenOf(xw); 4871d522f475Smrg 4872d522f475Smrg TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 4873d522f475Smrg (fonts && fonts->f_n) ? fonts->f_n : "<null>", 4874d522f475Smrg (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 4875d522f475Smrg 4876d522f475Smrg if (IsIcon(screen)) { 487720d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4878d522f475Smrg } else if (which >= 0 && which < NMENUFONTS) { 4879d522f475Smrg VTFontNames myfonts; 4880d522f475Smrg 4881d522f475Smrg memset(&myfonts, 0, sizeof(myfonts)); 4882d522f475Smrg if (fonts != 0) 4883d522f475Smrg myfonts = *fonts; 4884d522f475Smrg 4885d522f475Smrg if (which == fontMenu_fontsel) { /* go get the selection */ 4886d522f475Smrg FindFontSelection(xw, myfonts.f_n, False); 4887d522f475Smrg } else { 4888d522f475Smrg int oldFont = screen->menu_font_number; 4889d522f475Smrg 4890d522f475Smrg#define USE_CACHED(field, name) \ 4891d522f475Smrg if (myfonts.field == 0) { \ 4892492d43a5Smrg myfonts.field = x_strdup(screen->menu_font_names[which][name]); \ 4893d522f475Smrg TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 4894d522f475Smrg which, NonNull(myfonts.field))); \ 4895d522f475Smrg } else { \ 4896d522f475Smrg TRACE(("set myfonts." #field " reused\n")); \ 4897d522f475Smrg } 489820d2c4d2Smrg#define SAVE_FNAME(field, name) \ 489920d2c4d2Smrg if (myfonts.field != 0) { \ 490020d2c4d2Smrg if (screen->menu_font_names[which][name] == 0 \ 490120d2c4d2Smrg || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \ 4902d4fba8b9Smrg TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \ 490320d2c4d2Smrg which, myfonts.field)); \ 49049a64e1c5Smrg FREE_STRING(screen->menu_font_names[which][name]); \ 490520d2c4d2Smrg screen->menu_font_names[which][name] = x_strdup(myfonts.field); \ 490620d2c4d2Smrg } \ 490720d2c4d2Smrg } 490820d2c4d2Smrg 4909d522f475Smrg USE_CACHED(f_n, fNorm); 4910d522f475Smrg USE_CACHED(f_b, fBold); 4911d522f475Smrg#if OPT_WIDE_CHARS 4912d522f475Smrg USE_CACHED(f_w, fWide); 4913d522f475Smrg USE_CACHED(f_wb, fWBold); 4914d522f475Smrg#endif 4915d522f475Smrg if (xtermLoadFont(xw, 4916d522f475Smrg &myfonts, 4917d522f475Smrg doresize, which)) { 491820d2c4d2Smrg /* 491920d2c4d2Smrg * If successful, save the data so that a subsequent query via 492020d2c4d2Smrg * OSC-50 will return the expected values. 492120d2c4d2Smrg */ 492220d2c4d2Smrg SAVE_FNAME(f_n, fNorm); 492320d2c4d2Smrg SAVE_FNAME(f_b, fBold); 492420d2c4d2Smrg#if OPT_WIDE_CHARS 492520d2c4d2Smrg SAVE_FNAME(f_w, fWide); 492620d2c4d2Smrg SAVE_FNAME(f_wb, fWBold); 492720d2c4d2Smrg#endif 4928d522f475Smrg } else { 492994644356Smrg (void) xtermLoadFont(xw, 493094644356Smrg xtermFontName(screen->MenuFontName(oldFont)), 493194644356Smrg doresize, oldFont); 493220d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4933d522f475Smrg } 49349a64e1c5Smrg FREE_FNAME(f_n); 49359a64e1c5Smrg FREE_FNAME(f_b); 49369a64e1c5Smrg#if OPT_WIDE_CHARS 49379a64e1c5Smrg FREE_FNAME(f_w); 49389a64e1c5Smrg FREE_FNAME(f_wb); 49399a64e1c5Smrg#endif 4940d522f475Smrg } 494120d2c4d2Smrg } else { 494220d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 4943d522f475Smrg } 4944d522f475Smrg return; 4945d522f475Smrg} 4946dfb07bc7Smrg 4947dfb07bc7Smrg#if OPT_RENDERFONT 4948dfb07bc7Smrgstatic void 4949dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size) 4950dfb07bc7Smrg{ 4951dfb07bc7Smrg char *first = strstr(face_name, ":size="); 4952dfb07bc7Smrg if (first == 0) { 4953dfb07bc7Smrg first = face_name; 4954dfb07bc7Smrg } else { 4955dfb07bc7Smrg first++; 4956dfb07bc7Smrg } 4957dfb07bc7Smrg if (!strncmp(first, "size=", (size_t) 5)) { 4958dfb07bc7Smrg char *last = strchr(first, ':'); 4959dfb07bc7Smrg char mark; 4960dfb07bc7Smrg float value; 4961dfb07bc7Smrg char extra; 4962dfb07bc7Smrg TRACE(("...before trimming, font = \"%s\"\n", face_name)); 4963dfb07bc7Smrg if (last == 0) 4964dfb07bc7Smrg last = first + strlen(first); 4965dfb07bc7Smrg mark = *last; 4966dfb07bc7Smrg *last = '\0'; 4967dfb07bc7Smrg if (sscanf(first, "size=%g%c", &value, &extra) == 1) { 4968dfb07bc7Smrg TRACE(("...trimmed size from font: %g\n", value)); 4969dfb07bc7Smrg if (face_size != 0) 4970dfb07bc7Smrg *face_size = value; 4971dfb07bc7Smrg } 4972dfb07bc7Smrg if (mark) { 4973dfb07bc7Smrg while ((*first++ = *++last) != '\0') { 4974dfb07bc7Smrg ; 4975dfb07bc7Smrg } 4976dfb07bc7Smrg } else { 4977dfb07bc7Smrg if (first != face_name) 4978dfb07bc7Smrg --first; 4979dfb07bc7Smrg *first = '\0'; 4980dfb07bc7Smrg } 4981dfb07bc7Smrg TRACE(("...after trimming, font = \"%s\"\n", face_name)); 4982dfb07bc7Smrg } 4983dfb07bc7Smrg} 4984dfb07bc7Smrg#endif 4985dfb07bc7Smrg 4986dfb07bc7Smrg/* 4987dfb07bc7Smrg * Save a font specification to the proper list. 4988dfb07bc7Smrg */ 4989dfb07bc7Smrgstatic void 4990dfb07bc7Smrgsave2FontList(XtermWidget xw, 4991dfb07bc7Smrg const char *name, 4992dfb07bc7Smrg XtermFontNames * fontnames, 4993dfb07bc7Smrg VTFontEnum which, 4994dfb07bc7Smrg const char *source, 4995dfb07bc7Smrg Bool ttf) 4996dfb07bc7Smrg{ 4997dfb07bc7Smrg char *value; 4998dfb07bc7Smrg size_t plen; 4999dfb07bc7Smrg Bool marked = False; 5000dfb07bc7Smrg Bool use_ttf = ttf; 5001dfb07bc7Smrg 5002dfb07bc7Smrg (void) xw; 5003dfb07bc7Smrg 5004dfb07bc7Smrg if (source == 0) 5005dfb07bc7Smrg source = ""; 5006dfb07bc7Smrg while (isspace(CharOf(*source))) 5007dfb07bc7Smrg ++source; 5008dfb07bc7Smrg 5009dfb07bc7Smrg /* fontconfig patterns can contain ':' separators, but we'll treat 5010dfb07bc7Smrg * a leading prefix specially to denote whether the pattern might be 5011dfb07bc7Smrg * XLFD ("x" or "xlfd") versus Xft ("xft"). 5012dfb07bc7Smrg */ 5013dfb07bc7Smrg for (plen = 0; source[plen] != '\0'; ++plen) { 5014dfb07bc7Smrg if (source[plen] == ':') { 5015dfb07bc7Smrg marked = True; 5016dfb07bc7Smrg switch (plen) { 5017dfb07bc7Smrg case 0: 5018dfb07bc7Smrg ++plen; /* trim leading ':' */ 5019dfb07bc7Smrg break; 5020dfb07bc7Smrg case 1: 5021dfb07bc7Smrg if (!strncmp(source, "x", plen)) { 5022dfb07bc7Smrg ++plen; 5023dfb07bc7Smrg use_ttf = False; 5024dfb07bc7Smrg } else { 5025dfb07bc7Smrg marked = False; 5026dfb07bc7Smrg } 5027dfb07bc7Smrg break; 5028dfb07bc7Smrg case 3: 5029dfb07bc7Smrg if (!strncmp(source, "xft", plen)) { 5030dfb07bc7Smrg ++plen; 5031dfb07bc7Smrg use_ttf = True; 5032dfb07bc7Smrg } else { 5033dfb07bc7Smrg marked = False; 5034dfb07bc7Smrg } 5035dfb07bc7Smrg break; 5036dfb07bc7Smrg case 4: 5037dfb07bc7Smrg if (!strncmp(source, "xlfd", plen)) { 5038dfb07bc7Smrg ++plen; 5039dfb07bc7Smrg use_ttf = False; 5040dfb07bc7Smrg } else { 5041dfb07bc7Smrg marked = False; 5042dfb07bc7Smrg } 5043dfb07bc7Smrg break; 5044dfb07bc7Smrg default: 5045dfb07bc7Smrg marked = False; 5046dfb07bc7Smrg plen = 0; 5047dfb07bc7Smrg break; 5048dfb07bc7Smrg } 5049dfb07bc7Smrg break; 5050dfb07bc7Smrg } 5051dfb07bc7Smrg } 5052dfb07bc7Smrg if (!marked) 5053dfb07bc7Smrg plen = 0; 5054dfb07bc7Smrg value = x_strtrim(source + plen); 5055dfb07bc7Smrg if (value != 0) { 5056dfb07bc7Smrg Bool success = False; 5057dfb07bc7Smrg#if OPT_RENDERFONT 5058dfb07bc7Smrg VTFontList *target = (use_ttf 5059dfb07bc7Smrg ? &(fontnames->xft) 5060dfb07bc7Smrg : &(fontnames->x11)); 5061dfb07bc7Smrg#else 5062dfb07bc7Smrg VTFontList *target = &(fontnames->x11); 5063dfb07bc7Smrg#endif 5064dfb07bc7Smrg char ***list = 0; 5065dfb07bc7Smrg char **next = 0; 5066dfb07bc7Smrg size_t count = 0; 5067dfb07bc7Smrg 5068dfb07bc7Smrg (void) use_ttf; 5069dfb07bc7Smrg switch (which) { 5070dfb07bc7Smrg case fNorm: 5071dfb07bc7Smrg list = &(target->list_n); 5072dfb07bc7Smrg break; 5073dfb07bc7Smrg case fBold: 5074dfb07bc7Smrg list = &(target->list_b); 5075dfb07bc7Smrg break; 5076dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5077dfb07bc7Smrg case fItal: 5078dfb07bc7Smrg list = &(target->list_i); 5079dfb07bc7Smrg break; 5080d4fba8b9Smrg case fBtal: 5081d4fba8b9Smrg list = &(target->list_bi); 5082d4fba8b9Smrg break; 5083dfb07bc7Smrg#endif 5084dfb07bc7Smrg#if OPT_WIDE_CHARS 5085dfb07bc7Smrg case fWide: 5086dfb07bc7Smrg list = &(target->list_w); 5087dfb07bc7Smrg break; 5088dfb07bc7Smrg case fWBold: 5089dfb07bc7Smrg list = &(target->list_wb); 5090dfb07bc7Smrg break; 5091dfb07bc7Smrg case fWItal: 5092dfb07bc7Smrg list = &(target->list_wi); 5093dfb07bc7Smrg break; 5094d4fba8b9Smrg case fWBtal: 5095d4fba8b9Smrg list = &(target->list_wbi); 5096d4fba8b9Smrg break; 5097dfb07bc7Smrg#endif 5098dfb07bc7Smrg case fMAX: 5099dfb07bc7Smrg list = 0; 5100dfb07bc7Smrg break; 5101dfb07bc7Smrg } 5102dfb07bc7Smrg 5103dfb07bc7Smrg if (list != 0) { 5104dfb07bc7Smrg success = True; 5105dfb07bc7Smrg if (*list != 0) { 5106dfb07bc7Smrg while ((*list)[count] != 0) { 5107dfb07bc7Smrg if (IsEmpty((*list)[count])) { 5108dfb07bc7Smrg TRACE(("... initial %s\n", value)); 5109dfb07bc7Smrg free((*list)[count]); 5110dfb07bc7Smrg break; 5111dfb07bc7Smrg } else if (!strcmp(value, (*list)[count])) { 5112dfb07bc7Smrg TRACE(("... duplicate %s\n", value)); 5113dfb07bc7Smrg success = False; 5114dfb07bc7Smrg break; 5115dfb07bc7Smrg } 5116dfb07bc7Smrg ++count; 5117dfb07bc7Smrg } 5118dfb07bc7Smrg } 5119dfb07bc7Smrg if (success) { 5120dfb07bc7Smrg next = realloc(*list, sizeof(char *) * (count + 2)); 5121dfb07bc7Smrg if (next != 0) { 5122dfb07bc7Smrg#if OPT_RENDERFONT 5123dfb07bc7Smrg if (use_ttf) { 5124dfb07bc7Smrg trimSizeFromFace(value, 5125dfb07bc7Smrg (count == 0 && which == fNorm) 5126dfb07bc7Smrg ? &(xw->misc.face_size[0]) 5127dfb07bc7Smrg : (float *) 0); 5128dfb07bc7Smrg } 5129dfb07bc7Smrg#endif 5130dfb07bc7Smrg next[count++] = value; 5131dfb07bc7Smrg next[count] = 0; 5132dfb07bc7Smrg *list = next; 51338f44fb3bSmrg TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n", 5134dfb07bc7Smrg whichFontList(xw, target), 5135dfb07bc7Smrg whichFontList2(xw, *list), 5136dfb07bc7Smrg (unsigned long) count, 5137dfb07bc7Smrg value)); 5138dfb07bc7Smrg } else { 5139dfb07bc7Smrg fprintf(stderr, 5140dfb07bc7Smrg "realloc failure in save2FontList(%s)\n", 5141dfb07bc7Smrg name); 5142dfb07bc7Smrg freeFontList(list); 5143dfb07bc7Smrg success = False; 5144dfb07bc7Smrg } 5145dfb07bc7Smrg } 5146dfb07bc7Smrg } 5147dfb07bc7Smrg if (success) { 5148d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS) 5149d4fba8b9Smrg size_t limit = MAX_XFT_FONTS; 5150d4fba8b9Smrg#else 5151dfb07bc7Smrg size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS; 5152d4fba8b9Smrg#endif 5153d4fba8b9Smrg if (count > limit && *x_skip_blanks(value)) { 5154dfb07bc7Smrg fprintf(stderr, "%s: too many fonts for %s, ignoring %s\n", 5155dfb07bc7Smrg ProgramName, 5156dfb07bc7Smrg whichFontEnum(which), 5157dfb07bc7Smrg value); 5158dfb07bc7Smrg if (list && *list) { 5159dfb07bc7Smrg free((*list)[limit]); 5160dfb07bc7Smrg (*list)[limit] = 0; 5161dfb07bc7Smrg } 5162dfb07bc7Smrg } 5163dfb07bc7Smrg } else { 5164dfb07bc7Smrg free(value); 5165dfb07bc7Smrg } 5166dfb07bc7Smrg } 5167dfb07bc7Smrg} 5168dfb07bc7Smrg 5169dfb07bc7Smrg/* 5170dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list 5171dfb07bc7Smrg * of font-names. That would be bad for performance, but as a basis for an 5172dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating 5173dfb07bc7Smrg * an array of font-names. 5174dfb07bc7Smrg */ 5175dfb07bc7Smrgvoid 5176dfb07bc7SmrgallocFontList(XtermWidget xw, 5177dfb07bc7Smrg const char *name, 5178dfb07bc7Smrg XtermFontNames * target, 5179dfb07bc7Smrg VTFontEnum which, 5180dfb07bc7Smrg const char *source, 5181dfb07bc7Smrg Bool ttf) 5182dfb07bc7Smrg{ 5183dfb07bc7Smrg char *blob; 5184dfb07bc7Smrg 5185dfb07bc7Smrg blob = x_strdup(source); 5186d4fba8b9Smrg if (blob != 0) { 5187dfb07bc7Smrg int n; 5188dfb07bc7Smrg int pass; 5189dfb07bc7Smrg char **list = 0; 5190dfb07bc7Smrg 51918f44fb3bSmrg TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n", 51928f44fb3bSmrg whichFontEnum(which), name, blob)); 5193dfb07bc7Smrg 5194dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5195dfb07bc7Smrg unsigned count = 0; 5196dfb07bc7Smrg if (pass) 5197dfb07bc7Smrg list[0] = blob; 5198dfb07bc7Smrg for (n = 0; blob[n] != '\0'; ++n) { 5199dfb07bc7Smrg if (blob[n] == ',') { 5200dfb07bc7Smrg ++count; 5201dfb07bc7Smrg if (pass != 0) { 5202dfb07bc7Smrg blob[n] = '\0'; 5203dfb07bc7Smrg list[count] = blob + n + 1; 5204dfb07bc7Smrg } 5205dfb07bc7Smrg } 5206dfb07bc7Smrg } 5207dfb07bc7Smrg if (!pass) { 5208dfb07bc7Smrg if (count == 0 && *blob == '\0') 5209dfb07bc7Smrg break; 5210dfb07bc7Smrg list = TypeCallocN(char *, count + 2); 5211dfb07bc7Smrg if (list == 0) 5212dfb07bc7Smrg break; 5213dfb07bc7Smrg } 5214dfb07bc7Smrg } 5215dfb07bc7Smrg if (list) { 5216dfb07bc7Smrg for (n = 0; list[n] != 0; ++n) { 5217dfb07bc7Smrg if (*list[n]) { 5218dfb07bc7Smrg save2FontList(xw, name, target, which, list[n], ttf); 5219dfb07bc7Smrg } 5220dfb07bc7Smrg } 5221dfb07bc7Smrg free(list); 5222dfb07bc7Smrg } 5223dfb07bc7Smrg } 5224dfb07bc7Smrg free(blob); 5225dfb07bc7Smrg} 5226dfb07bc7Smrg 5227dfb07bc7Smrgstatic void 5228dfb07bc7SmrginitFontList(XtermWidget xw, 5229dfb07bc7Smrg const char *name, 5230dfb07bc7Smrg XtermFontNames * target, 5231dfb07bc7Smrg Bool ttf) 5232dfb07bc7Smrg{ 5233dfb07bc7Smrg int which; 5234dfb07bc7Smrg 5235dfb07bc7Smrg TRACE(("initFontList(%s)\n", name)); 5236dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5237dfb07bc7Smrg save2FontList(xw, name, target, (VTFontEnum) which, "", ttf); 5238dfb07bc7Smrg } 5239dfb07bc7Smrg} 5240dfb07bc7Smrg 5241dfb07bc7Smrgvoid 5242dfb07bc7SmrginitFontLists(XtermWidget xw) 5243dfb07bc7Smrg{ 5244dfb07bc7Smrg TRACE(("initFontLists\n")); 5245dfb07bc7Smrg initFontList(xw, "x11 font", &(xw->work.fonts), False); 5246dfb07bc7Smrg#if OPT_RENDERFONT 5247dfb07bc7Smrg initFontList(xw, "xft font", &(xw->work.fonts), True); 5248dfb07bc7Smrg#endif 5249dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5250dfb07bc7Smrg initFontList(xw, "cached font", 5251dfb07bc7Smrg &(xw->screen.cacheVTFonts.fonts), False); 5252dfb07bc7Smrg#endif 5253dfb07bc7Smrg} 5254dfb07bc7Smrg 5255dfb07bc7Smrgvoid 5256dfb07bc7SmrgcopyFontList(char ***targetp, char **source) 5257dfb07bc7Smrg{ 5258dfb07bc7Smrg freeFontList(targetp); 5259dfb07bc7Smrg 5260dfb07bc7Smrg if (source != 0) { 5261dfb07bc7Smrg int pass; 5262dfb07bc7Smrg size_t count; 5263dfb07bc7Smrg 5264dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5265dfb07bc7Smrg for (count = 0; source[count] != 0; ++count) { 5266dfb07bc7Smrg if (pass) 5267dfb07bc7Smrg (*targetp)[count] = x_strdup(source[count]); 5268dfb07bc7Smrg } 5269dfb07bc7Smrg if (!pass) { 5270dfb07bc7Smrg ++count; 5271dfb07bc7Smrg *targetp = TypeCallocN(char *, count); 5272dfb07bc7Smrg } 5273dfb07bc7Smrg } 5274dfb07bc7Smrg } else { 5275dfb07bc7Smrg *targetp = TypeCallocN(char *, 2); 5276dfb07bc7Smrg (*targetp)[0] = x_strdup(""); 5277dfb07bc7Smrg } 5278dfb07bc7Smrg} 5279dfb07bc7Smrg 5280dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5281dfb07bc7Smrgstatic Boolean 5282dfb07bc7Smrgmerge_sublist(char ***targetp, char **source) 5283dfb07bc7Smrg{ 5284dfb07bc7Smrg Boolean result = False; 5285dfb07bc7Smrg if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) { 5286dfb07bc7Smrg copyFontList(targetp, source); 5287dfb07bc7Smrg result = True; 5288dfb07bc7Smrg } 5289dfb07bc7Smrg return result; 5290dfb07bc7Smrg} 5291dfb07bc7Smrg#endif 5292dfb07bc7Smrg 5293dfb07bc7Smrgvoid 5294dfb07bc7SmrgfreeFontList(char ***targetp) 5295dfb07bc7Smrg{ 5296dfb07bc7Smrg if (targetp != 0) { 5297dfb07bc7Smrg char **target = *targetp; 5298dfb07bc7Smrg if (target != 0) { 5299dfb07bc7Smrg int n; 5300dfb07bc7Smrg for (n = 0; target[n] != 0; ++n) { 5301dfb07bc7Smrg free(target[n]); 5302dfb07bc7Smrg } 5303dfb07bc7Smrg free(target); 5304dfb07bc7Smrg *targetp = 0; 5305dfb07bc7Smrg } 5306dfb07bc7Smrg } 5307dfb07bc7Smrg} 5308dfb07bc7Smrg 5309dfb07bc7Smrgvoid 5310dfb07bc7SmrgfreeFontLists(VTFontList * lists) 5311dfb07bc7Smrg{ 5312dfb07bc7Smrg int which; 5313dfb07bc7Smrg 5314dfb07bc7Smrg TRACE(("freeFontLists\n")); 5315dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5316dfb07bc7Smrg char ***target = 0; 5317dfb07bc7Smrg switch (which) { 5318dfb07bc7Smrg case fNorm: 5319dfb07bc7Smrg target = &(lists->list_n); 5320dfb07bc7Smrg break; 5321dfb07bc7Smrg case fBold: 5322dfb07bc7Smrg target = &(lists->list_b); 5323dfb07bc7Smrg break; 5324dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5325dfb07bc7Smrg case fItal: 5326dfb07bc7Smrg target = &(lists->list_i); 5327dfb07bc7Smrg break; 5328d4fba8b9Smrg case fBtal: 5329d4fba8b9Smrg target = &(lists->list_bi); 5330d4fba8b9Smrg break; 5331dfb07bc7Smrg#endif 5332dfb07bc7Smrg#if OPT_WIDE_CHARS 5333dfb07bc7Smrg case fWide: 5334dfb07bc7Smrg target = &(lists->list_w); 5335dfb07bc7Smrg break; 5336dfb07bc7Smrg case fWBold: 5337dfb07bc7Smrg target = &(lists->list_wb); 5338dfb07bc7Smrg break; 5339dfb07bc7Smrg case fWItal: 5340dfb07bc7Smrg target = &(lists->list_wi); 5341dfb07bc7Smrg break; 5342d4fba8b9Smrg case fWBtal: 5343d4fba8b9Smrg target = &(lists->list_wbi); 5344d4fba8b9Smrg break; 5345dfb07bc7Smrg#endif 5346dfb07bc7Smrg default: 5347dfb07bc7Smrg target = 0; 5348dfb07bc7Smrg break; 5349dfb07bc7Smrg } 5350dfb07bc7Smrg freeFontList(target); 5351dfb07bc7Smrg } 5352dfb07bc7Smrg} 5353dfb07bc7Smrg 5354dfb07bc7Smrg/* 5355dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class. 5356dfb07bc7Smrg * XXX make this allocate the font on demand. 5357dfb07bc7Smrg */ 5358dfb07bc7SmrgXTermFonts * 5359dfb07bc7SmrggetNormalFont(TScreen *screen, int which) 5360dfb07bc7Smrg{ 5361dfb07bc7Smrg XTermFonts *result = 0; 5362dfb07bc7Smrg if (which >= 0 && which < fMAX) 5363d4fba8b9Smrg result = GetNormalFont(screen, which); 5364dfb07bc7Smrg return result; 5365dfb07bc7Smrg} 5366dfb07bc7Smrg 5367dfb07bc7Smrg#if OPT_DEC_CHRSET 5368dfb07bc7SmrgXTermFonts * 5369dfb07bc7SmrggetDoubleFont(TScreen *screen, int which) 5370dfb07bc7Smrg{ 5371dfb07bc7Smrg XTermFonts *result = 0; 5372dfb07bc7Smrg if ((int) which >= 0 && which < NUM_CHRSET) 5373d4fba8b9Smrg result = GetDoubleFont(screen, which); 5374d4fba8b9Smrg return result; 5375d4fba8b9Smrg} 5376d4fba8b9Smrg 5377d4fba8b9Smrg#if OPT_RENDERFONT 5378d4fba8b9SmrgXftFont * 5379d4fba8b9SmrggetDoubleXftFont(XTermDraw * params, unsigned chrset, unsigned attr_flags) 5380d4fba8b9Smrg{ 5381d4fba8b9Smrg XftFont *result = 0; 5382d4fba8b9Smrg 5383d4fba8b9Smrg XtermWidget xw = params->xw; 5384d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 5385d4fba8b9Smrg XftPattern *top_pattern; 5386d4fba8b9Smrg int fontnum = screen->menu_font_number; 5387d4fba8b9Smrg const char *face_name = getFaceName(xw, False); 5388d4fba8b9Smrg 5389d4fba8b9Smrg if (chrset != CSET_SWL 5390d4fba8b9Smrg && (top_pattern = XftNameParse(face_name)) != 0) { 5391d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 5392d4fba8b9Smrg XftPattern *sub_pattern = XftPatternDuplicate(top_pattern); 5393d4fba8b9Smrg 5394d4fba8b9Smrg switch (chrset) { 5395d4fba8b9Smrg case CSET_DHL_TOP: 5396d4fba8b9Smrg /* FALLTHRU */ 5397d4fba8b9Smrg case CSET_DHL_BOT: 5398d4fba8b9Smrg face_size *= 2; 5399d4fba8b9Smrg XftPatternBuild(sub_pattern, 5400d4fba8b9Smrg NormXftPattern, 5401d4fba8b9Smrg (void *) 0); 5402d4fba8b9Smrg break; 5403d4fba8b9Smrg case CSET_DWL: 5404d4fba8b9Smrg XftPatternBuild(sub_pattern, 5405d4fba8b9Smrg NormXftPattern, 5406d4fba8b9Smrg FC_ASPECT, XftTypeDouble, 2.0, 5407d4fba8b9Smrg (void *) 0); 5408d4fba8b9Smrg break; 5409d4fba8b9Smrg } 5410d4fba8b9Smrg if (attr_flags & BOLD) { 5411d4fba8b9Smrg XftPatternBuild(sub_pattern, 5412d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, 5413d4fba8b9Smrg (void *) 0); 5414d4fba8b9Smrg } 5415d4fba8b9Smrg result = xtermOpenXft(xw, face_name, sub_pattern, "doublesize"); 5416d4fba8b9Smrg } 5417dfb07bc7Smrg return result; 5418dfb07bc7Smrg} 5419dfb07bc7Smrg#endif 5420d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */ 5421dfb07bc7Smrg 5422dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5423dfb07bc7SmrgXTermFonts * 5424dfb07bc7SmrggetItalicFont(TScreen *screen, int which) 5425dfb07bc7Smrg{ 5426dfb07bc7Smrg XTermFonts *result = 0; 5427dfb07bc7Smrg#if OPT_WIDE_ATTRS 5428dfb07bc7Smrg if (which >= 0 && which < fMAX) 5429d4fba8b9Smrg result = GetItalicFont(screen, which); 5430dfb07bc7Smrg#else 5431dfb07bc7Smrg (void) screen; 5432dfb07bc7Smrg (void) which; 5433dfb07bc7Smrg#endif 5434dfb07bc7Smrg return result; 5435dfb07bc7Smrg} 5436dfb07bc7Smrg#endif 5437dfb07bc7Smrg 5438dfb07bc7Smrg#if OPT_RENDERFONT 5439dfb07bc7Smrg/* 5440dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font. 5441dfb07bc7Smrg * XXX make this allocate the font on demand. 5442dfb07bc7Smrg */ 5443dfb07bc7SmrgXTermXftFonts * 5444dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum) 5445dfb07bc7Smrg{ 5446dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 5447dfb07bc7Smrg XTermXftFonts *result = 0; 5448dfb07bc7Smrg if (fontnum >= 0 && fontnum < NMENUFONTS) { 5449dfb07bc7Smrg switch ((VTFontEnum) which) { 5450dfb07bc7Smrg case fNorm: 5451dfb07bc7Smrg result = &(screen->renderFontNorm[fontnum]); 5452dfb07bc7Smrg break; 5453dfb07bc7Smrg case fBold: 5454dfb07bc7Smrg result = &(screen->renderFontBold[fontnum]); 5455dfb07bc7Smrg break; 5456dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5457dfb07bc7Smrg case fItal: 5458dfb07bc7Smrg result = &(screen->renderFontItal[fontnum]); 5459dfb07bc7Smrg break; 5460d4fba8b9Smrg case fBtal: 5461d4fba8b9Smrg result = &(screen->renderFontBtal[fontnum]); 5462d4fba8b9Smrg break; 5463dfb07bc7Smrg#endif 5464dfb07bc7Smrg#if OPT_WIDE_CHARS 5465dfb07bc7Smrg case fWide: 5466dfb07bc7Smrg result = &(screen->renderWideNorm[fontnum]); 5467dfb07bc7Smrg break; 5468dfb07bc7Smrg case fWBold: 5469dfb07bc7Smrg result = &(screen->renderWideBold[fontnum]); 5470dfb07bc7Smrg break; 5471dfb07bc7Smrg case fWItal: 5472dfb07bc7Smrg result = &(screen->renderWideItal[fontnum]); 5473dfb07bc7Smrg break; 5474d4fba8b9Smrg case fWBtal: 5475d4fba8b9Smrg result = &(screen->renderWideBtal[fontnum]); 5476d4fba8b9Smrg break; 5477dfb07bc7Smrg#endif 5478dfb07bc7Smrg case fMAX: 5479dfb07bc7Smrg break; 5480dfb07bc7Smrg } 5481dfb07bc7Smrg } 5482dfb07bc7Smrg return result; 5483dfb07bc7Smrg} 5484dfb07bc7Smrg 5485dfb07bc7SmrgXftFont * 5486dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum) 5487dfb07bc7Smrg{ 5488d4fba8b9Smrg XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum); 5489dfb07bc7Smrg XftFont *result = 0; 5490dfb07bc7Smrg if (data != 0) 5491dfb07bc7Smrg result = data->font; 5492dfb07bc7Smrg return result; 5493dfb07bc7Smrg} 5494dfb07bc7Smrg#endif 5495dfb07bc7Smrg 5496dfb07bc7Smrgconst char * 5497dfb07bc7SmrgwhichFontEnum(VTFontEnum value) 5498dfb07bc7Smrg{ 5499dfb07bc7Smrg const char *result = "?"; 5500dfb07bc7Smrg#define DATA(name) case name: result = #name; break 5501dfb07bc7Smrg switch (value) { 5502dfb07bc7Smrg DATA(fNorm); 5503dfb07bc7Smrg DATA(fBold); 5504dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5505dfb07bc7Smrg DATA(fItal); 5506d4fba8b9Smrg DATA(fBtal); 5507dfb07bc7Smrg#endif 5508dfb07bc7Smrg#if OPT_WIDE_CHARS 5509dfb07bc7Smrg DATA(fWide); 5510dfb07bc7Smrg DATA(fWBold); 5511dfb07bc7Smrg DATA(fWItal); 5512d4fba8b9Smrg DATA(fWBtal); 5513dfb07bc7Smrg#endif 5514dfb07bc7Smrg DATA(fMAX); 5515dfb07bc7Smrg } 5516dfb07bc7Smrg#undef DATA 5517dfb07bc7Smrg return result; 5518dfb07bc7Smrg} 5519dfb07bc7Smrg 5520dfb07bc7Smrgconst char * 5521dfb07bc7SmrgwhichFontList(XtermWidget xw, VTFontList * value) 5522dfb07bc7Smrg{ 5523dfb07bc7Smrg const char *result = "?"; 5524dfb07bc7Smrg if (value == &(xw->work.fonts.x11)) 5525dfb07bc7Smrg result = "x11_fontnames"; 5526dfb07bc7Smrg#if OPT_RENDERFONT 5527dfb07bc7Smrg else if (value == &(xw->work.fonts.xft)) 5528dfb07bc7Smrg result = "xft_fontnames"; 5529dfb07bc7Smrg#endif 5530dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5531dfb07bc7Smrg else if (value == &(xw->screen.cacheVTFonts.fonts.x11)) 5532dfb07bc7Smrg result = "cached_fontnames"; 5533dfb07bc7Smrg#endif 5534dfb07bc7Smrg return result; 5535dfb07bc7Smrg} 5536dfb07bc7Smrg 5537dfb07bc7Smrgstatic const char * 5538dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value) 5539dfb07bc7Smrg{ 5540dfb07bc7Smrg const char *result = 0; 5541dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name 5542dfb07bc7Smrg DATA(list_n); 5543dfb07bc7Smrg DATA(list_b); 5544dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5545dfb07bc7Smrg DATA(list_i); 5546d4fba8b9Smrg DATA(list_bi); 5547dfb07bc7Smrg#endif 5548dfb07bc7Smrg#if OPT_WIDE_CHARS 5549dfb07bc7Smrg DATA(list_w); 5550dfb07bc7Smrg DATA(list_wb); 5551dfb07bc7Smrg DATA(list_wi); 5552d4fba8b9Smrg DATA(list_wbi); 5553dfb07bc7Smrg#endif 5554dfb07bc7Smrg#undef DATA 5555dfb07bc7Smrg return result; 5556dfb07bc7Smrg} 5557dfb07bc7Smrg 5558dfb07bc7Smrgconst char * 5559dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value) 5560dfb07bc7Smrg{ 5561dfb07bc7Smrg const char *result = 0; 5562dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value)) 5563dfb07bc7Smrg if (DATA(work.fonts.x11) == 0) { 5564dfb07bc7Smrg#if OPT_RENDERFONT 5565dfb07bc7Smrg if (DATA(work.fonts.xft) == 0) 5566dfb07bc7Smrg#endif 5567dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5568dfb07bc7Smrg if (DATA(screen.cacheVTFonts.fonts.x11) == 0) 5569dfb07bc7Smrg#endif 5570dfb07bc7Smrg result = "?"; 5571dfb07bc7Smrg } 5572dfb07bc7Smrg#undef DATA 5573dfb07bc7Smrg return result; 5574dfb07bc7Smrg} 5575