fontutils.c revision d1603bab
1d1603babSmrg/* $XTermId: fontutils.c,v 1.773 2023/05/08 00:00:38 tom Exp $ */ 2d522f475Smrg 30bd37d32Smrg/* 4d1603babSmrg * Copyright 1998-2022,2023 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 54d1603babSmrg#define USE_FC_COLOR 0 55d1603babSmrg#if OPT_RENDERFONT 56d1603babSmrg#if XftVersion > 20304 57d1603babSmrg#undef USE_FC_COLOR 58d1603babSmrg#define USE_FC_COLOR 1 59d1603babSmrg#endif 60d1603babSmrg#endif 61d1603babSmrg 62d1603babSmrg#define FcOK(func) (func == FcResultMatch) 63d1603babSmrg 64d4fba8b9Smrg#define NoFontWarning(data) (data)->warn = fwAlways 65d4fba8b9Smrg 660bd37d32Smrg#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 67d4fba8b9Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((double)((screen)->scale_height * (float) (src))) 680bd37d32Smrg 69d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */ 70d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 71d522f475Smrg (((cs)->rbearing|(cs)->lbearing| \ 72d522f475Smrg (cs)->ascent|(cs)->descent) == 0)) 73d522f475Smrg 74fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 75d522f475Smrg{ \ 76fa3f02f3Smrg cs = 0; \ 77d522f475Smrg if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 78d522f475Smrg if (fs->per_char == NULL) { \ 79d522f475Smrg cs = &fs->min_bounds; \ 80d522f475Smrg } else { \ 81d522f475Smrg cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 82d522f475Smrg } \ 83fa3f02f3Smrg if (CI_NONEXISTCHAR(cs)) cs = 0; \ 84d522f475Smrg } \ 85d522f475Smrg} 86d522f475Smrg 87fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 88d522f475Smrg{ \ 89fa3f02f3Smrg cs = 0; \ 90d522f475Smrg if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 91d522f475Smrg col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 92d522f475Smrg if (fs->per_char == NULL) { \ 93d522f475Smrg cs = &fs->min_bounds; \ 94d522f475Smrg } else { \ 95d522f475Smrg cs = &fs->per_char[((row - fs->min_byte1) * \ 96d522f475Smrg (fs->max_char_or_byte2 - \ 97d522f475Smrg fs->min_char_or_byte2 + 1)) + \ 98d522f475Smrg (col - fs->min_char_or_byte2)]; \ 99d522f475Smrg } \ 100fa3f02f3Smrg if (CI_NONEXISTCHAR(cs)) cs = 0; \ 101d522f475Smrg } \ 102d522f475Smrg} 103d522f475Smrg 1049a64e1c5Smrg#define FREE_FNAME(field) \ 105d1603babSmrg if (fonts == 0 || new_fnames.field != fonts->field) { \ 106d1603babSmrg FREE_STRING(new_fnames.field); \ 107d1603babSmrg new_fnames.field = 0; \ 1089a64e1c5Smrg } 1099a64e1c5Smrg 110d522f475Smrg/* 111d522f475Smrg * A structure to hold the relevant properties from a font 112d522f475Smrg * we need to make a well formed font name for it. 113d522f475Smrg */ 114d522f475Smrgtypedef struct { 115d522f475Smrg /* registry, foundry, family */ 1169a64e1c5Smrg const char *beginning; 117d522f475Smrg /* weight */ 1189a64e1c5Smrg const char *weight; 119d522f475Smrg /* slant */ 1209a64e1c5Smrg const char *slant; 121d522f475Smrg /* wideness */ 1229a64e1c5Smrg const char *wideness; 123d522f475Smrg /* add style */ 1249a64e1c5Smrg const char *add_style; 125d522f475Smrg int pixel_size; 1269a64e1c5Smrg const char *point_size; 127d522f475Smrg int res_x; 128d522f475Smrg int res_y; 1299a64e1c5Smrg const char *spacing; 130d522f475Smrg int average_width; 131d522f475Smrg /* charset registry, charset encoding */ 132d522f475Smrg char *end; 133d522f475Smrg} FontNameProperties; 134d522f475Smrg 135d4fba8b9Smrg#if OPT_WIDE_CHARS && (OPT_RENDERFONT || (OPT_TRACE > 1)) 136d4fba8b9Smrg#define MY_UCS(code,high,wide,name) { code, high, wide, #name } 137d4fba8b9Smrgstatic const struct { 138d4fba8b9Smrg unsigned code, high, wide; 139d4fba8b9Smrg const char *name; 140d4fba8b9Smrg} unicode_boxes[] = { 141d4fba8b9Smrg 142d4fba8b9Smrg MY_UCS(0x2500, 0, 1, box drawings light horizontal), 143d4fba8b9Smrg MY_UCS(0x2502, 1, 0, box drawings light vertical), 144d4fba8b9Smrg MY_UCS(0x250c, 2, 2, box drawings light down and right), 145d4fba8b9Smrg MY_UCS(0x2510, 2, 2, box drawings light down and left), 146d4fba8b9Smrg MY_UCS(0x2514, 2, 2, box drawings light up and right), 147d4fba8b9Smrg MY_UCS(0x2518, 2, 2, box drawings light up and left), 148d4fba8b9Smrg MY_UCS(0x251c, 1, 2, box drawings light vertical and right), 149d4fba8b9Smrg MY_UCS(0x2524, 1, 2, box drawings light vertical and left), 150d4fba8b9Smrg MY_UCS(0x252c, 2, 1, box drawings light down and horizontal), 151d4fba8b9Smrg MY_UCS(0x2534, 2, 1, box drawings light up and horizontal), 152d4fba8b9Smrg MY_UCS(0x253c, 1, 1, box drawings light vertical and horizontal), 153d4fba8b9Smrg { 154d4fba8b9Smrg 0, 0, 0, NULL 155d4fba8b9Smrg } 156d4fba8b9Smrg}; 157d4fba8b9Smrg 158d4fba8b9Smrg#undef MY_UCS 159d4fba8b9Smrg#endif /* OPT_WIDE_CHARS */ 160d4fba8b9Smrg 161dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 162dfb07bc7Smrgstatic Boolean merge_sublist(char ***, char **); 163dfb07bc7Smrg#endif 164dfb07bc7Smrg 165dfb07bc7Smrgstatic void save2FontList(XtermWidget, const char *, XtermFontNames *, 166d1603babSmrg VTFontEnum, const char *, Bool, Bool); 167dfb07bc7Smrg 1680bd37d32Smrg#if OPT_RENDERFONT 1690bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int); 1700bd37d32Smrg#endif 1710bd37d32Smrg 172d1603babSmrg#if OPT_REPORT_FONTS && OPT_TRACE 173d1603babSmrgstatic void 174d1603babSmrgreport_fonts(const char *fmt, ...) 175d1603babSmrg{ 176d1603babSmrg va_list ap; 177d1603babSmrg va_start(ap, fmt); 178d1603babSmrg vfprintf(stdout, fmt, ap); 179d1603babSmrg va_end(ap); 180d1603babSmrg#if OPT_TRACE 181d1603babSmrg va_start(ap, fmt); 182d1603babSmrg TraceVA(fmt, ap); 183d1603babSmrg va_end(ap); 184d1603babSmrg#endif 185d1603babSmrg} 186d1603babSmrg 187d1603babSmrg#define ReportFonts report_fonts 188d1603babSmrg#else 189d1603babSmrg#define ReportFonts printf 190d522f475Smrg#endif 191d522f475Smrg 192d4fba8b9Smrg#if OPT_TRACE 193d4fba8b9Smrgstatic void 194d4fba8b9Smrgset_font_height(TScreen *screen, VTwin *win, int height) 195d4fba8b9Smrg{ 196d4fba8b9Smrg SetFontHeight(screen, win, height); 197d4fba8b9Smrg TRACE(("SetFontHeight %d\n", win->f_height)); 198d4fba8b9Smrg#undef SetFontHeight 199d4fba8b9Smrg#define SetFontHeight(screen, win, height) set_font_height(screen, win, height) 200d4fba8b9Smrg} 201d4fba8b9Smrg 202d4fba8b9Smrgstatic void 203d4fba8b9Smrgset_font_width(TScreen *screen, VTwin *win, int width) 204d4fba8b9Smrg{ 205d4fba8b9Smrg (void) screen; 206d4fba8b9Smrg SetFontWidth(screen, win, width); 207d4fba8b9Smrg TRACE(("SetFontWidth %d\n", win->f_width)); 208d4fba8b9Smrg#undef SetFontWidth 209c48a5815Smrg#define SetFontWidth(screen, win, width) set_font_width(screen, win, width) 210d4fba8b9Smrg} 211d4fba8b9Smrg#endif 212d4fba8b9Smrg 213fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS 2142eaa94a1Schristosstatic unsigned 2159a64e1c5SmrgcountGlyphs(XFontStruct *fp) 216d522f475Smrg{ 217d522f475Smrg unsigned count = 0; 218d522f475Smrg 219d522f475Smrg if (fp != 0) { 220d522f475Smrg if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 221fa3f02f3Smrg count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1; 222d522f475Smrg } else if (fp->min_char_or_byte2 < 256 223d522f475Smrg && fp->max_char_or_byte2 < 256) { 224d522f475Smrg unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 225d522f475Smrg unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 226d522f475Smrg count = last + 1 - first; 227d522f475Smrg } 228d522f475Smrg } 229d522f475Smrg return count; 230d522f475Smrg} 231fa3f02f3Smrg#endif 232d522f475Smrg 233fa3f02f3Smrg#if OPT_WIDE_CHARS 234d522f475Smrg/* 235d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many 236d522f475Smrg * glyphs as the wide font. The counts should be the same, but settle for 237d522f475Smrg * filtering out the worst of the font mismatches. 238d522f475Smrg */ 239d522f475Smrgstatic Bool 2409a64e1c5SmrgcompatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs) 241d522f475Smrg{ 242d522f475Smrg unsigned count_w = countGlyphs(wfs); 243d522f475Smrg unsigned count_wb = countGlyphs(wbfs); 244d522f475Smrg if (count_w <= 256 || 245d522f475Smrg count_wb <= 256 || 246d522f475Smrg ((count_w / 4) * 3) > count_wb) { 247d522f475Smrg TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 248d522f475Smrg count_w, count_wb)); 249d522f475Smrg return False; 250d522f475Smrg } 251d522f475Smrg return True; 252d522f475Smrg} 253d522f475Smrg#endif /* OPT_WIDE_CHARS */ 254d522f475Smrg 25520d2c4d2Smrg#if OPT_BOX_CHARS 25620d2c4d2Smrgstatic void 25720d2c4d2SmrgsetupPackedFonts(XtermWidget xw) 25820d2c4d2Smrg{ 25920d2c4d2Smrg TScreen *screen = TScreenOf(xw); 26020d2c4d2Smrg Bool value = False; 26120d2c4d2Smrg 26220d2c4d2Smrg#if OPT_RENDERFONT 2630bd37d32Smrg if (xw->work.render_font == True) { 264dfb07bc7Smrg int e; 26520d2c4d2Smrg 266dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 267dfb07bc7Smrg XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number); 268dfb07bc7Smrg if (data != 0) { 269d1603babSmrg if (data->font_info.mixed) { 270dfb07bc7Smrg screen->allow_packing = True; 271dfb07bc7Smrg break; 272dfb07bc7Smrg } 273dfb07bc7Smrg } 274dfb07bc7Smrg } 27520d2c4d2Smrg } 27620d2c4d2Smrg#endif /* OPT_RENDERFONT */ 27720d2c4d2Smrg 27820d2c4d2Smrg value = screen->allow_packing; 27920d2c4d2Smrg 28020d2c4d2Smrg SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 28120d2c4d2Smrg} 28220d2c4d2Smrg#endif 28320d2c4d2Smrg 284d4fba8b9Smrgtypedef struct _nameList { 285d4fba8b9Smrg struct _nameList *next; 286d4fba8b9Smrg char *name; 287d4fba8b9Smrg} NameList; 288d4fba8b9Smrg 289d4fba8b9Smrgstatic NameList *derived_fonts; 290d4fba8b9Smrg 291d4fba8b9Smrgstatic Boolean 292d4fba8b9Smrgis_derived_font_name(const char *name) 293d4fba8b9Smrg{ 294d4fba8b9Smrg Boolean result = False; 295d4fba8b9Smrg NameList *list; 296d4fba8b9Smrg if (!IsEmpty(name)) { 297d4fba8b9Smrg for (list = derived_fonts; list != 0; list = list->next) { 298d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 299d4fba8b9Smrg result = True; 300d4fba8b9Smrg break; 301d4fba8b9Smrg } 302d4fba8b9Smrg } 303d4fba8b9Smrg } 304d4fba8b9Smrg return result; 305d4fba8b9Smrg} 306d4fba8b9Smrg 307d4fba8b9Smrgvoid 308d4fba8b9SmrgxtermDerivedFont(const char *name) 309d4fba8b9Smrg{ 310d4fba8b9Smrg if (!IsEmpty(name) && !is_derived_font_name(name)) { 311d4fba8b9Smrg NameList *list = TypeCalloc(NameList); 312d4fba8b9Smrg list->name = x_strdup(name); 313d4fba8b9Smrg list->next = derived_fonts; 314d4fba8b9Smrg derived_fonts = list; 315d4fba8b9Smrg } 316d4fba8b9Smrg} 317d4fba8b9Smrg 318d522f475Smrg/* 319d522f475Smrg * Returns the fields from start to stop in a dash- separated string. This 3209a64e1c5Smrg * function will modify the source, putting '\0's in the appropriate place and 321d522f475Smrg * moving the beginning forward to after the '\0' 322d522f475Smrg * 323d522f475Smrg * This will NOT work for the last field (but we won't need it). 324d522f475Smrg */ 325d522f475Smrgstatic char * 326d522f475Smrgn_fields(char **source, int start, int stop) 327d522f475Smrg{ 328d522f475Smrg int i; 329d522f475Smrg char *str, *str1; 330d522f475Smrg 331d522f475Smrg /* 332d522f475Smrg * find the start-1th dash 333d522f475Smrg */ 3349a64e1c5Smrg for (i = start - 1, str = *source; i; i--, str++) { 335d522f475Smrg if ((str = strchr(str, '-')) == 0) 336d522f475Smrg return 0; 3379a64e1c5Smrg } 338d522f475Smrg 339d522f475Smrg /* 340d522f475Smrg * find the stopth dash 341d522f475Smrg */ 3429a64e1c5Smrg for (i = stop - start + 1, str1 = str; i; i--, str1++) { 343d522f475Smrg if ((str1 = strchr(str1, '-')) == 0) 344d522f475Smrg return 0; 3459a64e1c5Smrg } 346d522f475Smrg 347d522f475Smrg /* 348d522f475Smrg * put a \0 at the end of the fields 349d522f475Smrg */ 350d522f475Smrg *(str1 - 1) = '\0'; 351d522f475Smrg 352d522f475Smrg /* 353d522f475Smrg * move source forward 354d522f475Smrg */ 355d522f475Smrg *source = str1; 356d522f475Smrg 357d522f475Smrg return str; 358d522f475Smrg} 359d522f475Smrg 360956cc18dSsnjstatic Boolean 361956cc18dSsnjcheck_fontname(const char *name) 362956cc18dSsnj{ 363956cc18dSsnj Boolean result = True; 364956cc18dSsnj 365492d43a5Smrg if (IsEmpty(name)) { 366956cc18dSsnj TRACE(("fontname missing\n")); 367956cc18dSsnj result = False; 368956cc18dSsnj } 369956cc18dSsnj return result; 370956cc18dSsnj} 371956cc18dSsnj 372d522f475Smrg/* 373d522f475Smrg * Gets the font properties from a given font structure. We use the FONT name 374d522f475Smrg * to find them out, since that seems easier. 375d522f475Smrg * 376d522f475Smrg * Returns a pointer to a static FontNameProperties structure 377d522f475Smrg * or NULL on error. 378d522f475Smrg */ 379d522f475Smrgstatic FontNameProperties * 3809a64e1c5Smrgget_font_name_props(Display *dpy, XFontStruct *fs, char **result) 381d522f475Smrg{ 382d522f475Smrg static FontNameProperties props; 383d522f475Smrg static char *last_name; 384d522f475Smrg 385d4fba8b9Smrg Atom fontatom; 386d4fba8b9Smrg char *name; 387d522f475Smrg char *str; 388d522f475Smrg 389d4fba8b9Smrg if (fs == NULL) 390d4fba8b9Smrg return NULL; 391d4fba8b9Smrg 392d522f475Smrg /* 393d522f475Smrg * first get the full font name 394d522f475Smrg */ 395d4fba8b9Smrg name = 0; 396d4fba8b9Smrg fontatom = XInternAtom(dpy, "FONT", False); 39720d2c4d2Smrg if (fontatom != 0) { 398037a25ddSmrg XFontProp *fp; 399037a25ddSmrg int i; 400037a25ddSmrg 40120d2c4d2Smrg for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 40220d2c4d2Smrg if (fp->name == fontatom) { 40320d2c4d2Smrg name = XGetAtomName(dpy, fp->card32); 40420d2c4d2Smrg break; 40520d2c4d2Smrg } 40620d2c4d2Smrg } 40720d2c4d2Smrg } 408d522f475Smrg 409d522f475Smrg if (name == 0) 410d522f475Smrg return 0; 411d522f475Smrg 412d522f475Smrg /* 413d522f475Smrg * XGetAtomName allocates memory - don't leak 414d522f475Smrg */ 415d4fba8b9Smrg XFree(last_name); 416d522f475Smrg last_name = name; 417d522f475Smrg 418d522f475Smrg if (result != 0) { 419956cc18dSsnj if (!check_fontname(name)) 420d522f475Smrg return 0; 421d4fba8b9Smrg free(*result); 4220bd37d32Smrg *result = x_strdup(name); 423d522f475Smrg } 424d522f475Smrg 425d522f475Smrg /* 426d522f475Smrg * Now split it up into parts and put them in 427d522f475Smrg * their places. Since we are using parts of 428d522f475Smrg * the original string, we must not free the Atom Name 429d522f475Smrg */ 430d522f475Smrg 431d522f475Smrg /* registry, foundry, family */ 432d522f475Smrg if ((props.beginning = n_fields(&name, 1, 3)) == 0) 433d522f475Smrg return 0; 434d522f475Smrg 435d522f475Smrg /* weight is the next */ 436d522f475Smrg if ((props.weight = n_fields(&name, 1, 1)) == 0) 437d522f475Smrg return 0; 438d522f475Smrg 439d522f475Smrg /* slant */ 440d522f475Smrg if ((props.slant = n_fields(&name, 1, 1)) == 0) 441d522f475Smrg return 0; 442d522f475Smrg 443d522f475Smrg /* width */ 444d522f475Smrg if ((props.wideness = n_fields(&name, 1, 1)) == 0) 445d522f475Smrg return 0; 446d522f475Smrg 447d522f475Smrg /* add style */ 448d522f475Smrg if ((props.add_style = n_fields(&name, 1, 1)) == 0) 449d522f475Smrg return 0; 450d522f475Smrg 451d522f475Smrg /* pixel size */ 452d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 453d522f475Smrg return 0; 454d522f475Smrg if ((props.pixel_size = atoi(str)) == 0) 455d522f475Smrg return 0; 456d522f475Smrg 457d522f475Smrg /* point size */ 458d522f475Smrg if ((props.point_size = n_fields(&name, 1, 1)) == 0) 459d522f475Smrg return 0; 460d522f475Smrg 461d522f475Smrg /* res_x */ 462d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 463d522f475Smrg return 0; 464d522f475Smrg if ((props.res_x = atoi(str)) == 0) 465d522f475Smrg return 0; 466d522f475Smrg 467d522f475Smrg /* res_y */ 468d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 469d522f475Smrg return 0; 470d522f475Smrg if ((props.res_y = atoi(str)) == 0) 471d522f475Smrg return 0; 472d522f475Smrg 473d522f475Smrg /* spacing */ 474d522f475Smrg if ((props.spacing = n_fields(&name, 1, 1)) == 0) 475d522f475Smrg return 0; 476d522f475Smrg 477d522f475Smrg /* average width */ 478d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 479d522f475Smrg return 0; 480d522f475Smrg if ((props.average_width = atoi(str)) == 0) 481d522f475Smrg return 0; 482d522f475Smrg 483d522f475Smrg /* the rest: charset registry and charset encoding */ 484d522f475Smrg props.end = name; 485d522f475Smrg 486d522f475Smrg return &props; 487d522f475Smrg} 488d522f475Smrg 489d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1) 490d522f475Smrg 491d522f475Smrgstatic void 492956cc18dSsnjalloca_fontname(char **result, size_t next) 493d522f475Smrg{ 494956cc18dSsnj size_t last = (*result != 0) ? strlen(*result) : 0; 495956cc18dSsnj size_t have = (*result != 0) ? ALLOCHUNK(last) : 0; 496956cc18dSsnj size_t want = last + next + 2; 497d522f475Smrg 498d522f475Smrg if (want >= have) { 49950027b5bSmrg char *save = *result; 500d522f475Smrg want = ALLOCHUNK(want); 501d522f475Smrg if (last != 0) { 502d522f475Smrg *result = TypeRealloc(char, want, *result); 5039a64e1c5Smrg if (*result == 0) 5049a64e1c5Smrg free(save); 505d522f475Smrg } else { 50650027b5bSmrg if ((*result = TypeMallocN(char, want)) != 0) { 50750027b5bSmrg free(save); 508d522f475Smrg **result = '\0'; 50950027b5bSmrg } 510d522f475Smrg } 511d522f475Smrg } 512d522f475Smrg} 513d522f475Smrg 514d522f475Smrgstatic void 51520d2c4d2Smrgappend_fontname_str(char **result, const char *value) 516d522f475Smrg{ 517d522f475Smrg if (value == 0) 518d522f475Smrg value = "*"; 519d522f475Smrg alloca_fontname(result, strlen(value)); 520d522f475Smrg if (*result != 0) { 521d522f475Smrg if (**result != '\0') 522d522f475Smrg strcat(*result, "-"); 523d522f475Smrg strcat(*result, value); 524d522f475Smrg } 525d522f475Smrg} 526d522f475Smrg 527d522f475Smrgstatic void 528d522f475Smrgappend_fontname_num(char **result, int value) 529d522f475Smrg{ 530d522f475Smrg if (value < 0) { 531d522f475Smrg append_fontname_str(result, "*"); 532d522f475Smrg } else { 533d522f475Smrg char temp[100]; 534d522f475Smrg sprintf(temp, "%d", value); 535d522f475Smrg append_fontname_str(result, temp); 536d522f475Smrg } 537d522f475Smrg} 538d522f475Smrg 539d522f475Smrg/* 540d522f475Smrg * Take the given font props and try to make a well formed font name specifying 541d522f475Smrg * the same base font and size and everything, but with different weight/width 542d522f475Smrg * according to the parameters. The return value is allocated, should be freed 543d522f475Smrg * by the caller. 544d522f475Smrg */ 545d522f475Smrgstatic char * 5469a64e1c5Smrgderive_font_name(FontNameProperties *props, 54720d2c4d2Smrg const char *use_weight, 548d522f475Smrg int use_average_width, 54920d2c4d2Smrg const char *use_encoding) 550d522f475Smrg{ 551d522f475Smrg char *result = 0; 552d522f475Smrg 553d522f475Smrg append_fontname_str(&result, props->beginning); 554d522f475Smrg append_fontname_str(&result, use_weight); 555d522f475Smrg append_fontname_str(&result, props->slant); 556d522f475Smrg append_fontname_str(&result, 0); 557d522f475Smrg append_fontname_str(&result, 0); 558d522f475Smrg append_fontname_num(&result, props->pixel_size); 559d522f475Smrg append_fontname_str(&result, props->point_size); 560d522f475Smrg append_fontname_num(&result, props->res_x); 561d522f475Smrg append_fontname_num(&result, props->res_y); 562d522f475Smrg append_fontname_str(&result, props->spacing); 563d522f475Smrg append_fontname_num(&result, use_average_width); 564d522f475Smrg append_fontname_str(&result, use_encoding); 565d522f475Smrg 566d4fba8b9Smrg xtermDerivedFont(result); 567d522f475Smrg return result; 568d522f475Smrg} 569d522f475Smrg 570d522f475Smrgstatic char * 5719a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width) 572d522f475Smrg{ 573d522f475Smrg return derive_font_name(props, "bold", use_average_width, props->end); 574d522f475Smrg} 575d522f475Smrg 5769a64e1c5Smrg#if OPT_WIDE_ATTRS 5779a64e1c5Smrgstatic char * 578dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant) 5799a64e1c5Smrg{ 5809a64e1c5Smrg FontNameProperties myprops = *props; 581dfb07bc7Smrg myprops.slant = slant; 582dfb07bc7Smrg return derive_font_name(&myprops, props->weight, myprops.average_width, props->end); 583dfb07bc7Smrg} 584dfb07bc7Smrg 585dfb07bc7Smrgstatic Boolean 586dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data) 587dfb07bc7Smrg{ 588d1603babSmrg static const char *const slant[] = 589dfb07bc7Smrg { 590dfb07bc7Smrg "o", 591dfb07bc7Smrg "i" 592dfb07bc7Smrg }; 593dfb07bc7Smrg Cardinal pass; 594dfb07bc7Smrg Boolean result = False; 595dfb07bc7Smrg 596d4fba8b9Smrg NoFontWarning(data); 597dfb07bc7Smrg for (pass = 0; pass < XtNumber(slant); ++pass) { 598d4fba8b9Smrg char *name; 599dfb07bc7Smrg if ((name = italic_font_name(fp, slant[pass])) != 0) { 600dfb07bc7Smrg TRACE(("open_italic_font %s %s\n", 601dfb07bc7Smrg whichFontEnum((VTFontEnum) n), name)); 602d1603babSmrg if (xtermOpenFont(xw, name, data, NULL, False)) { 603dfb07bc7Smrg result = (data->fs != 0); 604dfb07bc7Smrg#if OPT_REPORT_FONTS 605dfb07bc7Smrg if (resource.reportFonts) { 606d1603babSmrg ReportFonts("opened italic version of %s:\n\t%s\n", 607d1603babSmrg whichFontEnum((VTFontEnum) n), 608d1603babSmrg name); 609dfb07bc7Smrg } 610dfb07bc7Smrg#endif 611dfb07bc7Smrg } 612dfb07bc7Smrg free(name); 613dfb07bc7Smrg if (result) 614dfb07bc7Smrg break; 615dfb07bc7Smrg } 616dfb07bc7Smrg } 617dfb07bc7Smrg#if OPT_TRACE 618dfb07bc7Smrg if (result) { 619dfb07bc7Smrg XFontStruct *fs = data->fs; 620dfb07bc7Smrg if (fs != 0) { 621dfb07bc7Smrg TRACE(("...actual size %dx%d (ascent %d, descent %d)\n", 622dfb07bc7Smrg fs->ascent + 623dfb07bc7Smrg fs->descent, 624dfb07bc7Smrg fs->max_bounds.width, 625dfb07bc7Smrg fs->ascent, 626dfb07bc7Smrg fs->descent)); 627dfb07bc7Smrg } 628dfb07bc7Smrg } 629dfb07bc7Smrg#endif 630dfb07bc7Smrg return result; 6319a64e1c5Smrg} 6329a64e1c5Smrg#endif 6339a64e1c5Smrg 634d522f475Smrg#if OPT_WIDE_CHARS 635d522f475Smrg#define derive_wide_font(props, weight) \ 636d522f475Smrg derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 637d522f475Smrg 638d522f475Smrgstatic char * 6399a64e1c5Smrgwide_font_name(FontNameProperties *props) 640d522f475Smrg{ 641d522f475Smrg return derive_wide_font(props, "medium"); 642d522f475Smrg} 643d522f475Smrg 644d522f475Smrgstatic char * 6459a64e1c5Smrgwidebold_font_name(FontNameProperties *props) 646d522f475Smrg{ 647d522f475Smrg return derive_wide_font(props, "bold"); 648d522f475Smrg} 649d522f475Smrg#endif /* OPT_WIDE_CHARS */ 650d522f475Smrg 651d522f475Smrg#if OPT_DEC_CHRSET 652d522f475Smrg/* 653d522f475Smrg * Take the given font props and try to make a well formed font name specifying 654d522f475Smrg * the same base font but changed depending on the given attributes and chrset. 655d522f475Smrg * 656d522f475Smrg * For double width fonts, we just double the X-resolution, for double height 657d522f475Smrg * fonts we double the pixel-size and Y-resolution 658d522f475Smrg */ 659d522f475Smrgchar * 660d4fba8b9SmrgxtermSpecialFont(XTermDraw * params) 661d522f475Smrg{ 662d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 663d522f475Smrg#if OPT_TRACE 664d522f475Smrg static char old_spacing[80]; 665d522f475Smrg static FontNameProperties old_props; 666d522f475Smrg#endif 667d522f475Smrg FontNameProperties *props; 668d522f475Smrg char *result = 0; 66920d2c4d2Smrg const char *weight; 670d522f475Smrg int pixel_size; 671d522f475Smrg int res_x; 672d522f475Smrg int res_y; 673d522f475Smrg 674dfb07bc7Smrg props = get_font_name_props(screen->display, 675d4fba8b9Smrg GetNormalFont(screen, fNorm)->fs, 0); 676d522f475Smrg if (props == 0) 677d522f475Smrg return result; 678d522f475Smrg 679d522f475Smrg pixel_size = props->pixel_size; 680d522f475Smrg res_x = props->res_x; 681d522f475Smrg res_y = props->res_y; 682d4fba8b9Smrg if (params->attr_flags & BOLD) 683d522f475Smrg weight = "bold"; 684d522f475Smrg else 685d522f475Smrg weight = props->weight; 686d522f475Smrg 687d4fba8b9Smrg if (CSET_DOUBLE(params->this_chrset)) 688d522f475Smrg res_x *= 2; 689d522f475Smrg 690d4fba8b9Smrg if (params->this_chrset == CSET_DHL_TOP 691d4fba8b9Smrg || params->this_chrset == CSET_DHL_BOT) { 692d522f475Smrg res_y *= 2; 693d522f475Smrg pixel_size *= 2; 694d522f475Smrg } 695d522f475Smrg#if OPT_TRACE 696d522f475Smrg if (old_props.res_x != res_x 697d522f475Smrg || old_props.res_x != res_y 698d522f475Smrg || old_props.pixel_size != pixel_size 699d522f475Smrg || strcmp(old_props.spacing, props->spacing)) { 7009a64e1c5Smrg TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n", 701d4fba8b9Smrg params->attr_flags, params->draw_flags, params->this_chrset)); 702d522f475Smrg TRACE(("res_x = %d\n", res_x)); 703d522f475Smrg TRACE(("res_y = %d\n", res_y)); 704d522f475Smrg TRACE(("point_size = %s\n", props->point_size)); 705d522f475Smrg TRACE(("pixel_size = %d\n", pixel_size)); 706d522f475Smrg TRACE(("spacing = %s\n", props->spacing)); 707d522f475Smrg old_props.res_x = res_x; 708037a25ddSmrg old_props.res_y = res_y; 709d522f475Smrg old_props.pixel_size = pixel_size; 7100bd37d32Smrg old_props.spacing = old_spacing; 7110bd37d32Smrg sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 712d522f475Smrg } 713d522f475Smrg#endif 714d522f475Smrg 715d522f475Smrg append_fontname_str(&result, props->beginning); 716d522f475Smrg append_fontname_str(&result, weight); 717d522f475Smrg append_fontname_str(&result, props->slant); 718d522f475Smrg append_fontname_str(&result, props->wideness); 719d522f475Smrg append_fontname_str(&result, props->add_style); 720d522f475Smrg append_fontname_num(&result, pixel_size); 721d522f475Smrg append_fontname_str(&result, props->point_size); 722d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x); 723d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y); 724d522f475Smrg append_fontname_str(&result, props->spacing); 725d522f475Smrg append_fontname_str(&result, 0); 726d522f475Smrg append_fontname_str(&result, props->end); 727d522f475Smrg 728d4fba8b9Smrg xtermDerivedFont(result); 729d522f475Smrg return result; 730d522f475Smrg} 731d522f475Smrg#endif /* OPT_DEC_CHRSET */ 732d522f475Smrg 733d522f475Smrg/* 734d522f475Smrg * Case-independent comparison for font-names, including wildcards. 735d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 736d522f475Smrg * to use it). 737d522f475Smrg */ 738d522f475Smrgstatic Bool 739492d43a5Smrgsame_font_name(const char *pattern, const char *match) 740d522f475Smrg{ 741956cc18dSsnj Bool result = False; 742956cc18dSsnj 743956cc18dSsnj if (pattern && match) { 744956cc18dSsnj while (*pattern && *match) { 745956cc18dSsnj if (*pattern == *match) { 746956cc18dSsnj pattern++; 747956cc18dSsnj match++; 748956cc18dSsnj } else if (*pattern == '*' || *match == '*') { 749956cc18dSsnj if (same_font_name(pattern + 1, match)) { 750956cc18dSsnj return True; 751956cc18dSsnj } else if (same_font_name(pattern, match + 1)) { 752956cc18dSsnj return True; 753956cc18dSsnj } else { 754956cc18dSsnj return False; 755956cc18dSsnj } 756d522f475Smrg } else { 757956cc18dSsnj int p = x_toupper(*pattern++); 758956cc18dSsnj int m = x_toupper(*match++); 759956cc18dSsnj if (p != m) 760956cc18dSsnj return False; 761d522f475Smrg } 762d522f475Smrg } 763956cc18dSsnj result = (*pattern == *match); /* both should be NUL */ 764d522f475Smrg } 765956cc18dSsnj return result; 766d522f475Smrg} 767d522f475Smrg 768d522f475Smrg/* 769d522f475Smrg * Double-check the fontname that we asked for versus what the font server 770d522f475Smrg * actually gave us. The larger fixed fonts do not always have a matching bold 771d522f475Smrg * font, and the font server may try to scale another font or otherwise 772d522f475Smrg * substitute a mismatched font. 773d522f475Smrg * 774d522f475Smrg * If we cannot get what we requested, we will fallback to the original 775d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel 776d522f475Smrg * offset. 777d522f475Smrg */ 778d522f475Smrgstatic int 7799a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested) 780d522f475Smrg{ 7810bd37d32Smrg char *actual = 0; 782d522f475Smrg int got; 783d522f475Smrg 7840bd37d32Smrg if (get_font_name_props(dpy, fs, &actual) == 0) 785d522f475Smrg got = 0; 786d522f475Smrg else 787d522f475Smrg got = same_font_name(requested, actual); 7880bd37d32Smrg free(actual); 789d522f475Smrg return got; 790d522f475Smrg} 791d522f475Smrg 7929a64e1c5Smrg/* 7939a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able 7949a64e1c5Smrg * to check for missing glyphs in a comparable manner. 7959a64e1c5Smrg */ 7969a64e1c5Smrgstatic int 7979a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold) 7989a64e1c5Smrg{ 7999a64e1c5Smrg#define DATA "comparable_metrics: " 8009a64e1c5Smrg int result = 0; 8019a64e1c5Smrg 802dfb07bc7Smrg if (normal == 0 || bold == 0) { 803dfb07bc7Smrg ; 804dfb07bc7Smrg } else if (normal->all_chars_exist) { 8059a64e1c5Smrg if (bold->all_chars_exist) { 8069a64e1c5Smrg result = 1; 8079a64e1c5Smrg } else { 8089a64e1c5Smrg TRACE((DATA "all chars exist in normal font, but not in bold\n")); 8099a64e1c5Smrg } 8109a64e1c5Smrg } else if (normal->per_char != 0) { 8119a64e1c5Smrg if (bold->per_char != 0) { 8129a64e1c5Smrg result = 1; 8139a64e1c5Smrg } else { 8149a64e1c5Smrg TRACE((DATA "normal font has per-char metrics, but not bold\n")); 8159a64e1c5Smrg } 8169a64e1c5Smrg } else { 8179a64e1c5Smrg TRACE((DATA "normal font is not very good!\n")); 8189a64e1c5Smrg result = 1; /* give in (we're not going in reverse) */ 8199a64e1c5Smrg } 8209a64e1c5Smrg return result; 8219a64e1c5Smrg#undef DATA 8229a64e1c5Smrg} 8239a64e1c5Smrg 824d522f475Smrg/* 825d522f475Smrg * If the font server tries to adjust another font, it may not adjust it 826d522f475Smrg * properly. Check that the bounding boxes are compatible. Otherwise we'll 827d522f475Smrg * leave trash on the display when we mix normal and bold fonts. 828d522f475Smrg */ 829d522f475Smrgstatic int 8309a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs) 831d522f475Smrg{ 832956cc18dSsnj TScreen *screen = TScreenOf(xw); 833dfb07bc7Smrg int result = 0; 834dfb07bc7Smrg 835dfb07bc7Smrg if (nfs != 0 && bfs != 0) { 836dfb07bc7Smrg TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 837dfb07bc7Smrg nfs->ascent + nfs->descent, 838dfb07bc7Smrg bfs->ascent + bfs->descent, 839dfb07bc7Smrg nfs->min_bounds.width, bfs->min_bounds.width, 840dfb07bc7Smrg nfs->max_bounds.width, bfs->max_bounds.width)); 841dfb07bc7Smrg result = screen->free_bold_box 842dfb07bc7Smrg || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 843dfb07bc7Smrg && (nfs->min_bounds.width == bfs->min_bounds.width 844dfb07bc7Smrg || nfs->min_bounds.width == bfs->min_bounds.width + 1) 845dfb07bc7Smrg && (nfs->max_bounds.width == bfs->max_bounds.width 846dfb07bc7Smrg || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 847dfb07bc7Smrg } 848dfb07bc7Smrg return result; 849d522f475Smrg} 850d522f475Smrg 851d522f475Smrg/* 852d522f475Smrg * Check if the font looks like it has fixed width 853d522f475Smrg */ 854d522f475Smrgstatic int 8559a64e1c5Smrgis_fixed_font(XFontStruct *fs) 856d522f475Smrg{ 857d522f475Smrg if (fs) 858d522f475Smrg return (fs->min_bounds.width == fs->max_bounds.width); 859d522f475Smrg return 1; 860d522f475Smrg} 861d522f475Smrg 862d4fba8b9Smrgstatic int 863d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b) 864d4fba8b9Smrg{ 865d4fba8b9Smrg int result = 0; 866d4fba8b9Smrg if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width) 867d4fba8b9Smrg result = 1; 868d4fba8b9Smrg return result; 869d4fba8b9Smrg} 870d4fba8b9Smrg 871d522f475Smrg/* 872d522f475Smrg * Check if the font looks like a double width font (i.e. contains 873d522f475Smrg * characters of width X and 2X 874d522f475Smrg */ 875d522f475Smrg#if OPT_WIDE_CHARS 876d522f475Smrgstatic int 8779a64e1c5Smrgis_double_width_font(XFontStruct *fs) 878d522f475Smrg{ 879d4fba8b9Smrg return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width)); 880d522f475Smrg} 881d522f475Smrg#else 882d522f475Smrg#define is_double_width_font(fs) 0 883d522f475Smrg#endif 884d522f475Smrg 885d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 886d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890" 887d522f475Smrg 888d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */ 889d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 890d522f475Smrg "\xe5\x9b\x9b\xe4\xba\x94" \ 891d522f475Smrg "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 892d522f475Smrg "\xe4\xb9\x9d\xef\xa6\xb2" 893d522f475Smrg 894d522f475Smrg/* '1234567890' in Korean script in UTF-8 */ 895d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 896d522f475Smrg "\xec\x82\xac\xec\x98\xa4" \ 897d522f475Smrg "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 898d522f475Smrg "\xea\xb5\xac\xec\x98\x81" 899d522f475Smrg 900d522f475Smrg#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 901d522f475Smrg#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 902d522f475Smrg#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 903d522f475Smrg#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 904d522f475Smrg 905d522f475Smrgstatic Bool 9069a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font) 907d522f475Smrg{ 908d522f475Smrg XGlyphInfo gi1, gi2; 909d522f475Smrg FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 9100bd37d32Smrg String fwstr = FULL_WIDTH_TEST_STRING; 9110bd37d32Smrg String hwstr = HALF_WIDTH_TEST_STRING; 912d522f475Smrg 913d522f475Smrg /* Some Korean fonts don't have Chinese characters at all. */ 914d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 915d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 916d522f475Smrg return False; /* Not a CJK font */ 917d522f475Smrg else /* a Korean font without CJK Ideographs */ 918d522f475Smrg fwstr = FULL_WIDTH_TEST_STRING2; 919d522f475Smrg } 920d522f475Smrg 921d522f475Smrg XftTextExtents32(dpy, font, &c1, 1, &gi1); 922d522f475Smrg XftTextExtents32(dpy, font, &c2, 1, &gi2); 923d522f475Smrg if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 924d522f475Smrg return False; 925d522f475Smrg 9260bd37d32Smrg XftTextExtentsUtf8(dpy, 9270bd37d32Smrg font, 9280bd37d32Smrg (_Xconst FcChar8 *) hwstr, 9290bd37d32Smrg (int) strlen(hwstr), 9300bd37d32Smrg &gi1); 9310bd37d32Smrg XftTextExtentsUtf8(dpy, 9320bd37d32Smrg font, 9330bd37d32Smrg (_Xconst FcChar8 *) fwstr, 9340bd37d32Smrg (int) strlen(fwstr), 9350bd37d32Smrg &gi2); 936d522f475Smrg 937d522f475Smrg /* 938d522f475Smrg * fontconfig and Xft prior to 2.2(?) set the width of half-width 939d522f475Smrg * characters identical to that of full-width character in CJK double-width 940d522f475Smrg * (bi-width / monospace) font even though the former is half as wide as 941d522f475Smrg * the latter. This was fixed sometime before the release of fontconfig 942d522f475Smrg * 2.2 in early 2003. See 943d522f475Smrg * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 944d522f475Smrg * In the meantime, we have to check both possibilities. 945d522f475Smrg */ 946d522f475Smrg return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 947d522f475Smrg} 948d522f475Smrg#else 949d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0 950d522f475Smrg#endif 951d522f475Smrg 952d522f475Smrg#define EmptyFont(fs) (fs != 0 \ 953d522f475Smrg && ((fs)->ascent + (fs)->descent == 0 \ 954d522f475Smrg || (fs)->max_bounds.width == 0)) 955d522f475Smrg 956d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 957d522f475Smrg * (fs)->max_bounds.width) 958d522f475Smrg 959d522f475Smrgconst VTFontNames * 96020d2c4d2SmrgxtermFontName(const char *normal) 961d522f475Smrg{ 962d522f475Smrg static VTFontNames data; 9639a64e1c5Smrg FREE_STRING(data.f_n); 964d522f475Smrg memset(&data, 0, sizeof(data)); 965dfb07bc7Smrg if (normal) 966dfb07bc7Smrg data.f_n = x_strdup(normal); 967dfb07bc7Smrg return &data; 968dfb07bc7Smrg} 969dfb07bc7Smrg 970dfb07bc7Smrgconst VTFontNames * 971dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw) 972dfb07bc7Smrg{ 973dfb07bc7Smrg static VTFontNames data; 974dfb07bc7Smrg memset(&data, 0, sizeof(data)); 975dfb07bc7Smrg data.f_n = DefaultFontN(xw); 976dfb07bc7Smrg data.f_b = DefaultFontB(xw); 977dfb07bc7Smrg#if OPT_WIDE_CHARS 978dfb07bc7Smrg data.f_w = DefaultFontW(xw); 979dfb07bc7Smrg data.f_wb = DefaultFontWB(xw); 980dfb07bc7Smrg#endif 981d522f475Smrg return &data; 982d522f475Smrg} 983d522f475Smrg 984d522f475Smrgstatic void 985fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 986d522f475Smrg{ 987d522f475Smrg if (name != 0) { 9889a64e1c5Smrg String last = screen->menu_font_names[fontnum][which]; 989d522f475Smrg if (last != 0) { 990d522f475Smrg if (strcmp(last, name)) { 9919a64e1c5Smrg FREE_STRING(last); 992d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 993d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 994d522f475Smrg } 995d522f475Smrg } else { 996d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 997d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 998d522f475Smrg } 999d522f475Smrg } 1000d522f475Smrg} 1001d522f475Smrg 1002dfb07bc7Smrgstatic void 1003d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name) 1004dfb07bc7Smrg{ 1005d4fba8b9Smrg static NameList *reported; 1006d4fba8b9Smrg NameList *list; 1007dfb07bc7Smrg 1008dfb07bc7Smrg switch (xw->misc.fontWarnings) { 1009dfb07bc7Smrg case fwNever: 1010dfb07bc7Smrg return; 1011dfb07bc7Smrg case fwResource: 1012d4fba8b9Smrg if (is_derived_font_name(name)) 1013d4fba8b9Smrg return; 1014dfb07bc7Smrg break; 1015dfb07bc7Smrg case fwAlways: 1016dfb07bc7Smrg break; 1017dfb07bc7Smrg } 1018d4fba8b9Smrg for (list = reported; list != 0; list = list->next) { 1019d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 1020d4fba8b9Smrg return; 1021d4fba8b9Smrg } 1022d4fba8b9Smrg } 1023d4fba8b9Smrg if ((list = TypeMalloc(NameList)) != 0) { 1024d4fba8b9Smrg list->name = x_strdup(name); 1025d4fba8b9Smrg list->next = reported; 1026d4fba8b9Smrg reported = list; 1027d4fba8b9Smrg } 1028d4fba8b9Smrg xtermWarning("cannot %s%s%s %sfont \"%s\"\n", 1029d4fba8b9Smrg who, *tag ? " " : "", tag, 1030d4fba8b9Smrg is_derived_font_name(name) ? "derived " : "", 1031d4fba8b9Smrg name); 1032dfb07bc7Smrg} 1033dfb07bc7Smrg 1034d4fba8b9Smrg#if OPT_RENDERFONT 1035d4fba8b9Smrgstatic void 1036d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name) 1037d4fba8b9Smrg{ 1038d4fba8b9Smrg switch (xw->misc.fontWarnings) { 1039d4fba8b9Smrg case fwNever: 1040d4fba8b9Smrg return; 1041d4fba8b9Smrg case fwResource: 1042d4fba8b9Smrg /* these combinations of wide/bold/italic are all "derived" */ 1043d4fba8b9Smrg return; 1044d4fba8b9Smrg case fwAlways: 1045d4fba8b9Smrg break; 1046d4fba8b9Smrg } 1047d4fba8b9Smrg xtermWarning("did not find a usable %s TrueType font\n", name); 1048d4fba8b9Smrg} 1049d4fba8b9Smrg#endif 1050d4fba8b9Smrg 10518f44fb3bSmrgXFontStruct * 10528f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name) 10538f44fb3bSmrg{ 10548f44fb3bSmrg XFontStruct *result = NULL; 10558f44fb3bSmrg size_t have = strlen(name); 10568f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 10578f44fb3bSmrg ; /* just ignore it */ 10588f44fb3bSmrg } else { 10598f44fb3bSmrg TScreen *screen = TScreenOf(xw); 10608f44fb3bSmrg result = XLoadQueryFont(screen->display, name); 10618f44fb3bSmrg } 10628f44fb3bSmrg return result; 10638f44fb3bSmrg} 10648f44fb3bSmrg 1065d522f475Smrg/* 1066d1603babSmrg * Open the given font and verify that it is non-empty. Return false on 1067d522f475Smrg * failure. 1068d522f475Smrg */ 1069d522f475SmrgBool 1070956cc18dSsnjxtermOpenFont(XtermWidget xw, 1071956cc18dSsnj const char *name, 1072956cc18dSsnj XTermFonts * result, 1073d1603babSmrg XTermFonts * current, 1074956cc18dSsnj Bool force) 1075d522f475Smrg{ 1076d522f475Smrg Bool code = False; 1077d522f475Smrg 1078d4fba8b9Smrg TRACE(("xtermOpenFont %d:%d '%s'\n", 1079d4fba8b9Smrg result->warn, xw->misc.fontWarnings, NonNull(name))); 1080d1603babSmrg 1081492d43a5Smrg if (!IsEmpty(name)) { 1082d1603babSmrg Bool existing = (current != NULL 1083d1603babSmrg && current->fs != NULL 1084d1603babSmrg && current->fn != NULL); 1085d1603babSmrg 10868f44fb3bSmrg if ((result->fs = xtermLoadQueryFont(xw, name)) != 0) { 1087956cc18dSsnj code = True; 1088956cc18dSsnj if (EmptyFont(result->fs)) { 1089dfb07bc7Smrg xtermCloseFont(xw, result); 1090956cc18dSsnj code = False; 1091956cc18dSsnj } else { 1092956cc18dSsnj result->fn = x_strdup(name); 1093956cc18dSsnj } 109420d2c4d2Smrg } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 1095dfb07bc7Smrg if (result->warn <= xw->misc.fontWarnings 1096956cc18dSsnj#if OPT_RENDERFONT 1097956cc18dSsnj && !UsingRenderFont(xw) 1098956cc18dSsnj#endif 1099956cc18dSsnj ) { 1100dfb07bc7Smrg cannotFont(xw, "load", "", name); 1101956cc18dSsnj } else { 1102492d43a5Smrg TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 1103956cc18dSsnj } 1104d1603babSmrg if (existing) { 1105d1603babSmrg TRACE(("...continue using font '%s'\n", current->fn)); 1106d1603babSmrg result->fn = x_strdup(current->fn); 1107d1603babSmrg result->fs = current->fs; 1108d1603babSmrg } else if (force) { 1109d4fba8b9Smrg NoFontWarning(result); 1110d1603babSmrg code = xtermOpenFont(xw, DEFFONT, result, NULL, True); 1111956cc18dSsnj } 1112d522f475Smrg } 1113d522f475Smrg } 1114d4fba8b9Smrg NoFontWarning(result); 1115d522f475Smrg return code; 1116d522f475Smrg} 1117d522f475Smrg 1118d522f475Smrg/* 1119956cc18dSsnj * Close the font and free the font info. 1120d522f475Smrg */ 1121dfb07bc7Smrgvoid 1122d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt) 1123d522f475Smrg{ 1124d522f475Smrg if (fnt != 0 && fnt->fs != 0) { 1125d522f475Smrg TScreen *screen = TScreenOf(xw); 1126d522f475Smrg 1127d522f475Smrg clrCgsFonts(xw, WhichVWin(screen), fnt); 1128d522f475Smrg XFreeFont(screen->display, fnt->fs); 1129d522f475Smrg xtermFreeFontInfo(fnt); 1130d522f475Smrg } 1131d522f475Smrg} 1132d522f475Smrg 1133037a25ddSmrg/* 1134037a25ddSmrg * Close and free the font (as well as any aliases). 1135037a25ddSmrg */ 1136037a25ddSmrgstatic void 1137037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which) 1138037a25ddSmrg{ 1139037a25ddSmrg XFontStruct *thisFont = fnts[which].fs; 1140037a25ddSmrg 1141037a25ddSmrg if (thisFont != 0) { 1142037a25ddSmrg int k; 1143037a25ddSmrg 1144037a25ddSmrg xtermCloseFont(xw, &fnts[which]); 1145037a25ddSmrg for (k = 0; k < fMAX; ++k) { 1146037a25ddSmrg if (k != which) { 1147037a25ddSmrg if (thisFont == fnts[k].fs) { 1148037a25ddSmrg xtermFreeFontInfo(&fnts[k]); 1149037a25ddSmrg } 1150037a25ddSmrg } 1151037a25ddSmrg } 1152037a25ddSmrg } 1153037a25ddSmrg} 1154037a25ddSmrg 1155d522f475Smrg/* 1156d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer. 1157d522f475Smrg */ 1158d522f475Smrgvoid 1159d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 1160d522f475Smrg{ 1161037a25ddSmrg int j; 1162d522f475Smrg 1163d522f475Smrg for (j = 0; j < fMAX; ++j) { 1164037a25ddSmrg xtermCloseFont2(xw, fnts, j); 1165d522f475Smrg } 1166d522f475Smrg} 1167d522f475Smrg 1168d522f475Smrg/* 1169d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but 1170d522f475Smrg * ensuring that the names are reallocated to simplify freeing. 1171d522f475Smrg */ 1172d522f475Smrgvoid 1173d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 1174d522f475Smrg{ 1175d522f475Smrg xtermFreeFontInfo(target); 1176d522f475Smrg target->chrset = source->chrset; 1177d522f475Smrg target->flags = source->flags; 1178d522f475Smrg target->fn = x_strdup(source->fn); 1179d522f475Smrg target->fs = source->fs; 1180dfb07bc7Smrg target->warn = source->warn; 1181d522f475Smrg} 1182d522f475Smrg 1183d522f475Smrgvoid 1184d522f475SmrgxtermFreeFontInfo(XTermFonts * target) 1185d522f475Smrg{ 1186d522f475Smrg target->chrset = 0; 1187d522f475Smrg target->flags = 0; 1188d4fba8b9Smrg FreeAndNull(target->fn); 1189d522f475Smrg target->fs = 0; 1190d522f475Smrg} 1191d522f475Smrg 1192fa3f02f3Smrg#if OPT_REPORT_FONTS 1193fa3f02f3Smrgstatic void 1194fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs) 1195fa3f02f3Smrg{ 1196d1603babSmrg ReportFonts("\t\t%s:\n", tag); 1197d1603babSmrg ReportFonts("\t\t\tlbearing: %d\n", cs->lbearing); 1198d1603babSmrg ReportFonts("\t\t\trbearing: %d\n", cs->rbearing); 1199d1603babSmrg ReportFonts("\t\t\twidth: %d\n", cs->width); 1200d1603babSmrg ReportFonts("\t\t\tascent: %d\n", cs->ascent); 1201d1603babSmrg ReportFonts("\t\t\tdescent: %d\n", cs->descent); 1202fa3f02f3Smrg} 1203fa3f02f3Smrg 1204fa3f02f3Smrgstatic void 1205fa3f02f3SmrgreportOneVTFont(const char *tag, 1206fa3f02f3Smrg XTermFonts * fnt) 1207fa3f02f3Smrg{ 1208dfb07bc7Smrg if (!IsEmpty(fnt->fn) && fnt->fs != 0) { 1209fa3f02f3Smrg XFontStruct *fs = fnt->fs; 1210fa3f02f3Smrg unsigned first_char = 0; 1211fa3f02f3Smrg unsigned last_char = 0; 1212fa3f02f3Smrg 1213fa3f02f3Smrg if (fs->max_byte1 == 0) { 1214fa3f02f3Smrg first_char = fs->min_char_or_byte2; 1215fa3f02f3Smrg last_char = fs->max_char_or_byte2; 1216fa3f02f3Smrg } else { 1217fa3f02f3Smrg first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1218fa3f02f3Smrg last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1219fa3f02f3Smrg } 1220fa3f02f3Smrg 1221d1603babSmrg ReportFonts("\t%s: %s\n", tag, NonNull(fnt->fn)); 1222d1603babSmrg ReportFonts("\t\tall chars: %s\n", (fs->all_chars_exist 1223d1603babSmrg ? "yes" 1224d1603babSmrg : "no")); 1225d1603babSmrg ReportFonts("\t\tdefault char: %u\n", fs->default_char); 1226d1603babSmrg ReportFonts("\t\tdirection: %u\n", fs->direction); 1227d1603babSmrg ReportFonts("\t\tascent: %d\n", fs->ascent); 1228d1603babSmrg ReportFonts("\t\tdescent: %d\n", fs->descent); 1229d1603babSmrg ReportFonts("\t\tfirst char: %u\n", first_char); 1230d1603babSmrg ReportFonts("\t\tlast char: %u\n", last_char); 1231d1603babSmrg ReportFonts("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 12329a64e1c5Smrg if (FontLacksMetrics(fnt)) { 1233d1603babSmrg ReportFonts("\t\tmissing-chars: ?\n"); 1234d1603babSmrg ReportFonts("\t\tpresent-chars: ?\n"); 12359a64e1c5Smrg } else { 12369a64e1c5Smrg unsigned missing = 0; 1237037a25ddSmrg unsigned ch; 12389a64e1c5Smrg for (ch = first_char; ch <= last_char; ++ch) { 12399a64e1c5Smrg if (xtermMissingChar(ch, fnt)) { 12409a64e1c5Smrg ++missing; 12419a64e1c5Smrg } 12429a64e1c5Smrg } 1243d1603babSmrg ReportFonts("\t\tmissing-chars: %u\n", missing); 1244d1603babSmrg ReportFonts("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 12459a64e1c5Smrg } 1246d1603babSmrg ReportFonts("\t\tmin_byte1: %u\n", fs->min_byte1); 1247d1603babSmrg ReportFonts("\t\tmax_byte1: %u\n", fs->max_byte1); 1248d1603babSmrg ReportFonts("\t\tproperties: %d\n", fs->n_properties); 1249fa3f02f3Smrg reportXCharStruct("min_bounds", &(fs->min_bounds)); 1250fa3f02f3Smrg reportXCharStruct("max_bounds", &(fs->max_bounds)); 1251fa3f02f3Smrg /* TODO: report fs->properties and fs->per_char */ 1252fa3f02f3Smrg } 1253fa3f02f3Smrg} 1254fa3f02f3Smrg 1255fa3f02f3Smrgstatic void 1256fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum) 1257fa3f02f3Smrg{ 1258fa3f02f3Smrg if (resource.reportFonts) { 1259fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 1260fa3f02f3Smrg 1261fa3f02f3Smrg if (fontnum) { 1262d1603babSmrg ReportFonts("Loaded VTFonts(font%d)\n", fontnum); 1263fa3f02f3Smrg } else { 1264d1603babSmrg ReportFonts("Loaded VTFonts(default)\n"); 1265fa3f02f3Smrg } 1266dfb07bc7Smrg 1267d4fba8b9Smrg reportOneVTFont("fNorm", GetNormalFont(screen, fNorm)); 1268d4fba8b9Smrg reportOneVTFont("fBold", GetNormalFont(screen, fBold)); 1269fa3f02f3Smrg#if OPT_WIDE_CHARS 1270d4fba8b9Smrg reportOneVTFont("fWide", GetNormalFont(screen, fWide)); 1271d4fba8b9Smrg reportOneVTFont("fWBold", GetNormalFont(screen, fWBold)); 1272fa3f02f3Smrg#endif 1273fa3f02f3Smrg } 1274fa3f02f3Smrg} 1275fa3f02f3Smrg#endif 1276fa3f02f3Smrg 12779a64e1c5Smrgvoid 1278d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc) 12799a64e1c5Smrg{ 12809a64e1c5Smrg TScreen *screen = TScreenOf(xw); 12819a64e1c5Smrg VTwin *win = WhichVWin(screen); 1282d4fba8b9Smrg Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground); 1283d4fba8b9Smrg Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background); 1284dfb07bc7Smrg 12859a64e1c5Smrg setCgsFore(xw, win, gcNorm, new_normal); 12869a64e1c5Smrg setCgsBack(xw, win, gcNorm, new_revers); 1287dfb07bc7Smrg setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm)); 12889a64e1c5Smrg 12899a64e1c5Smrg copyCgs(xw, win, gcBold, gcNorm); 1290d4fba8b9Smrg setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold); 12919a64e1c5Smrg 12929a64e1c5Smrg setCgsFore(xw, win, gcNormReverse, new_revers); 12939a64e1c5Smrg setCgsBack(xw, win, gcNormReverse, new_normal); 1294dfb07bc7Smrg setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm)); 12959a64e1c5Smrg 12969a64e1c5Smrg copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1297d4fba8b9Smrg setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold); 12989a64e1c5Smrg 12999a64e1c5Smrg if_OPT_WIDE_CHARS(screen, { 1300dfb07bc7Smrg XTermFonts *wide_xx = myfunc(screen, fWide); 1301dfb07bc7Smrg XTermFonts *bold_xx = myfunc(screen, fWBold); 1302dfb07bc7Smrg if (wide_xx->fs != 0 1303dfb07bc7Smrg && bold_xx->fs != 0) { 13049a64e1c5Smrg setCgsFore(xw, win, gcWide, new_normal); 13059a64e1c5Smrg setCgsBack(xw, win, gcWide, new_revers); 1306dfb07bc7Smrg setCgsFont(xw, win, gcWide, wide_xx); 13079a64e1c5Smrg 13089a64e1c5Smrg copyCgs(xw, win, gcWBold, gcWide); 1309dfb07bc7Smrg setCgsFont(xw, win, gcWBold, bold_xx); 13109a64e1c5Smrg 13119a64e1c5Smrg setCgsFore(xw, win, gcWideReverse, new_revers); 13129a64e1c5Smrg setCgsBack(xw, win, gcWideReverse, new_normal); 1313dfb07bc7Smrg setCgsFont(xw, win, gcWideReverse, wide_xx); 13149a64e1c5Smrg 13159a64e1c5Smrg copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1316dfb07bc7Smrg setCgsFont(xw, win, gcWBoldReverse, bold_xx); 13179a64e1c5Smrg } 13189a64e1c5Smrg }); 13199a64e1c5Smrg} 13209a64e1c5Smrg 1321d4fba8b9Smrg#if OPT_WIDE_ATTRS 1322d4fba8b9Smrgunsigned 1323d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs) 1324d4fba8b9Smrg{ 1325c48a5815Smrg TScreen *screen = TScreenOf(xw); 1326c48a5815Smrg 132750027b5bSmrg (void) screen; 1328c48a5815Smrg if (UseItalicFont(screen)) { 1329c48a5815Smrg if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) { 1330c48a5815Smrg xtermLoadItalics(xw); 1331c48a5815Smrg xtermUpdateFontGCs(xw, getItalicFont); 1332c48a5815Smrg } else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) { 1333c48a5815Smrg xtermUpdateFontGCs(xw, getNormalFont); 1334c48a5815Smrg } 1335d4fba8b9Smrg } 1336d4fba8b9Smrg return new_attrs; 1337d4fba8b9Smrg} 1338d4fba8b9Smrg#endif 1339d4fba8b9Smrg 1340d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS 13419a64e1c5Smrgstatic void 13429a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp) 13439a64e1c5Smrg{ 13449a64e1c5Smrg if (fp->fs != 0) { 13459a64e1c5Smrg if (FontLacksMetrics(fp)) { 13469a64e1c5Smrg TRACE(("%s font lacks metrics\n", name)); 13479a64e1c5Smrg } else if (FontIsIncomplete(fp)) { 13489a64e1c5Smrg TRACE(("%s font is incomplete\n", name)); 13499a64e1c5Smrg } else { 13509a64e1c5Smrg TRACE(("%s font is complete\n", name)); 13519a64e1c5Smrg } 13529a64e1c5Smrg } else { 13539a64e1c5Smrg TRACE(("%s font is missing\n", name)); 13549a64e1c5Smrg } 13559a64e1c5Smrg} 13569a64e1c5Smrg#endif 13579a64e1c5Smrg 1358dfb07bc7Smrgstatic Bool 1359dfb07bc7SmrgloadNormFP(XtermWidget xw, 1360dfb07bc7Smrg char **nameOutP, 1361dfb07bc7Smrg XTermFonts * infoOut, 1362d1603babSmrg XTermFonts * current, 1363dfb07bc7Smrg int fontnum) 1364dfb07bc7Smrg{ 1365dfb07bc7Smrg Bool status = True; 1366dfb07bc7Smrg 1367dfb07bc7Smrg TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP))); 1368dfb07bc7Smrg 1369dfb07bc7Smrg if (!xtermOpenFont(xw, 1370dfb07bc7Smrg *nameOutP, 1371dfb07bc7Smrg infoOut, 1372d1603babSmrg current, (fontnum == fontMenu_default))) { 1373dfb07bc7Smrg /* 1374dfb07bc7Smrg * If we are opening the default font, and it happens to be missing, 1375dfb07bc7Smrg * force that to the compiled-in default font, e.g., "fixed". If we 1376dfb07bc7Smrg * cannot open the font, disable it from the menu. 1377dfb07bc7Smrg */ 1378dfb07bc7Smrg if (fontnum != fontMenu_fontsel) { 1379dfb07bc7Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1380dfb07bc7Smrg } 1381dfb07bc7Smrg status = False; 1382dfb07bc7Smrg } 1383dfb07bc7Smrg return status; 1384dfb07bc7Smrg} 1385dfb07bc7Smrg 1386dfb07bc7Smrgstatic Bool 1387dfb07bc7SmrgloadBoldFP(XtermWidget xw, 1388dfb07bc7Smrg char **nameOutP, 1389dfb07bc7Smrg XTermFonts * infoOut, 1390dfb07bc7Smrg const char *nameRef, 1391dfb07bc7Smrg XTermFonts * infoRef, 1392dfb07bc7Smrg int fontnum) 1393dfb07bc7Smrg{ 1394dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1395dfb07bc7Smrg Bool status = True; 1396dfb07bc7Smrg 1397dfb07bc7Smrg TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP))); 1398dfb07bc7Smrg 1399dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1400dfb07bc7Smrg FontNameProperties *fp; 1401dfb07bc7Smrg char *normal = x_strdup(nameRef); 1402dfb07bc7Smrg 1403dfb07bc7Smrg fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1404dfb07bc7Smrg if (fp != 0) { 1405d4fba8b9Smrg NoFontWarning(infoOut); 1406dfb07bc7Smrg *nameOutP = bold_font_name(fp, fp->average_width); 1407d1603babSmrg if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) { 1408dfb07bc7Smrg free(*nameOutP); 1409dfb07bc7Smrg *nameOutP = bold_font_name(fp, -1); 1410d1603babSmrg xtermOpenFont(xw, *nameOutP, infoOut, NULL, False); 1411dfb07bc7Smrg } 1412dfb07bc7Smrg TRACE(("...derived bold '%s'\n", NonNull(*nameOutP))); 1413dfb07bc7Smrg } 1414dfb07bc7Smrg if (fp == 0 || infoOut->fs == 0) { 1415dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1416dfb07bc7Smrg TRACE(("...cannot load a matching bold font\n")); 1417dfb07bc7Smrg } else if (comparable_metrics(infoRef->fs, infoOut->fs) 1418dfb07bc7Smrg && same_font_size(xw, infoRef->fs, infoOut->fs) 1419dfb07bc7Smrg && got_bold_font(screen->display, infoOut->fs, *nameOutP)) { 1420dfb07bc7Smrg TRACE(("...got a matching bold font\n")); 1421dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1422dfb07bc7Smrg } else { 1423dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1424dfb07bc7Smrg *infoOut = *infoRef; 1425dfb07bc7Smrg TRACE(("...did not get a matching bold font\n")); 1426dfb07bc7Smrg } 1427dfb07bc7Smrg free(normal); 1428d1603babSmrg } else if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) { 1429dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1430dfb07bc7Smrg TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP))); 1431dfb07bc7Smrg } else { 1432dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1433dfb07bc7Smrg } 1434dfb07bc7Smrg 1435dfb07bc7Smrg /* 1436dfb07bc7Smrg * Most of the time this call to load the font will succeed, even if 1437dfb07bc7Smrg * there is no wide font : the X server doubles the width of the 1438dfb07bc7Smrg * normal font, or similar. 1439dfb07bc7Smrg * 1440dfb07bc7Smrg * But if it did fail for some reason, then nevermind. 1441dfb07bc7Smrg */ 1442dfb07bc7Smrg if (EmptyFont(infoOut->fs)) 1443dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1444dfb07bc7Smrg 1445dfb07bc7Smrg if (!same_font_size(xw, infoRef->fs, infoOut->fs) 1446dfb07bc7Smrg && (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) { 1447dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold fonts\n")); 1448dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1449dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1450dfb07bc7Smrg } 1451dfb07bc7Smrg 1452dfb07bc7Smrg return status; 1453dfb07bc7Smrg} 1454dfb07bc7Smrg 1455dfb07bc7Smrg#if OPT_WIDE_CHARS 1456dfb07bc7Smrgstatic Bool 1457dfb07bc7SmrgloadWideFP(XtermWidget xw, 1458dfb07bc7Smrg char **nameOutP, 1459dfb07bc7Smrg XTermFonts * infoOut, 1460dfb07bc7Smrg const char *nameRef, 1461dfb07bc7Smrg XTermFonts * infoRef, 1462dfb07bc7Smrg int fontnum) 1463dfb07bc7Smrg{ 1464dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1465dfb07bc7Smrg Bool status = True; 1466dfb07bc7Smrg 1467dfb07bc7Smrg TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP))); 1468dfb07bc7Smrg 1469d4fba8b9Smrg if (!check_fontname(*nameOutP) 1470d4fba8b9Smrg && (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) { 1471dfb07bc7Smrg char *normal = x_strdup(nameRef); 1472d4fba8b9Smrg FontNameProperties *fp = get_font_name_props(screen->display, 1473d4fba8b9Smrg infoRef->fs, &normal); 1474dfb07bc7Smrg if (fp != 0) { 1475dfb07bc7Smrg *nameOutP = wide_font_name(fp); 1476d4fba8b9Smrg NoFontWarning(infoOut); 1477dfb07bc7Smrg } 1478dfb07bc7Smrg free(normal); 1479dfb07bc7Smrg } 1480dfb07bc7Smrg 1481dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1482d1603babSmrg if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False) 1483d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1484d4fba8b9Smrg && EmptyFont(infoOut->fs)) { 1485d4fba8b9Smrg xtermCloseFont2(xw, infoOut - fWide, fWide); 1486d4fba8b9Smrg } 1487d4fba8b9Smrg if (infoOut->fs == 0) { 1488dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1489d4fba8b9Smrg } else { 1490d4fba8b9Smrg TRACE(("...%s wide %s\n", 1491d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1492d4fba8b9Smrg NonNull(*nameOutP))); 1493d4fba8b9Smrg cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1494dfb07bc7Smrg } 1495dfb07bc7Smrg } else { 1496dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1497dfb07bc7Smrg } 1498c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width 1499c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width 1500c48a5815Smrg xw->work.force_wideFont = False; 1501c48a5815Smrg if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) { 1502c48a5815Smrg TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs))); 1503c48a5815Smrg TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs))); 1504c48a5815Smrg TRACE(("...actual width %d\n", MaxWidthOf(infoOut->fs))); 1505c48a5815Smrg xw->work.force_wideFont = True; 1506c48a5815Smrg } 1507dfb07bc7Smrg return status; 1508dfb07bc7Smrg} 1509dfb07bc7Smrg 1510dfb07bc7Smrgstatic Bool 1511dfb07bc7SmrgloadWBoldFP(XtermWidget xw, 1512dfb07bc7Smrg char **nameOutP, 1513dfb07bc7Smrg XTermFonts * infoOut, 1514dfb07bc7Smrg const char *wideNameRef, XTermFonts * wideInfoRef, 1515dfb07bc7Smrg const char *boldNameRef, XTermFonts * boldInfoRef, 1516dfb07bc7Smrg int fontnum) 1517dfb07bc7Smrg{ 1518dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1519dfb07bc7Smrg Bool status = True; 1520dfb07bc7Smrg char *bold = NULL; 1521dfb07bc7Smrg 1522dfb07bc7Smrg TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP))); 1523dfb07bc7Smrg 1524dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1525dfb07bc7Smrg FontNameProperties *fp; 1526dfb07bc7Smrg fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold); 1527dfb07bc7Smrg if (fp != 0) { 1528dfb07bc7Smrg *nameOutP = widebold_font_name(fp); 1529d4fba8b9Smrg NoFontWarning(infoOut); 1530dfb07bc7Smrg } 1531dfb07bc7Smrg } 1532dfb07bc7Smrg 1533dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1534dfb07bc7Smrg 1535d1603babSmrg if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False) 1536d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1537dfb07bc7Smrg && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) { 1538dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1539dfb07bc7Smrg } 1540dfb07bc7Smrg 1541dfb07bc7Smrg if (infoOut->fs == 0) { 1542d4fba8b9Smrg if (is_derived_font_name(*nameOutP)) 1543dfb07bc7Smrg free(*nameOutP); 1544dfb07bc7Smrg if (IsEmpty(wideNameRef)) { 1545dfb07bc7Smrg *nameOutP = x_strdup(boldNameRef); 1546dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1547dfb07bc7Smrg TRACE(("...cannot load wide-bold, use bold %s\n", 1548dfb07bc7Smrg NonNull(boldNameRef))); 1549dfb07bc7Smrg } else { 1550dfb07bc7Smrg *nameOutP = x_strdup(wideNameRef); 1551dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1552dfb07bc7Smrg TRACE(("...cannot load wide-bold, use wide %s\n", 1553dfb07bc7Smrg NonNull(wideNameRef))); 1554dfb07bc7Smrg } 1555dfb07bc7Smrg } else { 1556dfb07bc7Smrg TRACE(("...%s wide/bold %s\n", 1557d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1558dfb07bc7Smrg NonNull(*nameOutP))); 1559dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fWBold, *nameOutP); 1560dfb07bc7Smrg } 1561dfb07bc7Smrg } else if (is_double_width_font(boldInfoRef->fs)) { 1562dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1563dfb07bc7Smrg TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef))); 1564dfb07bc7Smrg } else { 1565dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1566dfb07bc7Smrg TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef))); 1567dfb07bc7Smrg } 1568dfb07bc7Smrg 1569dfb07bc7Smrg free(bold); 1570dfb07bc7Smrg 1571dfb07bc7Smrg if (EmptyFont(infoOut->fs)) { 1572dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1573dfb07bc7Smrg } else { 1574dfb07bc7Smrg if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs) 1575dfb07bc7Smrg || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs) 1576dfb07bc7Smrg && is_fixed_font(wideInfoRef->fs) 1577dfb07bc7Smrg && is_fixed_font(infoOut->fs)))) { 1578dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1579dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1580dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1581dfb07bc7Smrg } 1582dfb07bc7Smrg } 1583dfb07bc7Smrg 1584dfb07bc7Smrg return status; 1585dfb07bc7Smrg} 1586dfb07bc7Smrg#endif 1587dfb07bc7Smrg 1588d1603babSmrg/* 1589d1603babSmrg * Load a given bitmap font, along with the bold/wide variants. 1590d1603babSmrg * Returns nonzero on success. 1591d1603babSmrg */ 1592d522f475Smrgint 1593d522f475SmrgxtermLoadFont(XtermWidget xw, 1594d522f475Smrg const VTFontNames * fonts, 1595d522f475Smrg Bool doresize, 1596d522f475Smrg int fontnum) 1597d522f475Smrg{ 1598956cc18dSsnj TScreen *screen = TScreenOf(xw); 1599d522f475Smrg VTwin *win = WhichVWin(screen); 1600d522f475Smrg 1601d1603babSmrg VTFontNames new_fnames; 1602d1603babSmrg XTermFonts new_fonts[fMAX]; 1603d1603babSmrg XTermFonts old_fonts[fMAX]; 1604d522f475Smrg char *tmpname = NULL; 1605956cc18dSsnj Boolean proportional = False; 1606d1603babSmrg Boolean recovered; 1607d1603babSmrg int code = 0; 1608d522f475Smrg 1609d1603babSmrg memset(&new_fnames, 0, sizeof(new_fnames)); 1610d1603babSmrg memset(new_fonts, 0, sizeof(new_fonts)); 1611d1603babSmrg memcpy(&old_fonts, screen->fnts, sizeof(old_fonts)); 1612d522f475Smrg 1613d522f475Smrg if (fonts != 0) 1614d1603babSmrg new_fnames = *fonts; 1615d1603babSmrg if (!check_fontname(new_fnames.f_n)) 1616d1603babSmrg return code; 1617d522f475Smrg 1618d522f475Smrg if (fontnum == fontMenu_fontescape 1619d1603babSmrg && new_fnames.f_n != screen->MenuFontName(fontnum)) { 1620d1603babSmrg if ((tmpname = x_strdup(new_fnames.f_n)) == 0) 1621d1603babSmrg return code; 1622d522f475Smrg } 1623d522f475Smrg 1624d1603babSmrg TRACE(("Begin Cgs - xtermLoadFont(%s)\n", new_fnames.f_n)); 1625d522f475Smrg releaseWindowGCs(xw, win); 1626d522f475Smrg 1627956cc18dSsnj#define DbgResource(name, field, index) \ 1628956cc18dSsnj TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1629956cc18dSsnj fontnum, \ 1630d1603babSmrg (new_fonts[index].warn == fwResource) ? "*" : " ", \ 1631d1603babSmrg NonNull(new_fnames.field))) 1632956cc18dSsnj DbgResource("normal", f_n, fNorm); 1633956cc18dSsnj DbgResource("bold ", f_b, fBold); 1634d522f475Smrg#if OPT_WIDE_CHARS 1635956cc18dSsnj DbgResource("wide ", f_w, fWide); 1636956cc18dSsnj DbgResource("w/bold", f_wb, fWBold); 1637d522f475Smrg#endif 1638d522f475Smrg 1639dfb07bc7Smrg if (!loadNormFP(xw, 1640d1603babSmrg &new_fnames.f_n, 1641d1603babSmrg &new_fonts[fNorm], 1642d1603babSmrg &old_fonts[fNorm], 1643dfb07bc7Smrg fontnum)) 1644d522f475Smrg goto bad; 1645d522f475Smrg 1646dfb07bc7Smrg if (!loadBoldFP(xw, 1647d1603babSmrg &new_fnames.f_b, 1648d1603babSmrg &new_fonts[fBold], 1649d1603babSmrg new_fnames.f_n, 1650d1603babSmrg &new_fonts[fNorm], 1651dfb07bc7Smrg fontnum)) 1652dfb07bc7Smrg goto bad; 1653d522f475Smrg 1654d522f475Smrg /* 1655d522f475Smrg * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1656d522f475Smrg * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1657d522f475Smrg * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1658d522f475Smrg */ 1659d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1660d522f475Smrg 1661dfb07bc7Smrg if (!loadWideFP(xw, 1662d1603babSmrg &new_fnames.f_w, 1663d1603babSmrg &new_fonts[fWide], 1664d1603babSmrg new_fnames.f_n, 1665d1603babSmrg &new_fonts[fNorm], 1666dfb07bc7Smrg fontnum)) 1667dfb07bc7Smrg goto bad; 1668dfb07bc7Smrg 1669dfb07bc7Smrg if (!loadWBoldFP(xw, 1670d1603babSmrg &new_fnames.f_wb, 1671d1603babSmrg &new_fonts[fWBold], 1672d1603babSmrg new_fnames.f_w, 1673d1603babSmrg &new_fonts[fWide], 1674d1603babSmrg new_fnames.f_b, 1675d1603babSmrg &new_fonts[fBold], 1676dfb07bc7Smrg fontnum)) 1677dfb07bc7Smrg goto bad; 1678d522f475Smrg 1679d522f475Smrg }); 1680d522f475Smrg 1681d522f475Smrg /* 1682d522f475Smrg * Normal/bold fonts should be the same width. Also, the min/max 1683d522f475Smrg * values should be the same. 1684d522f475Smrg */ 1685d1603babSmrg if (new_fonts[fNorm].fs != 0 1686d1603babSmrg && new_fonts[fBold].fs != 0 1687d1603babSmrg && (!is_fixed_font(new_fonts[fNorm].fs) 1688d1603babSmrg || !is_fixed_font(new_fonts[fBold].fs) 1689d1603babSmrg || differing_widths(new_fonts[fNorm].fs, new_fonts[fBold].fs))) { 1690d522f475Smrg TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1691d1603babSmrg new_fonts[fNorm].fs->min_bounds.width, 1692d1603babSmrg new_fonts[fNorm].fs->max_bounds.width, 1693d1603babSmrg new_fonts[fBold].fs->min_bounds.width, 1694d1603babSmrg new_fonts[fBold].fs->max_bounds.width)); 1695d522f475Smrg proportional = True; 1696d522f475Smrg } 1697d522f475Smrg 1698d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1699d1603babSmrg if (new_fonts[fWide].fs != 0 1700d1603babSmrg && new_fonts[fWBold].fs != 0 1701d1603babSmrg && (!is_fixed_font(new_fonts[fWide].fs) 1702d1603babSmrg || !is_fixed_font(new_fonts[fWBold].fs) 1703d1603babSmrg || differing_widths(new_fonts[fWide].fs, new_fonts[fWBold].fs))) { 1704d522f475Smrg TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1705d1603babSmrg new_fonts[fWide].fs->min_bounds.width, 1706d1603babSmrg new_fonts[fWide].fs->max_bounds.width, 1707d1603babSmrg new_fonts[fWBold].fs->min_bounds.width, 1708d1603babSmrg new_fonts[fWBold].fs->max_bounds.width)); 1709d522f475Smrg proportional = True; 1710d522f475Smrg } 1711d522f475Smrg }); 1712d522f475Smrg 1713d522f475Smrg /* TODO : enforce that the width of the wide font is 2* the width 1714d522f475Smrg of the narrow font */ 1715d522f475Smrg 1716d522f475Smrg /* 1717d522f475Smrg * If we're switching fonts, free the old ones. Otherwise we'll leak 1718d522f475Smrg * the memory that is associated with the old fonts. The 1719d522f475Smrg * XLoadQueryFont call allocates a new XFontStruct. 1720d522f475Smrg */ 1721d522f475Smrg xtermCloseFonts(xw, screen->fnts); 17229a64e1c5Smrg#if OPT_WIDE_ATTRS 17239a64e1c5Smrg xtermCloseFonts(xw, screen->ifnts); 17249a64e1c5Smrg screen->ifnts_ok = False; 17259a64e1c5Smrg#endif 1726d522f475Smrg 1727d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fNorm), &new_fonts[fNorm]); 1728d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fBold), &new_fonts[fBold]); 1729d522f475Smrg#if OPT_WIDE_CHARS 1730d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]); 1731d1603babSmrg if (new_fonts[fWBold].fs == NULL) 1732d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]); 1733d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fWBold), &new_fonts[fWBold]); 1734d522f475Smrg#endif 1735d522f475Smrg 1736d4fba8b9Smrg xtermUpdateFontGCs(xw, getNormalFont); 1737d522f475Smrg 173820d2c4d2Smrg#if OPT_BOX_CHARS 173920d2c4d2Smrg screen->allow_packing = proportional; 174020d2c4d2Smrg setupPackedFonts(xw); 174120d2c4d2Smrg#endif 174220d2c4d2Smrg screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1743d4fba8b9Smrg screen->fnt_boxes = 1; 1744d522f475Smrg 1745d522f475Smrg#if OPT_BOX_CHARS 1746d522f475Smrg /* 17479a64e1c5Smrg * xterm uses character positions 1-31 of a font for the line-drawing 1748d522f475Smrg * characters. Check that they are all present. The null character 1749d522f475Smrg * (0) is special, and is not used. 1750d522f475Smrg */ 1751d522f475Smrg#if OPT_RENDERFONT 1752d522f475Smrg if (UsingRenderFont(xw)) { 1753d522f475Smrg /* 1754d522f475Smrg * FIXME: we shouldn't even be here if we're using Xft. 1755d522f475Smrg */ 1756d4fba8b9Smrg screen->fnt_boxes = 0; 1757d522f475Smrg TRACE(("assume Xft missing line-drawing chars\n")); 1758d522f475Smrg } else 1759d522f475Smrg#endif 1760d522f475Smrg { 1761d522f475Smrg unsigned ch; 1762d522f475Smrg 17639a64e1c5Smrg#if OPT_TRACE 1764d1603babSmrg#define TRACE_MISS(index) show_font_misses(#index, &new_fonts[index]) 17659a64e1c5Smrg TRACE_MISS(fNorm); 17669a64e1c5Smrg TRACE_MISS(fBold); 17679a64e1c5Smrg#if OPT_WIDE_CHARS 17689a64e1c5Smrg TRACE_MISS(fWide); 17699a64e1c5Smrg TRACE_MISS(fWBold); 17709a64e1c5Smrg#endif 17719a64e1c5Smrg#endif 1772fa3f02f3Smrg 1773d522f475Smrg#if OPT_WIDE_CHARS 1774d4fba8b9Smrg if (screen->utf8_mode || screen->unicode_font) { 1775d4fba8b9Smrg UIntSet(screen->fnt_boxes, 2); 1776d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1777d4fba8b9Smrg unsigned n = dec2ucs(screen, ch); 1778d4fba8b9Smrg if ((n != UCS_REPL) 1779d4fba8b9Smrg && (n != ch) 1780d4fba8b9Smrg && (screen->fnt_boxes & 2)) { 1781d1603babSmrg if (xtermMissingChar(n, &new_fonts[fNorm]) || 1782d1603babSmrg xtermMissingChar(n, &new_fonts[fBold])) { 1783d4fba8b9Smrg UIntClr(screen->fnt_boxes, 2); 1784d4fba8b9Smrg TRACE(("missing graphics character #%d, U+%04X\n", 1785d4fba8b9Smrg ch, n)); 1786d4fba8b9Smrg break; 1787d4fba8b9Smrg } 1788d4fba8b9Smrg } 1789d522f475Smrg } 1790d4fba8b9Smrg } 1791d522f475Smrg#endif 1792d4fba8b9Smrg 1793d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1794d1603babSmrg if (xtermMissingChar(ch, &new_fonts[fNorm])) { 1795d4fba8b9Smrg TRACE(("missing normal char #%d\n", ch)); 1796d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1797d522f475Smrg break; 1798d522f475Smrg } 1799d1603babSmrg if (xtermMissingChar(ch, &new_fonts[fBold])) { 1800d4fba8b9Smrg TRACE(("missing bold char #%d\n", ch)); 1801d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1802d522f475Smrg break; 1803d522f475Smrg } 1804d522f475Smrg } 1805d4fba8b9Smrg 1806d4fba8b9Smrg TRACE(("Will %suse internal line-drawing characters (mode %d)\n", 1807d4fba8b9Smrg screen->fnt_boxes ? "not " : "", 1808d4fba8b9Smrg screen->fnt_boxes)); 1809d522f475Smrg } 1810d522f475Smrg#endif 1811d522f475Smrg 1812d522f475Smrg if (screen->always_bold_mode) { 1813d522f475Smrg screen->enbolden = screen->bold_mode; 1814d522f475Smrg } else { 1815d522f475Smrg screen->enbolden = screen->bold_mode 1816d1603babSmrg && ((new_fonts[fNorm].fs == new_fonts[fBold].fs) 1817d1603babSmrg || same_font_name(new_fnames.f_n, new_fnames.f_b)); 1818d522f475Smrg } 1819d522f475Smrg TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1820d522f475Smrg screen->enbolden ? "" : "not ")); 1821d522f475Smrg 1822d522f475Smrg set_menu_font(False); 1823d522f475Smrg screen->menu_font_number = fontnum; 1824d522f475Smrg set_menu_font(True); 1825d522f475Smrg if (tmpname) { /* if setting escape or sel */ 1826d522f475Smrg if (screen->MenuFontName(fontnum)) 18279a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontnum)); 1828d522f475Smrg screen->MenuFontName(fontnum) = tmpname; 1829d522f475Smrg if (fontnum == fontMenu_fontescape) { 183094644356Smrg update_font_escape(); 1831d522f475Smrg } 1832d522f475Smrg#if OPT_SHIFT_FONTS 1833d1603babSmrg screen->menu_font_sizes[fontnum] = FontSize(new_fonts[fNorm].fs); 1834d522f475Smrg#endif 1835d522f475Smrg } 1836d522f475Smrg set_cursor_gcs(xw); 1837d522f475Smrg xtermUpdateFontInfo(xw, doresize); 1838d522f475Smrg TRACE(("Success Cgs - xtermLoadFont\n")); 1839fa3f02f3Smrg#if OPT_REPORT_FONTS 1840fa3f02f3Smrg reportVTFontInfo(xw, fontnum); 18419a64e1c5Smrg#endif 18429a64e1c5Smrg FREE_FNAME(f_n); 18439a64e1c5Smrg FREE_FNAME(f_b); 18449a64e1c5Smrg#if OPT_WIDE_CHARS 18459a64e1c5Smrg FREE_FNAME(f_w); 18469a64e1c5Smrg FREE_FNAME(f_wb); 18479a64e1c5Smrg#endif 1848d1603babSmrg if (new_fonts[fNorm].fn == new_fonts[fBold].fn) { 1849d1603babSmrg free(new_fonts[fNorm].fn); 18509a64e1c5Smrg } else { 1851d1603babSmrg free(new_fonts[fNorm].fn); 1852d1603babSmrg free(new_fonts[fBold].fn); 18539a64e1c5Smrg } 18549a64e1c5Smrg#if OPT_WIDE_CHARS 1855d1603babSmrg free(new_fonts[fWide].fn); 1856d1603babSmrg free(new_fonts[fWBold].fn); 1857fa3f02f3Smrg#endif 1858dfb07bc7Smrg xtermSetWinSize(xw); 1859d522f475Smrg return 1; 1860d522f475Smrg 1861d522f475Smrg bad: 1862d1603babSmrg recovered = False; 1863d4fba8b9Smrg free(tmpname); 18640bd37d32Smrg 18650bd37d32Smrg#if OPT_RENDERFONT 186694644356Smrg if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) { 18679a64e1c5Smrg int old_fontnum = screen->menu_font_number; 18689a64e1c5Smrg#if OPT_TOOLBAR 18699a64e1c5Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, True); 18709a64e1c5Smrg#endif 18719a64e1c5Smrg Bell(xw, XkbBI_MinorError, 0); 1872d1603babSmrg new_fnames.f_n = screen->MenuFontName(old_fontnum); 1873d1603babSmrg if (xtermLoadFont(xw, &new_fnames, doresize, old_fontnum)) 1874d1603babSmrg recovered = True; 1875d1603babSmrg } else if (x_strcasecmp(new_fnames.f_n, DEFFONT) 1876d1603babSmrg && x_strcasecmp(new_fnames.f_n, old_fonts[fNorm].fn)) { 1877d1603babSmrg new_fnames.f_n = x_strdup(old_fonts[fNorm].fn); 1878d1603babSmrg TRACE(("...recovering from failed font-load\n")); 1879d1603babSmrg if (xtermLoadFont(xw, &new_fnames, doresize, fontnum)) { 1880d1603babSmrg recovered = True; 188194644356Smrg if (fontnum != fontMenu_fontsel) { 188294644356Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, 188394644356Smrg UsingRenderFont(xw)); 188494644356Smrg } 18850bd37d32Smrg TRACE(("...recovered size %dx%d\n", 18860bd37d32Smrg FontHeight(screen), 18870bd37d32Smrg FontWidth(screen))); 18880bd37d32Smrg } 18890bd37d32Smrg } 18900bd37d32Smrg#endif 1891d1603babSmrg if (!recovered) { 1892d1603babSmrg releaseWindowGCs(xw, win); 1893d1603babSmrg xtermCloseFonts(xw, new_fonts); 1894d1603babSmrg TRACE(("Fail Cgs - xtermLoadFont\n")); 1895d1603babSmrg code = 0; 1896d1603babSmrg } 1897d1603babSmrg return code; 1898d522f475Smrg} 1899d522f475Smrg 19009a64e1c5Smrg#if OPT_WIDE_ATTRS 19019a64e1c5Smrg/* 19029a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts. 19039a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font. 19049a64e1c5Smrg */ 19059a64e1c5Smrgvoid 19069a64e1c5SmrgxtermLoadItalics(XtermWidget xw) 19079a64e1c5Smrg{ 19089a64e1c5Smrg TScreen *screen = TScreenOf(xw); 19099a64e1c5Smrg 1910c48a5815Smrg if (UseItalicFont(screen) && !screen->ifnts_ok) { 1911037a25ddSmrg int n; 1912dfb07bc7Smrg FontNameProperties *fp; 1913dfb07bc7Smrg XTermFonts *data; 1914037a25ddSmrg 19159a64e1c5Smrg screen->ifnts_ok = True; 19169a64e1c5Smrg for (n = 0; n < fMAX; ++n) { 1917dfb07bc7Smrg switch (n) { 1918dfb07bc7Smrg case fNorm: 1919dfb07bc7Smrg /* FALLTHRU */ 1920dfb07bc7Smrg case fBold: 1921dfb07bc7Smrg /* FALLTHRU */ 1922dfb07bc7Smrg#if OPT_WIDE_CHARS 1923dfb07bc7Smrg case fWide: 1924dfb07bc7Smrg /* FALLTHRU */ 1925dfb07bc7Smrg case fWBold: 1926dfb07bc7Smrg#endif 1927dfb07bc7Smrg /* FALLTHRU */ 1928dfb07bc7Smrg data = getItalicFont(screen, n); 1929037a25ddSmrg 1930dfb07bc7Smrg /* 1931dfb07bc7Smrg * FIXME - need to handle font-leaks 1932dfb07bc7Smrg */ 1933dfb07bc7Smrg data->fs = 0; 1934dfb07bc7Smrg if (getNormalFont(screen, n)->fs != 0 && 1935dfb07bc7Smrg (fp = get_font_name_props(screen->display, 1936dfb07bc7Smrg getNormalFont(screen, n)->fs, 1937dfb07bc7Smrg 0)) != 0) { 1938dfb07bc7Smrg if (!open_italic_font(xw, n, fp, data)) { 1939dfb07bc7Smrg if (n > 0) { 1940dfb07bc7Smrg xtermCopyFontInfo(data, 1941dfb07bc7Smrg getItalicFont(screen, n - 1)); 1942dfb07bc7Smrg } else { 1943dfb07bc7Smrg xtermOpenFont(xw, 1944dfb07bc7Smrg getNormalFont(screen, n)->fn, 1945d1603babSmrg data, NULL, False); 19469a64e1c5Smrg } 19479a64e1c5Smrg } 19489a64e1c5Smrg } 1949dfb07bc7Smrg break; 19509a64e1c5Smrg } 19519a64e1c5Smrg } 19529a64e1c5Smrg } 19539a64e1c5Smrg} 19549a64e1c5Smrg#endif 19559a64e1c5Smrg 1956d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1957d522f475Smrg/* 1958d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action. 1959d522f475Smrg */ 1960dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \ 1961492d43a5Smrg if (IsEmpty(dst.name)) { \ 1962dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \ 19639a64e1c5Smrg dst.name = x_strdup(src.name); \ 1964d522f475Smrg } else { \ 1965dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1966dfb07bc7Smrg } 1967dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \ 1968d1603babSmrg if (dst.fonts.x11.name == NULL) \ 1969d1603babSmrg dst.fonts.x11.name = TypeCalloc(char *); \ 1970dfb07bc7Smrg if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \ 1971dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \ 1972dfb07bc7Smrg } else { \ 1973dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \ 1974d522f475Smrg } 1975d522f475Smrg 1976dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \ 1977e39b573cSmrg if (IsEmpty(dst.name)) { \ 1978e39b573cSmrg TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1979e39b573cSmrg dst.name = x_strdup(""); \ 1980e39b573cSmrg } else { \ 1981dfb07bc7Smrg TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1982e39b573cSmrg } 1983e39b573cSmrg 19849a64e1c5Smrg#define FREE_MENU_FONTS(dst) \ 19859a64e1c5Smrg TRACE(("FREE_MENU_FONTS " #dst "\n")); \ 19869a64e1c5Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 19879a64e1c5Smrg for (m = 0; m < fMAX; ++m) { \ 19889a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 19899a64e1c5Smrg dst.menu_font_names[n][m] = 0; \ 19909a64e1c5Smrg } \ 19919a64e1c5Smrg } 19929a64e1c5Smrg 1993dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \ 1994d522f475Smrg TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1995d522f475Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1996d522f475Smrg for (m = 0; m < fMAX; ++m) { \ 19979a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 1998492d43a5Smrg dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1999d522f475Smrg } \ 200094644356Smrg TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \ 2001e39b573cSmrg } 2002e39b573cSmrg 20039a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \ 2004dfb07bc7Smrg TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \ 20059a64e1c5Smrg xtermCopyVTFontNames(&target.default_font, &source.default_font) 20069a64e1c5Smrg 2007dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \ 2008dfb07bc7Smrg TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \ 2009dfb07bc7Smrg xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11) 2010dfb07bc7Smrg 2011dfb07bc7Smrgstatic void 2012dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source) 2013dfb07bc7Smrg{ 2014dfb07bc7Smrg#define COPY_IT(name,field) \ 2015dfb07bc7Smrg TRACE((".. "#name" = %s\n", NonNull(source->field))); \ 2016dfb07bc7Smrg free(target->field); \ 2017dfb07bc7Smrg target->field = x_strdup(source->field) 2018dfb07bc7Smrg 2019dfb07bc7Smrg TRACE(("xtermCopyVTFontNames\n")); 2020dfb07bc7Smrg 2021dfb07bc7Smrg COPY_IT(font, f_n); 2022dfb07bc7Smrg COPY_IT(boldFont, f_b); 2023dfb07bc7Smrg 2024dfb07bc7Smrg#if OPT_WIDE_CHARS 2025dfb07bc7Smrg COPY_IT(wideFont, f_w); 2026dfb07bc7Smrg COPY_IT(wideBoldFont, f_wb); 2027dfb07bc7Smrg#endif 2028dfb07bc7Smrg#undef COPY_IT 2029dfb07bc7Smrg} 2030dfb07bc7Smrg 20319a64e1c5Smrgstatic void 2032dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source) 20339a64e1c5Smrg{ 2034dfb07bc7Smrg#define COPY_IT(name,field) \ 2035dfb07bc7Smrg copyFontList(&(target->field), source->field); \ 2036dfb07bc7Smrg TRACE_ARGV(".. " #name, source->field) 2037dfb07bc7Smrg 2038dfb07bc7Smrg (void) xw; 2039dfb07bc7Smrg TRACE(("xtermCopyFontLists %s ->%s\n", 2040dfb07bc7Smrg whichFontList(xw, source), 2041dfb07bc7Smrg whichFontList(xw, target))); 2042dfb07bc7Smrg 2043dfb07bc7Smrg COPY_IT(font, list_n); 2044dfb07bc7Smrg COPY_IT(fontBold, list_b); 2045dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 2046dfb07bc7Smrg COPY_IT(fontItal, list_i); 2047d4fba8b9Smrg COPY_IT(fontBtal, list_bi); 2048dfb07bc7Smrg#endif 20499a64e1c5Smrg#if OPT_WIDE_CHARS 2050dfb07bc7Smrg COPY_IT(wideFont, list_w); 2051dfb07bc7Smrg COPY_IT(wideBoldFont, list_wb); 2052dfb07bc7Smrg COPY_IT(wideItalFont, list_wi); 2053d4fba8b9Smrg COPY_IT(wideBtalFont, list_wbi); 20549a64e1c5Smrg#endif 2055dfb07bc7Smrg#undef COPY_IT 20569a64e1c5Smrg} 20579a64e1c5Smrg 2058e39b573cSmrgvoid 2059e39b573cSmrgxtermSaveVTFonts(XtermWidget xw) 2060e39b573cSmrg{ 2061e39b573cSmrg TScreen *screen = TScreenOf(xw); 2062e39b573cSmrg Cardinal n, m; 2063e39b573cSmrg 2064e39b573cSmrg if (!screen->savedVTFonts) { 2065e39b573cSmrg 2066e39b573cSmrg screen->savedVTFonts = True; 2067e39b573cSmrg TRACE(("xtermSaveVTFonts saving original\n")); 20689a64e1c5Smrg COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc); 2069dfb07bc7Smrg COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work); 2070dfb07bc7Smrg COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 2071e39b573cSmrg } 2072e39b573cSmrg} 2073e39b573cSmrg 2074e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 2075e39b573cSmrg#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 2076e39b573cSmrg 2077e39b573cSmrgstatic Boolean 2078e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b) 2079e39b573cSmrg{ 2080e39b573cSmrg Boolean result = True; 2081e39b573cSmrg 2082e39b573cSmrg if (!SAME_MEMBER(default_font.f_n) 2083e39b573cSmrg || !SAME_MEMBER(default_font.f_b) 20840bd37d32Smrg#if OPT_WIDE_CHARS 2085e39b573cSmrg || !SAME_MEMBER(default_font.f_w) 20860bd37d32Smrg || !SAME_MEMBER(default_font.f_wb) 20870bd37d32Smrg#endif 20880bd37d32Smrg ) { 2089e39b573cSmrg TRACE(("sameSubResources: default_font differs\n")); 2090e39b573cSmrg result = False; 2091e39b573cSmrg } else { 2092037a25ddSmrg int n; 2093037a25ddSmrg 2094e39b573cSmrg for (n = 0; n < NMENUFONTS; ++n) { 2095e39b573cSmrg if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 2096e39b573cSmrg TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 2097e39b573cSmrg result = False; 2098e39b573cSmrg break; 2099e39b573cSmrg } 2100d522f475Smrg } 2101e39b573cSmrg } 2102e39b573cSmrg 2103e39b573cSmrg return result; 2104e39b573cSmrg} 2105d522f475Smrg 2106d522f475Smrg/* 2107d522f475Smrg * Load the "VT" font names from the given subresource name/class. These 2108d522f475Smrg * correspond to the VT100 resources. 2109d522f475Smrg */ 2110d522f475Smrgstatic Bool 211120d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 2112d522f475Smrg{ 2113e39b573cSmrg SubResourceRec subresourceRec; 2114e39b573cSmrg SubResourceRec referenceRec; 2115d522f475Smrg 2116d522f475Smrg /* 2117d522f475Smrg * These are duplicates of the VT100 font resources, but with a special 2118d522f475Smrg * application/classname passed in to distinguish them. 2119d522f475Smrg */ 2120d522f475Smrg static XtResource font_resources[] = 2121d522f475Smrg { 2122d522f475Smrg Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 2123d522f475Smrg Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 2124d522f475Smrg#if OPT_WIDE_CHARS 2125d522f475Smrg Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 2126d522f475Smrg Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 2127d522f475Smrg#endif 2128d522f475Smrg Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 2129d522f475Smrg Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 2130d522f475Smrg Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 2131d522f475Smrg Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 2132d522f475Smrg Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 2133d522f475Smrg Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 2134d4fba8b9Smrg Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL), 2135d522f475Smrg }; 2136d522f475Smrg Cardinal n, m; 2137d522f475Smrg Bool status = True; 2138956cc18dSsnj TScreen *screen = TScreenOf(xw); 2139d522f475Smrg 2140e39b573cSmrg TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 2141e39b573cSmrg NonNull(myName), NonNull(myClass))); 2142d522f475Smrg 2143e39b573cSmrg xtermSaveVTFonts(xw); 2144d522f475Smrg 2145492d43a5Smrg if (IsEmpty(myName)) { 2146d522f475Smrg TRACE(("xtermLoadVTFonts restoring original\n")); 21479a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts); 2148dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts); 21499a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2150dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 2151d522f475Smrg } else { 2152d522f475Smrg TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 2153d522f475Smrg 2154e39b573cSmrg memset(&referenceRec, 0, sizeof(referenceRec)); 2155d522f475Smrg memset(&subresourceRec, 0, sizeof(subresourceRec)); 2156956cc18dSsnj XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 2157d522f475Smrg myName, myClass, 2158d522f475Smrg font_resources, 2159d522f475Smrg (Cardinal) XtNumber(font_resources), 2160d522f475Smrg NULL, (Cardinal) 0); 2161d522f475Smrg 2162e39b573cSmrg /* 2163e39b573cSmrg * XtGetSubresources returns no status, so we compare the returned 2164e39b573cSmrg * data against a zero'd struct to see if any data is returned. 2165e39b573cSmrg */ 2166e39b573cSmrg if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 2167e39b573cSmrg && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 2168e39b573cSmrg 2169e39b573cSmrg screen->mergedVTFonts = True; 2170d522f475Smrg 21719a64e1c5Smrg /* 21729a64e1c5Smrg * To make it simple, reallocate the strings returned by 21739a64e1c5Smrg * XtGetSubresources. We can free our own strings, but not theirs. 21749a64e1c5Smrg */ 21759a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_n); 21769a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_b); 21779a64e1c5Smrg#if OPT_WIDE_CHARS 21789a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_w); 21799a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_wb); 21809a64e1c5Smrg#endif 21819a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 21829a64e1c5Smrg ALLOC_STRING(subresourceRec.MenuFontName(n)); 21839a64e1c5Smrg } 21849a64e1c5Smrg 2185dfb07bc7Smrg /* 2186dfb07bc7Smrg * Now, save the string to a font-list for consistency 2187dfb07bc7Smrg */ 2188dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \ 2189d1603babSmrg if (subresourceRec.default_font.field != NULL) { \ 2190d1603babSmrg char *blob = x_strdup(subresourceRec.default_font.field); \ 2191d1603babSmrg char *base; \ 2192d1603babSmrg for (base = blob; ; base = NULL) { \ 2193d1603babSmrg char *item = strtok(base, ","); \ 2194d1603babSmrg if (item == NULL) \ 2195d1603babSmrg break; \ 2196d1603babSmrg save2FontList(xw, "cached", \ 2197d1603babSmrg &(subresourceRec.fonts), \ 2198d1603babSmrg which, \ 2199d1603babSmrg item, False, False); \ 2200d1603babSmrg } \ 2201d1603babSmrg free(blob); \ 2202d1603babSmrg } 2203dfb07bc7Smrg 2204dfb07bc7Smrg ALLOC_SUBLIST(fNorm, f_n); 2205dfb07bc7Smrg ALLOC_SUBLIST(fBold, f_b); 2206dfb07bc7Smrg#if OPT_WIDE_CHARS 2207dfb07bc7Smrg ALLOC_SUBLIST(fWide, f_w); 2208dfb07bc7Smrg ALLOC_SUBLIST(fWBold, f_wb); 2209dfb07bc7Smrg#endif 2210dfb07bc7Smrg 2211d522f475Smrg /* 2212d522f475Smrg * If a particular resource value was not found, use the original. 2213d522f475Smrg */ 2214dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n); 2215dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b); 2216dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_n); 2217dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_b); 2218d522f475Smrg#if OPT_WIDE_CHARS 2219dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w); 2220dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb); 2221dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_w); 2222dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_wb); 2223d522f475Smrg#endif 22249a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2225dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n)); 22269a64e1c5Smrg } 2227d522f475Smrg 2228d522f475Smrg /* 2229d522f475Smrg * Finally, copy the subresource data to the widget. 2230d522f475Smrg */ 22319a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, subresourceRec); 2232dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, subresourceRec); 22339a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2234dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, subresourceRec); 22359a64e1c5Smrg 22369a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontMenu_default)); 22379a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fBold]); 2238dfb07bc7Smrg screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw)); 2239dfb07bc7Smrg screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw)); 2240d522f475Smrg#if OPT_WIDE_CHARS 22419a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWide]); 22429a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWBold]); 2243dfb07bc7Smrg screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw)); 2244dfb07bc7Smrg screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw)); 2245d522f475Smrg#endif 22469a64e1c5Smrg /* 22479a64e1c5Smrg * And remove our copies of strings. 22489a64e1c5Smrg */ 22499a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_n); 22509a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_b); 22519a64e1c5Smrg#if OPT_WIDE_CHARS 22529a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_w); 22539a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_wb); 22549a64e1c5Smrg#endif 22559a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 22569a64e1c5Smrg FREE_STRING(subresourceRec.MenuFontName(n)); 22579a64e1c5Smrg } 2258d522f475Smrg } else { 2259d522f475Smrg TRACE(("...no resources found\n")); 2260d522f475Smrg status = False; 2261d522f475Smrg } 2262d522f475Smrg } 2263dfb07bc7Smrg TRACE((".. xtermLoadVTFonts: %d\n", status)); 2264d522f475Smrg return status; 2265d522f475Smrg} 2266d522f475Smrg 2267d522f475Smrg#if OPT_WIDE_CHARS 2268d522f475Smrgstatic Bool 22699a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk) 2270d522f475Smrg{ 2271d522f475Smrg Bool result = False; 2272d522f475Smrg 2273d522f475Smrg (void) tag; 2274d522f475Smrg if (okFont(fp)) { 2275d522f475Smrg unsigned count = countGlyphs(fp); 2276d522f475Smrg TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 2277d522f475Smrg result = (count > 256) ? True : False; 2278d522f475Smrg } else { 2279d522f475Smrg result = nullOk; 2280d522f475Smrg } 2281d522f475Smrg return result; 2282d522f475Smrg} 2283d522f475Smrg 2284d522f475Smrg/* 2285d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts. 2286d522f475Smrg * 2287d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not 2288d522f475Smrg * been setup, so we pass nullOk=True to isWideFont(). 2289d522f475Smrg * 2290d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry 2291d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide. 2292d522f475Smrg */ 2293d522f475SmrgBool 2294d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk) 2295d522f475Smrg{ 2296956cc18dSsnj TScreen *screen = TScreenOf(xw); 2297d522f475Smrg Bool result; 2298d522f475Smrg 2299d4fba8b9Smrg if (EmptyFont(GetNormalFont(screen, fWide)->fs)) { 2300d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2301d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk)); 2302d522f475Smrg } else { 2303d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk) 2304d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fWBold)->fs, 2305dfb07bc7Smrg "wide-bold", nullOk)); 2306d522f475Smrg if (result && !screen->utf8_latin1) { 2307d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2308d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, 2309dfb07bc7Smrg "bold", nullOk)); 2310d522f475Smrg } 2311d522f475Smrg } 2312d522f475Smrg if (!result) { 2313d522f475Smrg TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 2314e39b573cSmrg result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 2315d522f475Smrg } 2316d522f475Smrg TRACE(("xtermLoadWideFonts:%d\n", result)); 2317d522f475Smrg return result; 2318d522f475Smrg} 2319d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2320d522f475Smrg 2321d522f475Smrg/* 2322d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts. 2323d522f475Smrg */ 2324d522f475SmrgBool 2325956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw) 2326d522f475Smrg{ 2327d522f475Smrg Bool result; 2328956cc18dSsnj result = xtermLoadVTFonts(xw, NULL, NULL); 2329d522f475Smrg TRACE(("xtermLoadDefaultFonts:%d\n", result)); 2330d522f475Smrg return result; 2331d522f475Smrg} 2332d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 2333d522f475Smrg 2334d522f475Smrg#if OPT_LOAD_VTFONTS 2335d522f475Smrgvoid 2336d522f475SmrgHandleLoadVTFonts(Widget w, 23379a64e1c5Smrg XEvent *event GCC_UNUSED, 2338d4fba8b9Smrg String *params, 2339d4fba8b9Smrg Cardinal *param_count) 2340d522f475Smrg{ 2341956cc18dSsnj XtermWidget xw; 2342956cc18dSsnj 2343956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2344037a25ddSmrg static char empty[] = ""; /* appease strict compilers */ 2345037a25ddSmrg 2346956cc18dSsnj TScreen *screen = TScreenOf(xw); 2347492d43a5Smrg char name_buf[80]; 2348492d43a5Smrg String name = (String) ((*param_count > 0) ? params[0] : empty); 234994644356Smrg char *myName = MyStackAlloc(strlen(name) + 1, name_buf); 2350d522f475Smrg 2351d522f475Smrg TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 235294644356Smrg if (myName != 0) { 2353037a25ddSmrg char class_buf[80]; 235494644356Smrg String convert = (String) ((*param_count > 1) ? params[1] : myName); 235594644356Smrg char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf); 235694644356Smrg 235794644356Smrg strcpy(myName, name); 235894644356Smrg if (myClass != 0) { 235994644356Smrg strcpy(myClass, convert); 236094644356Smrg if (*param_count == 1) 236194644356Smrg myClass[0] = x_toupper(myClass[0]); 236294644356Smrg 236394644356Smrg if (xtermLoadVTFonts(xw, myName, myClass)) { 2364037a25ddSmrg int n; 236594644356Smrg /* 236694644356Smrg * When switching fonts, try to preserve the font-menu 236794644356Smrg * selection, since it is less surprising to do that (if 236894644356Smrg * the font-switching can be undone) than to switch to 236994644356Smrg * "Default". 237094644356Smrg */ 237194644356Smrg int font_number = screen->menu_font_number; 237294644356Smrg if (font_number > fontMenu_lastBuiltin) 237394644356Smrg font_number = fontMenu_lastBuiltin; 237494644356Smrg for (n = 0; n < NMENUFONTS; ++n) { 237594644356Smrg screen->menu_font_sizes[n] = 0; 237694644356Smrg } 2377dfb07bc7Smrg if (font_number == fontMenu_default) { 2378dfb07bc7Smrg SetVTFont(xw, font_number, True, defaultVTFontNames(xw)); 2379dfb07bc7Smrg } else { 2380dfb07bc7Smrg SetVTFont(xw, font_number, True, NULL); 2381dfb07bc7Smrg } 238294644356Smrg } 238394644356Smrg MyStackFree(myClass, class_buf); 23849a64e1c5Smrg } 238594644356Smrg MyStackFree(myName, name_buf); 2386d522f475Smrg } 2387d522f475Smrg } 2388d522f475Smrg} 2389d522f475Smrg#endif /* OPT_LOAD_VTFONTS */ 2390d522f475Smrg 2391d522f475Smrg/* 2392d522f475Smrg * Set the limits for the box that outlines the cursor. 2393d522f475Smrg */ 2394d522f475Smrgvoid 2395fa3f02f3SmrgxtermSetCursorBox(TScreen *screen) 2396d522f475Smrg{ 2397d522f475Smrg static XPoint VTbox[NBOX]; 2398d522f475Smrg XPoint *vp; 23992eaa94a1Schristos int fw = FontWidth(screen) - 1; 24002eaa94a1Schristos int fh = FontHeight(screen) - 1; 2401d1603babSmrg int ww = isCursorBar(screen) ? fw / 8 : fw; 2402d1603babSmrg int hh = isCursorUnderline(screen) ? fh / 8 : fh; 2403d1603babSmrg if (ww < 2) 2404d1603babSmrg ww = 2; 2405d1603babSmrg if (hh < 2) 2406d1603babSmrg hh = 2; 2407d522f475Smrg 2408d522f475Smrg vp = &VTbox[1]; 24090bd37d32Smrg (vp++)->x = (short) ww; 24102eaa94a1Schristos (vp++)->y = (short) hh; 24110bd37d32Smrg (vp++)->x = (short) -ww; 24122eaa94a1Schristos vp->y = (short) -hh; 24132eaa94a1Schristos 2414d522f475Smrg screen->box = VTbox; 2415d522f475Smrg} 2416d522f475Smrg 2417d4fba8b9Smrg#if OPT_RENDERFONT 2418d4fba8b9Smrg 2419d1603babSmrg#define CACHE_XFT(data) if (XftFp(data) != NULL) {\ 2420d1603babSmrg int err = checkXftWidth(xw, data);\ 2421d4fba8b9Smrg TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\ 2422d1603babSmrg #data,\ 2423d4fba8b9Smrg fontnum,\ 2424d1603babSmrg XftFp(data)->height,\ 2425d1603babSmrg XftFp(data)->ascent,\ 2426d1603babSmrg XftFp(data)->descent,\ 2427d1603babSmrg ((XftFp(data)->ascent + XftFp(data)->descent) > XftFp(data)->height ? "*" : ""),\ 2428d1603babSmrg XftFp(data)->max_advance_width,\ 2429d1603babSmrg data->font_info.min_width,\ 2430d1603babSmrg data->font_info.mixed ? " mixed" : "",\ 2431d4fba8b9Smrg err ? " ERROR" : ""));\ 2432d4fba8b9Smrg if (err) {\ 2433d1603babSmrg xtermCloseXft(screen, data);\ 2434d1603babSmrg memset((data), 0, sizeof(*data));\ 2435d4fba8b9Smrg failed += err;\ 2436d4fba8b9Smrg }\ 2437d522f475Smrg } 2438d522f475Smrg 2439dfb07bc7Smrg#if OPT_REPORT_FONTS 244020d2c4d2Smrgstatic FcChar32 24419a64e1c5SmrgxtermXftFirstChar(XftFont *xft) 244220d2c4d2Smrg{ 244320d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 244420d2c4d2Smrg FcChar32 next; 244520d2c4d2Smrg FcChar32 first; 244620d2c4d2Smrg int i; 244720d2c4d2Smrg 244820d2c4d2Smrg first = FcCharSetFirstPage(xft->charset, map, &next); 24499a64e1c5Smrg for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { 245020d2c4d2Smrg if (map[i]) { 245120d2c4d2Smrg FcChar32 bits = map[i]; 2452fa3f02f3Smrg first += (FcChar32) i *32; 245320d2c4d2Smrg while (!(bits & 0x1)) { 245420d2c4d2Smrg bits >>= 1; 245520d2c4d2Smrg first++; 245620d2c4d2Smrg } 245720d2c4d2Smrg break; 245820d2c4d2Smrg } 24599a64e1c5Smrg } 246020d2c4d2Smrg return first; 246120d2c4d2Smrg} 246220d2c4d2Smrg 246320d2c4d2Smrgstatic FcChar32 24649a64e1c5SmrgxtermXftLastChar(XftFont *xft) 246520d2c4d2Smrg{ 2466d1603babSmrg FcChar32 temp, last, next; 246720d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 246820d2c4d2Smrg int i; 246920d2c4d2Smrg last = FcCharSetFirstPage(xft->charset, map, &next); 2470d1603babSmrg while ((temp = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 2471d1603babSmrg last = temp; 2472fa3f02f3Smrg last &= (FcChar32) ~ 0xff; 24739a64e1c5Smrg for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) { 247420d2c4d2Smrg if (map[i]) { 247520d2c4d2Smrg FcChar32 bits = map[i]; 2476fa3f02f3Smrg last += (FcChar32) i *32 + 31; 247720d2c4d2Smrg while (!(bits & 0x80000000)) { 247820d2c4d2Smrg last--; 247920d2c4d2Smrg bits <<= 1; 248020d2c4d2Smrg } 248120d2c4d2Smrg break; 248220d2c4d2Smrg } 24839a64e1c5Smrg } 2484dfb07bc7Smrg return (FcChar32) last; 248520d2c4d2Smrg} 2486dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 248720d2c4d2Smrg 2488d4fba8b9Smrg#if OPT_TRACE 2489d4fba8b9Smrg 2490d4fba8b9Smrg#if !OPT_WIDE_CHARS 2491d4fba8b9Smrgstatic Char * 2492d4fba8b9SmrgconvertToUTF8(Char *buffer, int c) 2493d4fba8b9Smrg{ 2494d4fba8b9Smrg buffer[0] = (Char) c; 2495d4fba8b9Smrg buffer[1] = 0; 2496d4fba8b9Smrg return buffer; 2497d4fba8b9Smrg} 2498d4fba8b9Smrg#endif 2499d4fba8b9Smrg 250020d2c4d2Smrgstatic void 25019a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data) 250220d2c4d2Smrg{ 2503d1603babSmrg XftFont *xft = XftFp(data); 250420d2c4d2Smrg TScreen *screen = TScreenOf(xw); 250520d2c4d2Smrg VTwin *win = WhichVWin(screen); 250620d2c4d2Smrg 250720d2c4d2Smrg FcChar32 c; 250820d2c4d2Smrg FcChar32 first = xtermXftFirstChar(xft); 250920d2c4d2Smrg FcChar32 last = xtermXftLastChar(xft); 2510d4fba8b9Smrg FcChar32 dump; 251120d2c4d2Smrg unsigned count = 0; 2512d4fba8b9Smrg unsigned too_high = 0; 2513d4fba8b9Smrg unsigned too_wide = 0; 2514d4fba8b9Smrg Boolean skip = False; 2515d4fba8b9Smrg 2516d4fba8b9Smrg TRACE(("dumpXft " TRACE_L "\n")); 2517d4fba8b9Smrg TRACE(("\tdata range U+%04X..U+%04X\n", first, last)); 2518d4fba8b9Smrg TRACE(("\tcode\tcells\tdimensions\n")); 2519d4fba8b9Smrg#if OPT_TRACE < 2 2520d4fba8b9Smrg dump = 255; 2521d4fba8b9Smrg#else 2522d4fba8b9Smrg dump = last; 2523d4fba8b9Smrg#endif 252420d2c4d2Smrg for (c = first; c <= last; ++c) { 252520d2c4d2Smrg if (FcCharSetHasChar(xft->charset, c)) { 2526c48a5815Smrg int width = CharWidth(screen, c); 252720d2c4d2Smrg XGlyphInfo extents; 2528d4fba8b9Smrg Boolean big_x; 2529d4fba8b9Smrg Boolean big_y; 253020d2c4d2Smrg 253120d2c4d2Smrg XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2532d4fba8b9Smrg big_x = (extents.width > win->f_width); 2533d4fba8b9Smrg big_y = (extents.height > win->f_height); 2534d4fba8b9Smrg 2535d4fba8b9Smrg if (c <= dump) { 2536d4fba8b9Smrg Char buffer[80]; 2537d4fba8b9Smrg 2538d4fba8b9Smrg *convertToUTF8(buffer, c) = '\0'; 2539d4fba8b9Smrg TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n", 2540d4fba8b9Smrg (big_y ? "y" : ""), 2541d4fba8b9Smrg (big_x ? "x" : ""), 2542d4fba8b9Smrg c, width, 2543d4fba8b9Smrg ((double) extents.height) / win->f_height, 2544d4fba8b9Smrg ((double) extents.width) / win->f_width, 2545d4fba8b9Smrg buffer)); 2546d4fba8b9Smrg } else if (!skip) { 2547d4fba8b9Smrg skip = True; 2548d4fba8b9Smrg TRACE(("\t...skipping\n")); 2549d4fba8b9Smrg } 2550d4fba8b9Smrg if (big_y) 2551d4fba8b9Smrg ++too_high; 2552d4fba8b9Smrg if (big_x) 2553d4fba8b9Smrg ++too_wide; 255420d2c4d2Smrg ++count; 255520d2c4d2Smrg } 255620d2c4d2Smrg } 2557d4fba8b9Smrg TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide)); 255820d2c4d2Smrg} 255920d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data) 256020d2c4d2Smrg#else 256120d2c4d2Smrg#define DUMP_XFT(xw, data) /* nothing */ 256220d2c4d2Smrg#endif 256320d2c4d2Smrg 2564d4fba8b9Smrg/* 2565d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a 2566d4fba8b9Smrg * problem with web browsers. As of 2018/12 (4 years later), Xft does not work 2567d4fba8b9Smrg * with that. Even with this workaround, fontconfig has at least one bug which 2568d4fba8b9Smrg * causes it to crash (Debian #917034). 2569d4fba8b9Smrg */ 2570d4fba8b9Smrg#ifdef FC_COLOR 2571d4fba8b9Smrg#define GetFcBool(pattern, what) \ 2572d1603babSmrg FcOK(FcPatternGetBool(pattern, what, 0, &fcbogus)) 2573d4fba8b9Smrg 2574d4fba8b9Smrgstatic Boolean 2575d4fba8b9SmrgisBogusXft(XftFont *font) 2576d4fba8b9Smrg{ 2577d4fba8b9Smrg Boolean result = False; 2578d4fba8b9Smrg if (font != 0) { 2579d4fba8b9Smrg FcBool fcbogus; 2580d4fba8b9Smrg if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) { 2581d4fba8b9Smrg TRACE(("...matched color-bitmap font\n")); 2582d1603babSmrg#if !USE_FC_COLOR 2583d4fba8b9Smrg result = True; 2584d1603babSmrg#endif 2585d4fba8b9Smrg } else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) { 2586d4fba8b9Smrg TRACE(("...matched non-outline font\n")); 2587d4fba8b9Smrg /* This is legal for regular bitmap fonts - fontconfig attempts to 2588d4fba8b9Smrg * find a match - but problematic for misencoded color-bitmap fonts. 2589d4fba8b9Smrg */ 2590d4fba8b9Smrg } 2591d4fba8b9Smrg } 2592d4fba8b9Smrg return result; 2593d4fba8b9Smrg} 2594d4fba8b9Smrg#endif 2595d4fba8b9Smrg 2596d4fba8b9Smrg#if OPT_BOX_CHARS 2597956cc18dSsnjstatic void 2598d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state) 2599d4fba8b9Smrg{ 2600d4fba8b9Smrg TRACE(("setBrokenBoxChars %s\n", BtoS(state))); 2601d4fba8b9Smrg term->work.broken_box_chars = (Boolean) state; 2602d4fba8b9Smrg TScreenOf(xw)->broken_box_chars = (Boolean) state; 2603d4fba8b9Smrg update_font_boxchars(); 2604d4fba8b9Smrg} 2605d4fba8b9Smrg 2606d4fba8b9Smrg#else 2607d4fba8b9Smrg#define setBrokenBoxChars(xw, state) /* nothing */ 2608d4fba8b9Smrg#endif 2609d4fba8b9Smrg 2610d4fba8b9Smrgstatic Boolean 2611d4fba8b9SmrgcheckedXftWidth(Display *dpy, 2612d4fba8b9Smrg XTermXftFonts *source, 2613d4fba8b9Smrg unsigned limit, 2614d4fba8b9Smrg Dimension *width, 2615d4fba8b9Smrg FcChar32 c) 2616d4fba8b9Smrg{ 2617d4fba8b9Smrg Boolean result = False; 2618d4fba8b9Smrg 2619d1603babSmrg if (FcCharSetHasChar(XftFp(source)->charset, c)) { 2620d4fba8b9Smrg XGlyphInfo extents; 2621d4fba8b9Smrg 2622d4fba8b9Smrg result = True; 2623d1603babSmrg XftTextExtents32(dpy, XftFp(source), &c, 1, &extents); 2624d4fba8b9Smrg if (*width < extents.width && extents.width <= limit) { 2625d4fba8b9Smrg *width = extents.width; 2626d4fba8b9Smrg } 2627d4fba8b9Smrg } 2628d4fba8b9Smrg return result; 2629d4fba8b9Smrg} 2630d4fba8b9Smrg 2631d1603babSmrg/* 2632d1603babSmrg * Check if the given character has a glyph known to Xft. This is likely to be 2633d1603babSmrg * slower than checking our cache. 2634d1603babSmrg * 2635d1603babSmrg * see xc/lib/Xft/xftglyphs.c 2636d1603babSmrg */ 2637d1603babSmrgstatic Bool 2638d1603babSmrgslowXftMissing(XtermWidget xw, XftFont *font, unsigned wc) 2639d1603babSmrg{ 2640d1603babSmrg TScreen *screen = TScreenOf(xw); 2641d1603babSmrg Bool result = False; 2642d1603babSmrg 2643d1603babSmrg if (font != NULL) { 2644d1603babSmrg if (XftCharIndex(screen->display, font, wc) == 0) 2645d1603babSmrg result = True; 2646d1603babSmrg } 2647d1603babSmrg return result; 2648d1603babSmrg} 2649d1603babSmrg 2650d4fba8b9Smrgstatic int 2651d1603babSmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *data) 2652956cc18dSsnj{ 2653956cc18dSsnj FcChar32 c; 2654d1603babSmrg FcChar32 last = xtermXftLastChar(XftFp(data)); 2655d1603babSmrg Dimension limit = (Dimension) XftFp(data)->max_advance_width; 2656956cc18dSsnj Dimension width = 0; 2657d4fba8b9Smrg Dimension width2 = 0; 2658d4fba8b9Smrg int failed = 0; 2659d4fba8b9Smrg#if OPT_WIDE_CHARS 2660d4fba8b9Smrg Cardinal n; 2661d4fba8b9Smrg#endif 2662956cc18dSsnj 2663d1603babSmrg data->font_info.min_width = 0; 2664d1603babSmrg data->font_info.max_width = limit; 2665d4fba8b9Smrg 2666d4fba8b9Smrg#if OPT_WIDE_CHARS 2667d4fba8b9Smrg /* 2668d4fba8b9Smrg * Check if the line-drawing characters are all provided in the font. 2669d4fba8b9Smrg * If so, take that into account for the cell-widths. 2670d4fba8b9Smrg */ 2671d4fba8b9Smrg for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) { 2672d4fba8b9Smrg if (!checkedXftWidth(XtDisplay(xw), 2673d1603babSmrg data, 2674d4fba8b9Smrg limit, 2675d4fba8b9Smrg &width2, unicode_boxes[n].code)) { 2676d4fba8b9Smrg width2 = 0; 2677d4fba8b9Smrg TRACE(("font omits U+%04X line-drawing symbol\n", 2678d4fba8b9Smrg unicode_boxes[n].code)); 2679d4fba8b9Smrg break; 2680d4fba8b9Smrg } 2681d4fba8b9Smrg } 2682d4fba8b9Smrg#else 2683d4fba8b9Smrg (void) width2; 2684d4fba8b9Smrg#endif 2685d4fba8b9Smrg 2686d4fba8b9Smrg if (width2 > 0) { 2687d4fba8b9Smrg Dimension check = (Dimension) (limit + 1) / 2; 2688d4fba8b9Smrg TRACE(("font provides VT100-style line-drawing\n")); 2689d4fba8b9Smrg /* 2690d4fba8b9Smrg * The "VT100 line-drawing" characters happen to be all "ambiguous 2691d4fba8b9Smrg * width" in Unicode's scheme. That means that they could be twice as 2692d4fba8b9Smrg * wide as the Latin-1 characters. 2693d4fba8b9Smrg */ 2694d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n)) 2695d4fba8b9Smrg if (width2 > FC_ERR(check)) { 2696d4fba8b9Smrg TRACE(("line-drawing characters appear to be double-width (ignore)\n")); 2697d4fba8b9Smrg setBrokenBoxChars(xw, True); 2698d4fba8b9Smrg } else if (width2 > width) { 2699d4fba8b9Smrg width = width2; 2700d4fba8b9Smrg } 2701d4fba8b9Smrg } else { 2702d4fba8b9Smrg TRACE(("font does NOT provide VT100-style line-drawing\n")); 2703d4fba8b9Smrg setBrokenBoxChars(xw, True); 2704d4fba8b9Smrg } 2705956cc18dSsnj 270620d2c4d2Smrg /* 2707d4fba8b9Smrg * For each printable code, ask what its width is. Given the maximum width 2708d4fba8b9Smrg * for those, we have a reasonable estimate of the single-column width. 270920d2c4d2Smrg * 271020d2c4d2Smrg * Ignore control characters - their extent information is misleading. 271120d2c4d2Smrg */ 2712956cc18dSsnj for (c = 32; c < 256; ++c) { 2713c48a5815Smrg if (CharWidth(TScreenOf(xw), c) <= 0) 271420d2c4d2Smrg continue; 2715d1603babSmrg if (FcCharSetHasChar(XftFp(data)->charset, c)) { 2716d4fba8b9Smrg (void) checkedXftWidth(XtDisplay(xw), 2717d1603babSmrg data, 2718d1603babSmrg data->font_info.max_width, 2719d4fba8b9Smrg &width, c); 2720d4fba8b9Smrg } 2721d4fba8b9Smrg } 2722956cc18dSsnj 2723d4fba8b9Smrg /* 2724d4fba8b9Smrg * Sometimes someone uses a symbol font which has no useful ASCII or 2725d4fba8b9Smrg * Latin-1 characters. Allow that, in case they did it intentionally. 2726d4fba8b9Smrg */ 2727d4fba8b9Smrg if (width == 0) { 2728d4fba8b9Smrg failed = 1; 2729d4fba8b9Smrg if (last >= 256) { 2730d1603babSmrg width = data->font_info.max_width; 2731956cc18dSsnj } 2732956cc18dSsnj } 2733d1603babSmrg data->font_info.min_width = width; 2734d1603babSmrg data->font_info.mixed = (data->font_info.max_width >= 2735d1603babSmrg (data->font_info.min_width + 1)); 2736d4fba8b9Smrg return failed; 2737956cc18dSsnj} 2738956cc18dSsnj 2739d1603babSmrg#if OPT_TRACE 2740d1603babSmrgstatic const char * 2741d1603babSmrgnameOfXftFont(XftFont *fp) 2742d1603babSmrg{ 2743d1603babSmrg static char *result; 2744d1603babSmrg char buffer[1024]; 2745d1603babSmrg FreeAndNull(result); 2746d1603babSmrg if (XftNameUnparse(fp->pattern, buffer, (int) sizeof(buffer))) { 2747d1603babSmrg char *target; 2748d1603babSmrg char *source = buffer; 2749d1603babSmrg if ((target = strtok(source, ":")) != 0) { 2750d1603babSmrg result = x_strdup(target); 2751d1603babSmrg } 2752d1603babSmrg } 2753d1603babSmrg return NonNull(result); 2754d1603babSmrg} 2755d1603babSmrg#endif 2756d1603babSmrg 2757dfb07bc7Smrg#if OPT_REPORT_FONTS 2758fa3f02f3Smrgstatic void 2759fa3f02f3SmrgreportXftFonts(XtermWidget xw, 2760d1603babSmrg XTermXftFonts *fontData, 2761d1603babSmrg int fontNum, 27629a64e1c5Smrg XftFont *fp, 2763fa3f02f3Smrg const char *name, 2764fa3f02f3Smrg const char *tag, 27659a64e1c5Smrg XftPattern *match) 2766fa3f02f3Smrg{ 2767fa3f02f3Smrg if (resource.reportFonts) { 2768fa3f02f3Smrg char buffer[1024]; 2769fa3f02f3Smrg FcChar32 first_char = xtermXftFirstChar(fp); 2770fa3f02f3Smrg FcChar32 last_char = xtermXftLastChar(fp); 2771fa3f02f3Smrg FcChar32 ch; 2772fa3f02f3Smrg unsigned missing = 0; 2773fa3f02f3Smrg 2774d1603babSmrg ReportFonts("Loaded XftFonts(%s[%s])\n", name, tag); 2775fa3f02f3Smrg 2776fa3f02f3Smrg for (ch = first_char; ch <= last_char; ++ch) { 2777d1603babSmrg if (xtermXftMissing(xw, fontData, fontNum, fp, ch)) { 2778fa3f02f3Smrg ++missing; 2779fa3f02f3Smrg } 2780fa3f02f3Smrg } 2781d1603babSmrg ReportFonts("\t\tfirst char: %u\n", first_char); 2782d1603babSmrg ReportFonts("\t\tlast char: %u\n", last_char); 2783d1603babSmrg ReportFonts("\t\tmissing-chars: %u\n", missing); 2784d1603babSmrg ReportFonts("\t\tpresent-chars: %u\n", ((last_char - first_char) 2785d1603babSmrg + 1 - missing)); 2786fa3f02f3Smrg 2787fa3f02f3Smrg if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 2788fa3f02f3Smrg char *target; 2789fa3f02f3Smrg char *source = buffer; 2790fa3f02f3Smrg while ((target = strtok(source, ":")) != 0) { 2791d1603babSmrg ReportFonts("\t%s\n", target); 2792fa3f02f3Smrg source = 0; 2793fa3f02f3Smrg } 2794fa3f02f3Smrg } 2795d4fba8b9Smrg fflush(stdout); 2796fa3f02f3Smrg } 2797fa3f02f3Smrg} 2798d1603babSmrg 2799d1603babSmrgstatic void 2800d1603babSmrgreportXftFallbackFont(XtermWidget xw, 2801d1603babSmrg XTermXftFonts *fontData, 2802d1603babSmrg int fontNum, 2803d1603babSmrg XftFont *font, 2804d1603babSmrg XftPattern *match) 2805d1603babSmrg{ 2806d1603babSmrg if (resource.reportFonts) { 2807d1603babSmrg char tag[80]; 2808d1603babSmrg sprintf(tag, "%s#%d", 2809d1603babSmrg whichXftFonts(xw, fontData), 2810d1603babSmrg fontNum + 1); 2811d1603babSmrg reportXftFonts(xw, fontData, fontNum, font, "fallback", tag, match); 2812d1603babSmrg } 2813d1603babSmrg} 2814d1603babSmrg 2815dfb07bc7Smrg#else 2816d1603babSmrg#define reportXftFonts(xw, fontData, fontNum, result, name, tag, match) /* empty */ 2817d1603babSmrg#define reportXftFallbackFont(xw, fontData, fontNum, font, match) /* empty */ 2818dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 2819fa3f02f3Smrg 2820d4fba8b9Smrg/* 2821d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to 2822d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does 2823d4fba8b9Smrg * this. That is, closing a font-file may leave the data in Xft's cache, while 2824d4fba8b9Smrg * opening a file may free the data used for the match. 2825d4fba8b9Smrg * 2826d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data 2827d4fba8b9Smrg * if it may have been seen before. 2828d4fba8b9Smrg */ 2829d4fba8b9SmrgBoolean 2830d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font) 2831d4fba8b9Smrg{ 2832d4fba8b9Smrg Boolean result = False; 2833d1603babSmrg if (font != NULL) { 2834d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2835d4fba8b9Smrg ListXftFonts *p; 2836d1603babSmrg for (p = screen->list_xft_fonts; p != NULL; p = p->next) { 2837d4fba8b9Smrg if (p->font == font) { 2838d4fba8b9Smrg result = True; 2839d4fba8b9Smrg break; 2840d4fba8b9Smrg } 2841d4fba8b9Smrg } 2842d4fba8b9Smrg if (!result) { 2843d4fba8b9Smrg p = TypeXtMalloc(ListXftFonts); 2844d1603babSmrg if (p != NULL) { 2845d4fba8b9Smrg p->font = font; 2846d4fba8b9Smrg p->next = screen->list_xft_fonts; 2847d4fba8b9Smrg screen->list_xft_fonts = p; 2848d4fba8b9Smrg } 2849d4fba8b9Smrg } 2850d4fba8b9Smrg } 2851d4fba8b9Smrg return result; 2852d4fba8b9Smrg} 2853d4fba8b9Smrg 2854d4fba8b9Smrg/* 2855d4fba8b9Smrg * Drop an entry from the cache, and close the font. 2856d4fba8b9Smrg */ 2857d4fba8b9Smrgvoid 2858d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font) 2859d4fba8b9Smrg{ 2860d4fba8b9Smrg if (font != 0) { 2861d4fba8b9Smrg ListXftFonts *p, *q; 2862d4fba8b9Smrg 2863d4fba8b9Smrg for (p = screen->list_xft_fonts, q = 0; p != 0; q = p, p = p->next) { 2864d4fba8b9Smrg if (p->font == font) { 2865d4fba8b9Smrg XftFontClose(screen->display, font); 2866d4fba8b9Smrg if (q != 0) { 2867d4fba8b9Smrg q->next = p->next; 2868d4fba8b9Smrg } else { 2869d4fba8b9Smrg screen->list_xft_fonts = p->next; 2870d4fba8b9Smrg } 2871d4fba8b9Smrg free(p); 2872d4fba8b9Smrg break; 2873d4fba8b9Smrg } 2874d4fba8b9Smrg } 2875d4fba8b9Smrg } 2876d4fba8b9Smrg} 2877d4fba8b9Smrg 2878d1603babSmrgstatic void 2879d1603babSmrgxtermOpenXft(XtermWidget xw, 2880d1603babSmrg XTermXftFonts *fontData, 2881d1603babSmrg int fontNum, 2882d1603babSmrg const char *name, 2883d1603babSmrg XftPattern *pat, 2884d1603babSmrg const char *tag) 2885d522f475Smrg{ 2886956cc18dSsnj TScreen *screen = TScreenOf(xw); 2887956cc18dSsnj Display *dpy = screen->display; 2888d522f475Smrg XftResult status; 2889d522f475Smrg XftFont *result = 0; 2890d522f475Smrg 2891d4fba8b9Smrg TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag)); 2892d1603babSmrg if (pat != 0 && (fontNum <= MaxXftCache)) { 2893d4fba8b9Smrg XftPattern *match; 2894d4fba8b9Smrg 2895d4fba8b9Smrg FcConfigSubstitute(NULL, pat, FcMatchPattern); 2896d4fba8b9Smrg XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat); 2897d4fba8b9Smrg 2898d4fba8b9Smrg match = FcFontMatch(NULL, pat, &status); 2899d522f475Smrg if (match != 0) { 2900d4fba8b9Smrg Boolean maybeReopened = False; 2901d522f475Smrg result = XftFontOpenPattern(dpy, match); 2902d4fba8b9Smrg#ifdef FC_COLOR 2903d1603babSmrg if (result != NULL) { 2904d4fba8b9Smrg if (isBogusXft(result)) { 2905d4fba8b9Smrg XftFontClose(dpy, result); 2906d1603babSmrg result = NULL; 2907d4fba8b9Smrg maybeReopened = True; 2908d4fba8b9Smrg } 2909d4fba8b9Smrg } 2910d4fba8b9Smrg#endif 2911d1603babSmrg if (result != NULL) { 2912d522f475Smrg TRACE(("...matched %s font\n", tag)); 2913d1603babSmrg if (fontData->fs_size < fontNum) 2914d1603babSmrg fontData->fs_size = fontNum; 2915d1603babSmrg XftFpN(fontData, fontNum) = result; 2916d1603babSmrg XftIsN(fontData, fontNum) = xcOpened; 2917d4fba8b9Smrg if (!maybeXftCache(xw, result)) { 2918d1603babSmrg reportXftFonts(xw, fontData, fontNum, result, name, tag, match); 2919d4fba8b9Smrg } 2920d522f475Smrg } else { 2921d4fba8b9Smrg TRACE(("...could not open %s font\n", tag)); 2922d4fba8b9Smrg if (!maybeReopened) 2923d4fba8b9Smrg XftPatternDestroy(match); 2924956cc18dSsnj if (xw->misc.fontWarnings >= fwAlways) { 2925dfb07bc7Smrg cannotFont(xw, "open", tag, name); 2926956cc18dSsnj } 2927d522f475Smrg } 2928d522f475Smrg } else { 2929d522f475Smrg TRACE(("...did not match %s font\n", tag)); 2930956cc18dSsnj if (xw->misc.fontWarnings >= fwResource) { 2931dfb07bc7Smrg cannotFont(xw, "match", tag, name); 2932956cc18dSsnj } 2933d522f475Smrg } 2934d522f475Smrg } 2935d1603babSmrg if (result == NULL && (fontNum <= MaxXftCache)) { 2936d1603babSmrg XftFpN(fontData, fontNum) = NULL; 2937d1603babSmrg XftIsN(fontData, fontNum) = xcEmpty; 2938d1603babSmrg } 2939d522f475Smrg} 2940d522f475Smrg 2941d522f475Smrg#if OPT_SHIFT_FONTS 2942d522f475Smrg/* 2943d522f475Smrg * Don't make a dependency on the math library for a single function. 2944d522f475Smrg * (Newton Raphson). 2945d522f475Smrg */ 2946d522f475Smrgstatic double 29470bd37d32SmrgdimSquareRoot(double value) 2948d522f475Smrg{ 2949d522f475Smrg double result = 0.0; 2950d522f475Smrg if (value > 0.0) { 2951d522f475Smrg int n; 2952d522f475Smrg double older = value; 2953d522f475Smrg for (n = 0; n < 10; ++n) { 2954d522f475Smrg double delta = (older * older - value) / (2.0 * older); 2955d522f475Smrg double newer = older - delta; 2956d522f475Smrg older = newer; 2957d522f475Smrg result = newer; 2958d522f475Smrg if (delta > -0.001 && delta < 0.001) 2959d522f475Smrg break; 2960d522f475Smrg } 2961d522f475Smrg } 2962d522f475Smrg return result; 2963d522f475Smrg} 2964d522f475Smrg#endif 2965d522f475Smrg 2966d4fba8b9Smrg#ifdef DEBUG_XFT 2967d4fba8b9Smrgstatic void 2968d1603babSmrgtrace_xft_glyph(XtermWidget xw, XTermXftFonts *data, FT_Face face, int code, const char *name) 2969d4fba8b9Smrg{ 2970d1603babSmrg if (xtermXftMissing(xw, data, 0, XftFp(data), code)) { 2971d4fba8b9Smrg TRACE(("Xft glyph U+%04X missing :%s\n", code, name)); 2972d4fba8b9Smrg } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 2973d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 2974d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 2975d4fba8b9Smrg code, 2976d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 2977d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 2978d4fba8b9Smrg name)); 2979d4fba8b9Smrg } 2980d4fba8b9Smrg} 2981d4fba8b9Smrg 2982d4fba8b9Smrg#if OPT_WIDE_CHARS 2983d4fba8b9Smrgstatic void 2984d1603babSmrgtrace_xft_line_drawing(XtermWidget xw, XTermXftFonts *data, FT_Face face) 2985d4fba8b9Smrg{ 2986d4fba8b9Smrg int n; 2987d4fba8b9Smrg for (n = 0; unicode_boxes[n].code != 0; ++n) { 2988d1603babSmrg trace_xft_glyph(xw, data, face, unicode_boxes[n].code, 2989d4fba8b9Smrg unicode_boxes[n].name); 2990d4fba8b9Smrg } 2991d4fba8b9Smrg} 2992d4fba8b9Smrg#else 2993d1603babSmrg#define trace_xft_line_drawing(xw, data, face) /* nothing */ 2994d4fba8b9Smrg#endif 2995d4fba8b9Smrg#endif /* DEBUG_XFT */ 2996d4fba8b9Smrg 2997d4fba8b9Smrg/* 2998d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box. If so, 2999d4fba8b9Smrg * they're not useful. 3000d4fba8b9Smrg */ 3001d4fba8b9Smrg#if OPT_BOX_CHARS 3002d4fba8b9Smrgstatic void 3003d1603babSmrglinedrawing_gaps(XtermWidget xw, XTermXftFonts *data) 3004d4fba8b9Smrg{ 3005d4fba8b9Smrg Boolean broken; 3006d4fba8b9Smrg 3007d4fba8b9Smrg#if OPT_WIDE_CHARS 3008d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3009d4fba8b9Smrg int n; 3010d4fba8b9Smrg FT_Face face; 3011d1603babSmrg face = XftLockFace(XftFp(data)); 3012d4fba8b9Smrg broken = False; 3013d4fba8b9Smrg for (n = 0; unicode_boxes[n].code; ++n) { 3014d4fba8b9Smrg unsigned code = unicode_boxes[n].code; 3015d4fba8b9Smrg 3016d1603babSmrg if (xtermXftMissing(xw, data, 0, XftFp(data), code)) { 3017d4fba8b9Smrg TRACE(("Xft glyph U+%04X is missing\n", code)); 3018d4fba8b9Smrg broken = True; 3019d4fba8b9Smrg break; 3020d4fba8b9Smrg } 3021d4fba8b9Smrg 3022d4fba8b9Smrg if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 3023d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 3024d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 3025d4fba8b9Smrg code, 3026d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 3027d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 3028d4fba8b9Smrg unicode_boxes[n].name)); 3029d4fba8b9Smrg /* 3030d4fba8b9Smrg * While it is possible for badly-designed fonts to have line 3031d4fba8b9Smrg * drawing characters which do not meet, FreeType aggravates the 3032d4fba8b9Smrg * situation with its rounding. Check for an obvious case where 3033d4fba8b9Smrg * the weights at the ends of a vertical line do not add up. That 3034d4fba8b9Smrg * shows up as two under-weight rows at the beginning/end of the 3035d4fba8b9Smrg * bitmap. 3036d4fba8b9Smrg */ 3037d4fba8b9Smrg if (code == 0x2502) { 3038d4fba8b9Smrg unsigned r, c; 3039d4fba8b9Smrg unsigned mids = 0, ends = 0; 3040d1603babSmrg unsigned char *buffer = g->bitmap.buffer; 3041d4fba8b9Smrg 3042d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 3043d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 3044d4fba8b9Smrg /* FALLTHRU */ 3045d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 3046d4fba8b9Smrg for (r = 0; r < (unsigned) g->bitmap.rows; ++r) { 3047d4fba8b9Smrg unsigned k = r * (unsigned) g->bitmap.pitch; 3048d4fba8b9Smrg unsigned sum = 0; 3049d4fba8b9Smrg for (c = 0; c < (unsigned) g->bitmap.width; ++c) { 3050d4fba8b9Smrg unsigned xx = 0; 3051d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 3052d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 3053d1603babSmrg xx = (unsigned) ((buffer[k + (c / 8)] 3054d4fba8b9Smrg >> (c % 8)) & 1); 3055d4fba8b9Smrg break; 3056d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 3057d1603babSmrg xx = buffer[k + c]; 3058d4fba8b9Smrg break; 3059d4fba8b9Smrg } 3060d4fba8b9Smrg sum += xx; 3061d4fba8b9Smrg TRACE2((" %2x", xx)); 3062d4fba8b9Smrg } 3063d4fba8b9Smrg TRACE2((" = %u\n", sum)); 3064d4fba8b9Smrg if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) { 3065d4fba8b9Smrg mids = sum; 3066d4fba8b9Smrg } else { 3067d4fba8b9Smrg ends += sum; 3068d4fba8b9Smrg } 3069d4fba8b9Smrg } 3070d4fba8b9Smrg TRACE(("...compare middle %u vs ends %u\n", mids, ends)); 3071d4fba8b9Smrg if ((mids > ends) && (g->bitmap.rows < 16)) 3072d4fba8b9Smrg broken = True; 3073d4fba8b9Smrg break; 3074d4fba8b9Smrg default: 3075d4fba8b9Smrg TRACE(("FIXME pixel_mode %d not handled\n", 3076d4fba8b9Smrg g->bitmap.pixel_mode)); 3077d4fba8b9Smrg break; 3078d4fba8b9Smrg } 3079d4fba8b9Smrg if (broken) 3080d4fba8b9Smrg break; 3081d4fba8b9Smrg } 3082d4fba8b9Smrg /* 3083d4fba8b9Smrg * The factor of two accounts for line-drawing that goes through 3084d4fba8b9Smrg * the middle of a cell, possibly leaving half of the cell unused. 3085d4fba8b9Smrg * A horizontal line has to extend the full width of the cell. 3086d4fba8b9Smrg */ 3087d4fba8b9Smrg switch (unicode_boxes[n].high) { 3088d4fba8b9Smrg case 1: 3089d4fba8b9Smrg if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) { 3090d4fba8b9Smrg TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n", 3091d4fba8b9Smrg (unsigned) g->bitmap.rows, 3092d4fba8b9Smrg (unsigned) FontHeight(screen))); 3093d4fba8b9Smrg broken = True; 3094d4fba8b9Smrg } 3095d4fba8b9Smrg break; 3096d4fba8b9Smrg case 2: 3097d4fba8b9Smrg if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) { 3098d4fba8b9Smrg TRACE(("...bitmap is too short for half-cell (%u vs %u)\n", 3099d4fba8b9Smrg (unsigned) (g->bitmap.rows * 2), 3100d4fba8b9Smrg (unsigned) FontHeight(screen))); 3101d4fba8b9Smrg broken = True; 3102d4fba8b9Smrg } 3103d4fba8b9Smrg break; 3104d4fba8b9Smrg } 3105d4fba8b9Smrg switch (unicode_boxes[n].wide) { 3106d4fba8b9Smrg case 1: 3107d4fba8b9Smrg if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) { 3108d4fba8b9Smrg TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n", 3109d4fba8b9Smrg (unsigned) g->bitmap.width, 3110d4fba8b9Smrg (unsigned) FontWidth(screen))); 3111d4fba8b9Smrg broken = True; 3112d4fba8b9Smrg } 3113d4fba8b9Smrg break; 3114d4fba8b9Smrg case 2: 3115d4fba8b9Smrg if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) { 3116d4fba8b9Smrg TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n", 3117d4fba8b9Smrg (unsigned) (g->bitmap.width * 2), 3118d4fba8b9Smrg (unsigned) FontWidth(screen))); 3119d4fba8b9Smrg broken = True; 3120d4fba8b9Smrg } 3121d4fba8b9Smrg break; 3122d4fba8b9Smrg } 3123d4fba8b9Smrg if (broken) 3124d4fba8b9Smrg break; 3125d4fba8b9Smrg } 3126d4fba8b9Smrg } 3127d1603babSmrg XftUnlockFace(XftFp(data)); 3128d4fba8b9Smrg#else 3129d1603babSmrg (void) data; 3130d4fba8b9Smrg broken = True; 3131d4fba8b9Smrg#endif 3132d4fba8b9Smrg 3133d4fba8b9Smrg if (broken) { 3134d4fba8b9Smrg TRACE(("Xft line-drawing would not work\n")); 3135d4fba8b9Smrg setBrokenBoxChars(xw, True); 3136d4fba8b9Smrg } 3137d4fba8b9Smrg} 3138d4fba8b9Smrg#endif /* OPT_BOX_CHARS */ 3139d4fba8b9Smrg 3140d522f475Smrg/* 3141d522f475Smrg * Given the Xft font metrics, determine the actual font size. This is used 3142d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same 3143d522f475Smrg * rule. 3144d522f475Smrg */ 3145d522f475Smrgstatic void 3146d1603babSmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XTermXftFonts *data, const char *tag) 3147d522f475Smrg{ 3148d1603babSmrg XftFont *font = XftFp(data); 3149d1603babSmrg if (font != NULL) { 3150d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3151d522f475Smrg int width, height, ascent, descent; 3152d4fba8b9Smrg#ifdef DEBUG_XFT 3153d4fba8b9Smrg int n; 3154d4fba8b9Smrg FT_Face face; 3155d4fba8b9Smrg FT_Size size; 3156d4fba8b9Smrg FT_Size_Metrics metrics; 3157d4fba8b9Smrg Boolean scalable; 3158d4fba8b9Smrg Boolean is_fixed; 3159d4fba8b9Smrg Boolean debug_xft = False; 3160d4fba8b9Smrg 3161d4fba8b9Smrg face = XftLockFace(font); 3162d4fba8b9Smrg size = face->size; 3163d4fba8b9Smrg metrics = size->metrics; 3164d4fba8b9Smrg is_fixed = FT_IS_FIXED_WIDTH(face); 3165d4fba8b9Smrg scalable = FT_IS_SCALABLE(face); 3166d1603babSmrg trace_xft_line_drawing(xw, data, face); 3167d4fba8b9Smrg for (n = 32; n < 127; ++n) { 3168d4fba8b9Smrg char name[80]; 3169d4fba8b9Smrg sprintf(name, "letter \"%c\"", n); 3170d1603babSmrg trace_xft_glyph(xw, data, face, n, name); 3171d4fba8b9Smrg } 3172d4fba8b9Smrg XftUnlockFace(font); 3173d4fba8b9Smrg 3174d4fba8b9Smrg /* freetype's inconsistent for this sign */ 3175d4fba8b9Smrg metrics.descender = -metrics.descender; 3176d4fba8b9Smrg 3177d4fba8b9Smrg#define TR_XFT "Xft metrics: " 3178d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0) 3179d4fba8b9Smrg#define M_64(a,b) ((font->a * 64) != metrics.b) 3180d4fba8b9Smrg#define BOTH(a,b) D_64(b), M_64(a,b) ? "*" : "" 3181d4fba8b9Smrg 3182d4fba8b9Smrg debug_xft = (M_64(ascent, ascender) 3183d4fba8b9Smrg || M_64(descent, descender) 3184d4fba8b9Smrg || M_64(height, height) 3185d4fba8b9Smrg || M_64(max_advance_width, max_advance)); 3186d4fba8b9Smrg 3187d4fba8b9Smrg TRACE(("Xft font is %sscalable, %sfixed-width\n", 3188d4fba8b9Smrg is_fixed ? "" : "not ", 3189d4fba8b9Smrg scalable ? "" : "not ")); 3190d4fba8b9Smrg 3191d4fba8b9Smrg if (debug_xft) { 3192d4fba8b9Smrg TRACE(("Xft font size %d+%d vs %d by %d\n", 3193d4fba8b9Smrg font->ascent, 3194d4fba8b9Smrg font->descent, 3195d4fba8b9Smrg font->height, 3196d4fba8b9Smrg font->max_advance_width)); 3197d4fba8b9Smrg TRACE((TR_XFT "ascender %6.2f%s\n", BOTH(ascent, ascender))); 3198d4fba8b9Smrg TRACE((TR_XFT "descender %6.2f%s\n", BOTH(descent, descender))); 3199d4fba8b9Smrg TRACE((TR_XFT "height %6.2f%s\n", BOTH(height, height))); 3200d4fba8b9Smrg TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance))); 3201d4fba8b9Smrg } else { 3202d4fba8b9Smrg TRACE((TR_XFT "matches font\n")); 3203d4fba8b9Smrg } 3204d4fba8b9Smrg#endif 3205d522f475Smrg 3206d522f475Smrg width = font->max_advance_width; 3207d522f475Smrg height = font->height; 3208d522f475Smrg ascent = font->ascent; 3209d522f475Smrg descent = font->descent; 3210d4fba8b9Smrg if (screen->force_xft_height && height < ascent + descent) { 3211d4fba8b9Smrg TRACE(("...height is less than ascent + descent (%u vs %u)\n", 3212d4fba8b9Smrg height, ascent + descent)); 3213d4fba8b9Smrg if ((ascent + descent) > (height + 1)) { 3214d4fba8b9Smrg /* this happens less than 10% of the time */ 3215d4fba8b9Smrg --ascent; 3216d4fba8b9Smrg --descent; 3217d4fba8b9Smrg TRACE(("...decrement both ascent and descent before retry\n")); 3218d4fba8b9Smrg } else if (ascent > descent) { 3219d4fba8b9Smrg /* this is the usual case */ 3220d4fba8b9Smrg --ascent; 3221d4fba8b9Smrg TRACE(("...decrement ascent before retry\n")); 3222d4fba8b9Smrg } else { 3223d4fba8b9Smrg /* this could happen, though rare... */ 3224d4fba8b9Smrg --descent; 3225d4fba8b9Smrg TRACE(("...decrement descent before retry\n")); 3226d4fba8b9Smrg } 3227d522f475Smrg height = ascent + descent; 3228d4fba8b9Smrg font->ascent = ascent; 3229d4fba8b9Smrg font->descent = descent; 3230d4fba8b9Smrg TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n", 3231d4fba8b9Smrg height, ascent + descent, ascent, descent)); 3232d522f475Smrg } 3233d522f475Smrg if (is_double_width_font_xft(screen->display, font)) { 3234d4fba8b9Smrg TRACE(("...reduce width from %d to %d\n", width, width >> 1)); 3235d522f475Smrg width >>= 1; 3236d522f475Smrg } 3237d522f475Smrg if (tag == 0) { 32380bd37d32Smrg SetFontWidth(screen, win, width); 32390bd37d32Smrg SetFontHeight(screen, win, height); 3240d522f475Smrg win->f_ascent = ascent; 3241d522f475Smrg win->f_descent = descent; 3242d522f475Smrg TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 3243d522f475Smrg width, height, ascent, descent)); 3244d522f475Smrg } else if (win->f_width < width || 3245d522f475Smrg win->f_height < height || 3246d522f475Smrg win->f_ascent < ascent || 3247d522f475Smrg win->f_descent < descent) { 3248d522f475Smrg TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 3249d522f475Smrg tag, 3250d522f475Smrg win->f_width, win->f_height, win->f_ascent, win->f_descent, 3251d522f475Smrg width, height, ascent, descent)); 3252d522f475Smrg 32530bd37d32Smrg SetFontWidth(screen, win, width); 32540bd37d32Smrg SetFontHeight(screen, win, height); 3255d522f475Smrg win->f_ascent = ascent; 3256d522f475Smrg win->f_descent = descent; 3257d522f475Smrg } else { 3258d522f475Smrg TRACE(("setRenderFontsize %s unchanged\n", tag)); 3259d522f475Smrg } 3260d4fba8b9Smrg#if OPT_BOX_CHARS 3261d4fba8b9Smrg if (!screen->broken_box_chars && (tag == 0)) { 3262d1603babSmrg linedrawing_gaps(xw, data); 3263d4fba8b9Smrg } 3264d4fba8b9Smrg#endif 3265d522f475Smrg } 3266d522f475Smrg} 3267d522f475Smrg#endif 3268d522f475Smrg 326920d2c4d2Smrgstatic void 3270d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed) 327120d2c4d2Smrg{ 3272d4fba8b9Smrg if (value == 0 || failed) { 3273d4fba8b9Smrg if (value == 0) { 3274d4fba8b9Smrg xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 3275d4fba8b9Smrg exit(1); 3276d4fba8b9Smrg } else { 3277d4fba8b9Smrg xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag); 3278d4fba8b9Smrg } 327920d2c4d2Smrg } 328020d2c4d2Smrg} 328120d2c4d2Smrg 328220d2c4d2Smrg#if OPT_RENDERFONT 328320d2c4d2Smrgvoid 32849a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub) 328520d2c4d2Smrg{ 3286d1603babSmrg if (XftFp(pub) != NULL) { 3287d1603babSmrg int n; 3288d4fba8b9Smrg 3289d4fba8b9Smrg if (pub->pattern) { 3290d4fba8b9Smrg XftPatternDestroy(pub->pattern); 3291d1603babSmrg pub->pattern = NULL; 3292d4fba8b9Smrg } 3293d4fba8b9Smrg if (pub->fontset) { 3294d4fba8b9Smrg XftFontSetDestroy(pub->fontset); 3295d1603babSmrg pub->fontset = NULL; 3296d4fba8b9Smrg } 3297d4fba8b9Smrg 3298d1603babSmrg for (n = 0; n <= pub->fs_size; ++n) { 3299d1603babSmrg if (XftFpN(pub, n) != NULL) { 3300d1603babSmrg closeCachedXft(screen, XftFpN(pub, n)); 3301d1603babSmrg XftFpN(pub, n) = NULL; 3302d1603babSmrg XftIsN(pub, n) = xcEmpty; 3303d4fba8b9Smrg } 3304d4fba8b9Smrg } 3305d1603babSmrg FreeAndNull(pub->font_map.per_font); 3306d1603babSmrg memset(pub, 0, sizeof(*pub)); 330720d2c4d2Smrg } 330820d2c4d2Smrg} 330920d2c4d2Smrg 331020d2c4d2Smrg/* 3311d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting. 331220d2c4d2Smrg */ 3313492d43a5SmrgString 3314d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName) 331520d2c4d2Smrg{ 331620d2c4d2Smrg#if OPT_RENDERWIDE 3317492d43a5Smrg String result = (wideName 3318dfb07bc7Smrg ? FirstItemOf(xw->work.fonts.xft.list_w) 3319dfb07bc7Smrg : CurrentXftFont(xw)); 332020d2c4d2Smrg#else 3321dfb07bc7Smrg String result = CurrentXftFont(xw); 3322d4fba8b9Smrg (void) wideName; 332320d2c4d2Smrg#endif 332420d2c4d2Smrg return x_nonempty(result); 332520d2c4d2Smrg} 332620d2c4d2Smrg 332720d2c4d2Smrg/* 332820d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that 332920d2c4d2Smrg * are derived from it. 333020d2c4d2Smrg */ 333120d2c4d2Smrgvoid 333220d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value) 333320d2c4d2Smrg{ 333420d2c4d2Smrg TScreen *screen = TScreenOf(xw); 3335dfb07bc7Smrg Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0) 3336dfb07bc7Smrg || strcmp(CurrentXftFont(xw), value)); 333720d2c4d2Smrg 33380bd37d32Smrg if (changed) { 3339037a25ddSmrg int n; 3340037a25ddSmrg 3341dfb07bc7Smrg CurrentXftFont(xw) = x_strdup(value); 33420bd37d32Smrg for (n = 0; n < NMENUFONTS; ++n) { 3343dfb07bc7Smrg int e; 33440bd37d32Smrg xw->misc.face_size[n] = -1.0; 3345dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 3346dfb07bc7Smrg xtermCloseXft(screen, getMyXftFont(xw, e, n)); 3347dfb07bc7Smrg } 33480bd37d32Smrg } 334920d2c4d2Smrg } 335020d2c4d2Smrg} 335120d2c4d2Smrg#endif 335220d2c4d2Smrg 3353d522f475Smrg/* 3354d522f475Smrg * Compute useful values for the font/window sizes 3355d522f475Smrg */ 3356d522f475Smrgvoid 3357d522f475SmrgxtermComputeFontInfo(XtermWidget xw, 33589a64e1c5Smrg VTwin *win, 33599a64e1c5Smrg XFontStruct *font, 3360d522f475Smrg int sbwidth) 3361d522f475Smrg{ 3362956cc18dSsnj TScreen *screen = TScreenOf(xw); 3363d522f475Smrg 3364d522f475Smrg int i, j, width, height; 3365492d43a5Smrg#if OPT_RENDERFONT 3366492d43a5Smrg int fontnum = screen->menu_font_number; 3367492d43a5Smrg#endif 3368d4fba8b9Smrg int failed = 0; 3369d522f475Smrg 3370d522f475Smrg#if OPT_RENDERFONT 3371d522f475Smrg /* 3372d522f475Smrg * xterm contains a lot of references to fonts, assuming they are fixed 3373d522f475Smrg * size. This chunk of code overrides the actual font-selection (see 3374d522f475Smrg * drawXtermText()), if the user has selected render-font. All of the 3375d522f475Smrg * font-loading for fixed-fonts still goes on whether or not this chunk 3376d522f475Smrg * overrides it. 3377d522f475Smrg */ 3378492d43a5Smrg if (UsingRenderFont(xw) && fontnum >= 0) { 3379492d43a5Smrg String face_name = getFaceName(xw, False); 3380d1603babSmrg XTermXftFonts *norm = &(screen->renderFontNorm[fontnum]); 3381d1603babSmrg XTermXftFonts *bold = &(screen->renderFontBold[fontnum]); 3382d1603babSmrg XTermXftFonts *ital = &(screen->renderFontItal[fontnum]); 3383d1603babSmrg XTermXftFonts *btal = &(screen->renderFontBtal[fontnum]); 3384d522f475Smrg#if OPT_RENDERWIDE 3385d1603babSmrg XTermXftFonts *wnorm = &(screen->renderWideNorm[fontnum]); 3386d1603babSmrg XTermXftFonts *wbold = &(screen->renderWideBold[fontnum]); 3387d1603babSmrg XTermXftFonts *wital = &(screen->renderWideItal[fontnum]); 3388d1603babSmrg XTermXftFonts *wbtal = &(screen->renderWideBtal[fontnum]); 3389d522f475Smrg#endif 3390d522f475Smrg 3391d1603babSmrg if (XftFp(norm) == 0 && !IsEmpty(face_name)) { 3392d1603babSmrg Work *work = &(xw->work); 3393d522f475Smrg XftPattern *pat; 33940bd37d32Smrg double face_size; 3395d522f475Smrg 33960bd37d32Smrg TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 3397492d43a5Smrg fontnum, face_name, 3398d522f475Smrg xw->misc.face_size[fontnum])); 3399d522f475Smrg 3400d1603babSmrg TRACE(("Using Xft %d\n", XftGetVersion())); 3401d4fba8b9Smrg TRACE(("Using FontConfig %d\n", FC_VERSION)); 3402d4fba8b9Smrg 3403d1603babSmrg if (work->xft_defaults == NULL) { 3404d1603babSmrg FcInit(); 3405d1603babSmrg work->xft_defaults = FcPatternCreate(); 3406d1603babSmrg XftDefaultSubstitute(screen->display, 3407d1603babSmrg XScreenNumberOfScreen(XtScreen(xw)), 3408d1603babSmrg work->xft_defaults); 3409d1603babSmrg if (screen->xft_max_glyph_memory > 0) { 3410d1603babSmrg FcPatternAddInteger(work->xft_defaults, 3411d1603babSmrg XFT_MAX_GLYPH_MEMORY, 3412d1603babSmrg screen->xft_max_glyph_memory); 3413d1603babSmrg } 3414d1603babSmrg if (screen->xft_max_unref_fonts > 0) { 3415d1603babSmrg FcPatternAddInteger(work->xft_defaults, 3416d1603babSmrg XFT_MAX_UNREF_FONTS, 3417d1603babSmrg screen->xft_max_unref_fonts); 3418d1603babSmrg } 3419d1603babSmrg#ifdef XFT_TRACK_MEM_USAGE 3420d1603babSmrg FcPatternAddBool(work->xft_defaults, 3421d1603babSmrg XFT_TRACK_MEM_USAGE, 3422d1603babSmrg screen->xft_track_mem_usage); 3423d1603babSmrg#endif 3424d1603babSmrg XftDefaultSet(screen->display, work->xft_defaults); 3425d1603babSmrg } 3426d1603babSmrg 34270bd37d32Smrg fillInFaceSize(xw, fontnum); 3428d4fba8b9Smrg face_size = (double) xw->misc.face_size[fontnum]; 3429d522f475Smrg 3430d522f475Smrg /* 3431d522f475Smrg * By observation (there is no documentation), XftPatternBuild is 3432d522f475Smrg * cumulative. Build the bold- and italic-patterns on top of the 3433d522f475Smrg * normal pattern. 3434d522f475Smrg */ 3435d4fba8b9Smrg#ifdef FC_COLOR 3436d1603babSmrg#if USE_FC_COLOR 3437d1603babSmrg#define NormXftPattern \ 3438d1603babSmrg XFT_FAMILY, XftTypeString, "mono", \ 3439d1603babSmrg FC_OUTLINE, XftTypeBool, FcTrue, \ 3440d1603babSmrg XFT_SIZE, XftTypeDouble, face_size 3441d1603babSmrg#else 3442d522f475Smrg#define NormXftPattern \ 3443d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3444d4fba8b9Smrg FC_COLOR, XftTypeBool, FcFalse, \ 3445d4fba8b9Smrg FC_OUTLINE, XftTypeBool, FcTrue, \ 3446d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3447d1603babSmrg#endif 3448d4fba8b9Smrg#else 3449d4fba8b9Smrg#define NormXftPattern \ 3450d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3451d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3452d4fba8b9Smrg#endif 3453d522f475Smrg 3454d522f475Smrg#define BoldXftPattern(norm) \ 3455d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3456d1603babSmrg XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3457d522f475Smrg 3458d522f475Smrg#define ItalXftPattern(norm) \ 3459d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3460d1603babSmrg XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3461d4fba8b9Smrg 3462d4fba8b9Smrg#define BtalXftPattern(norm) \ 3463d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3464d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3465d1603babSmrg XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3466d522f475Smrg 34679a64e1c5Smrg#if OPT_WIDE_ATTRS 34689a64e1c5Smrg#define HAVE_ITALICS 1 34699a64e1c5Smrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0) 34709a64e1c5Smrg#elif OPT_ISO_COLORS 34719a64e1c5Smrg#define HAVE_ITALICS 1 34729a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0) 34739a64e1c5Smrg#else 34749a64e1c5Smrg#define HAVE_ITALICS 0 34759a64e1c5Smrg#endif 34769a64e1c5Smrg 3477d4fba8b9Smrg#if OPT_DEC_CHRSET 3478d4fba8b9Smrg freeall_DoubleFT(xw); 3479d4fba8b9Smrg#endif 348020d2c4d2Smrg if ((pat = XftNameParse(face_name)) != 0) { 3481d1603babSmrg#define OPEN_XFT(data, tag) xtermOpenXft(xw, data, 0, face_name, data->pattern, tag) 3482d1603babSmrg norm->pattern = XftPatternDuplicate(pat); 3483d1603babSmrg XftPatternBuild(norm->pattern, 3484d522f475Smrg NormXftPattern, 3485d522f475Smrg (void *) 0); 3486d4fba8b9Smrg OPEN_XFT(norm, "normal"); 3487d522f475Smrg 3488d1603babSmrg if (XftFp(norm) != 0) { 3489d1603babSmrg bold->pattern = XftPatternDuplicate(pat); 3490d1603babSmrg XftPatternBuild(bold->pattern, 3491d4fba8b9Smrg NormXftPattern, 3492d522f475Smrg BoldXftPattern(norm), 3493d522f475Smrg (void *) 0); 3494d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3495d522f475Smrg 34969a64e1c5Smrg#if HAVE_ITALICS 34979a64e1c5Smrg if (FIND_ITALICS) { 3498d1603babSmrg ital->pattern = XftPatternDuplicate(pat); 3499d1603babSmrg XftPatternBuild(ital->pattern, 3500d522f475Smrg NormXftPattern, 3501d522f475Smrg ItalXftPattern(norm), 3502d522f475Smrg (void *) 0); 3503d4fba8b9Smrg OPEN_XFT(ital, "italic"); 3504d1603babSmrg btal->pattern = XftPatternDuplicate(pat); 3505d1603babSmrg XftPatternBuild(btal->pattern, 3506d4fba8b9Smrg NormXftPattern, 3507d4fba8b9Smrg BtalXftPattern(norm), 3508d4fba8b9Smrg (void *) 0); 3509d4fba8b9Smrg OPEN_XFT(btal, "bold-italic"); 3510d522f475Smrg } 35119a64e1c5Smrg#endif 3512d522f475Smrg 3513d522f475Smrg /* 3514d522f475Smrg * FIXME: just assume that the corresponding font has no 3515d522f475Smrg * graphics characters. 3516d522f475Smrg */ 3517d522f475Smrg if (screen->fnt_boxes) { 3518d4fba8b9Smrg screen->fnt_boxes = 0; 3519d1603babSmrg TRACE(("Xft opened - will not use internal line-drawing characters\n")); 3520d522f475Smrg } 3521d522f475Smrg } 3522d522f475Smrg 3523d1603babSmrg CACHE_XFT(norm); 3524d4fba8b9Smrg 3525d1603babSmrg CACHE_XFT(bold); 3526d1603babSmrg if (XftFp(norm) != 0 && !XftFp(bold)) { 3527d4fba8b9Smrg noUsableXft(xw, "bold"); 3528d1603babSmrg XftPatternDestroy(bold->pattern); 3529d1603babSmrg bold->pattern = XftPatternDuplicate(pat); 3530d1603babSmrg XftPatternBuild(bold->pattern, 3531d4fba8b9Smrg NormXftPattern, 3532d4fba8b9Smrg (void *) 0); 3533d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3534d4fba8b9Smrg failed = 0; 3535d1603babSmrg CACHE_XFT(bold); 3536d4fba8b9Smrg } 3537d4fba8b9Smrg#if HAVE_ITALICS 3538d1603babSmrg CACHE_XFT(ital); 3539d1603babSmrg if (XftFp(norm) != 0 && !XftFp(ital)) { 3540d4fba8b9Smrg noUsableXft(xw, "italic"); 3541d1603babSmrg XftPatternDestroy(ital->pattern); 3542d1603babSmrg ital->pattern = XftPatternDuplicate(pat); 3543d1603babSmrg XftPatternBuild(ital->pattern, 3544d4fba8b9Smrg NormXftPattern, 3545d4fba8b9Smrg (void *) 0); 3546d4fba8b9Smrg OPEN_XFT(ital, "italics"); 3547d4fba8b9Smrg failed = 0; 3548d1603babSmrg CACHE_XFT(ital); 3549d4fba8b9Smrg } 3550d1603babSmrg CACHE_XFT(btal); 3551d1603babSmrg if (XftFp(norm) != 0 && !XftFp(btal)) { 3552d4fba8b9Smrg noUsableXft(xw, "bold italic"); 3553d1603babSmrg XftPatternDestroy(btal->pattern); 3554d1603babSmrg btal->pattern = XftPatternDuplicate(pat); 3555d1603babSmrg XftPatternBuild(btal->pattern, 3556d4fba8b9Smrg NormXftPattern, 3557d4fba8b9Smrg (void *) 0); 3558d4fba8b9Smrg OPEN_XFT(btal, "bold-italics"); 3559d4fba8b9Smrg failed = 0; 3560d1603babSmrg CACHE_XFT(btal); 3561d4fba8b9Smrg } 3562d4fba8b9Smrg#endif 3563d522f475Smrg XftPatternDestroy(pat); 3564d4fba8b9Smrg } else { 3565d4fba8b9Smrg failed = 1; 3566d522f475Smrg } 3567d522f475Smrg 3568d522f475Smrg /* 3569d4fba8b9Smrg * See xtermXftDrawString(). A separate double-width font is nice 3570d4fba8b9Smrg * to have, but not essential. 3571d522f475Smrg */ 3572d522f475Smrg#if OPT_RENDERWIDE 3573d1603babSmrg if (XftFp(norm) != 0 && screen->wide_chars) { 3574d1603babSmrg int char_width = XftFp(norm)->max_advance_width * 2; 3575dfb07bc7Smrg double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w) 3576d1603babSmrg || screen->renderFontNorm[fontnum].font_info.mixed) 3577956cc18dSsnj ? 1.0 3578956cc18dSsnj : 2.0); 3579d522f475Smrg 358020d2c4d2Smrg face_name = getFaceName(xw, True); 3581d522f475Smrg TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 358220d2c4d2Smrg NonNull(face_name), 3583d522f475Smrg char_width)); 3584d522f475Smrg 3585d522f475Smrg#define WideXftPattern \ 3586d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3587d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size, \ 3588d4fba8b9Smrg XFT_SPACING, XftTypeInteger, XFT_MONO, \ 3589d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, char_width, \ 3590d4fba8b9Smrg FC_ASPECT, XftTypeDouble, aspect 3591d4fba8b9Smrg 3592d4fba8b9Smrg if (!IsEmpty(face_name) && (pat = XftNameParse(face_name)) 3593d4fba8b9Smrg != 0) { 3594d1603babSmrg wnorm->pattern = XftPatternDuplicate(pat); 3595d1603babSmrg XftPatternBuild(wnorm->pattern, 3596d522f475Smrg WideXftPattern, 3597d522f475Smrg (void *) 0); 3598d4fba8b9Smrg OPEN_XFT(wnorm, "wide"); 3599d522f475Smrg 3600d1603babSmrg if (XftFp(wnorm) != 0) { 3601d1603babSmrg wbold->pattern = XftPatternDuplicate(pat); 3602d1603babSmrg XftPatternBuild(wbold->pattern, 3603d522f475Smrg WideXftPattern, 3604d522f475Smrg BoldXftPattern(wnorm), 3605d522f475Smrg (void *) 0); 3606d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3607d522f475Smrg 36089a64e1c5Smrg#if HAVE_ITALICS 36099a64e1c5Smrg if (FIND_ITALICS) { 3610d1603babSmrg wital->pattern = XftPatternDuplicate(pat); 3611d1603babSmrg XftPatternBuild(wital->pattern, 3612d522f475Smrg WideXftPattern, 3613d522f475Smrg ItalXftPattern(wnorm), 3614d522f475Smrg (void *) 0); 3615d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3616d4fba8b9Smrg } 3617d1603babSmrg CACHE_XFT(wbtal); 3618d1603babSmrg if (!XftFp(wbtal)) { 3619d4fba8b9Smrg noUsableXft(xw, "wide bold"); 3620d1603babSmrg XftPatternDestroy(wbtal->pattern); 3621d1603babSmrg wbtal->pattern = XftPatternDuplicate(pat); 3622d1603babSmrg XftPatternBuild(wbtal->pattern, 3623d4fba8b9Smrg WideXftPattern, 3624d4fba8b9Smrg (void *) 0); 3625d4fba8b9Smrg OPEN_XFT(wbtal, "wide-bold-italics"); 3626d4fba8b9Smrg failed = 0; 3627d1603babSmrg CACHE_XFT(wbtal); 3628d522f475Smrg } 3629d522f475Smrg#endif 3630d522f475Smrg } 3631d4fba8b9Smrg 3632d1603babSmrg CACHE_XFT(wnorm); 3633d4fba8b9Smrg 3634d1603babSmrg CACHE_XFT(wbold); 3635d1603babSmrg if (XftFp(wnorm) != 0 && !XftFp(wbold)) { 3636d4fba8b9Smrg noUsableXft(xw, "wide-bold"); 3637d1603babSmrg XftPatternDestroy(wbold->pattern); 3638d1603babSmrg wbold->pattern = XftPatternDuplicate(pat); 3639d1603babSmrg XftPatternBuild(bold->pattern, 3640d4fba8b9Smrg WideXftPattern, 3641d4fba8b9Smrg (void *) 0); 3642d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3643d4fba8b9Smrg failed = 0; 3644d1603babSmrg CACHE_XFT(bold); 3645d4fba8b9Smrg } 3646d4fba8b9Smrg 3647d1603babSmrg CACHE_XFT(wital); 3648d1603babSmrg if (XftFp(wnorm) != 0 && !XftFp(wital)) { 3649d4fba8b9Smrg noUsableXft(xw, "wide-italic"); 3650d1603babSmrg XftPatternDestroy(wital->pattern); 3651d1603babSmrg wital->pattern = XftPatternDuplicate(pat); 3652d1603babSmrg XftPatternBuild(wital->pattern, 3653d4fba8b9Smrg WideXftPattern, 3654d4fba8b9Smrg (void *) 0); 3655d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3656d4fba8b9Smrg failed = 0; 3657d1603babSmrg CACHE_XFT(wital); 3658d4fba8b9Smrg } 3659d4fba8b9Smrg 3660d522f475Smrg XftPatternDestroy(pat); 3661d522f475Smrg } 3662d4fba8b9Smrg#undef OPEN_XFT 3663d522f475Smrg } 3664d522f475Smrg#endif /* OPT_RENDERWIDE */ 3665d522f475Smrg } 3666d1603babSmrg if (XftFp(norm) == 0) { 36672eaa94a1Schristos TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 36680bd37d32Smrg xw->work.render_font = False; 3669d522f475Smrg update_font_renderfont(); 3670d522f475Smrg /* now we will fall through into the bitmap fonts */ 3671d522f475Smrg } else { 3672d4fba8b9Smrg setBrokenBoxChars(xw, False); 3673d1603babSmrg setRenderFontsize(xw, win, norm, NULL); 3674d1603babSmrg setRenderFontsize(xw, win, bold, "bold"); 3675d1603babSmrg setRenderFontsize(xw, win, ital, "ital"); 3676d1603babSmrg setRenderFontsize(xw, win, btal, "btal"); 367720d2c4d2Smrg#if OPT_BOX_CHARS 367820d2c4d2Smrg setupPackedFonts(xw); 367920d2c4d2Smrg 368020d2c4d2Smrg if (screen->force_packed) { 368120d2c4d2Smrg XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 3682d1603babSmrg SetFontHeight(screen, win, XftFp(use)->ascent + XftFp(use)->descent); 3683d1603babSmrg SetFontWidth(screen, win, use->font_info.min_width); 368420d2c4d2Smrg TRACE(("...packed TrueType font %dx%d vs %d\n", 368520d2c4d2Smrg win->f_height, 368620d2c4d2Smrg win->f_width, 3687d1603babSmrg use->font_info.max_width)); 368820d2c4d2Smrg } 368920d2c4d2Smrg#endif 369020d2c4d2Smrg DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 3691d522f475Smrg } 3692d522f475Smrg } 3693d522f475Smrg /* 3694d522f475Smrg * Are we handling a bitmap font? 3695d522f475Smrg */ 3696492d43a5Smrg else 3697d522f475Smrg#endif /* OPT_RENDERFONT */ 3698d522f475Smrg { 369920d2c4d2Smrg if (is_double_width_font(font) && !(screen->fnt_prop)) { 37000bd37d32Smrg SetFontWidth(screen, win, font->min_bounds.width); 3701d522f475Smrg } else { 37020bd37d32Smrg SetFontWidth(screen, win, font->max_bounds.width); 3703d522f475Smrg } 37040bd37d32Smrg SetFontHeight(screen, win, font->ascent + font->descent); 3705d522f475Smrg win->f_ascent = font->ascent; 3706d522f475Smrg win->f_descent = font->descent; 3707d522f475Smrg } 3708d522f475Smrg i = 2 * screen->border + sbwidth; 3709d522f475Smrg j = 2 * screen->border; 3710d522f475Smrg width = MaxCols(screen) * win->f_width + i; 3711d522f475Smrg height = MaxRows(screen) * win->f_height + j; 3712956cc18dSsnj win->fullwidth = (Dimension) width; 3713956cc18dSsnj win->fullheight = (Dimension) height; 3714d522f475Smrg win->width = width - i; 3715d522f475Smrg win->height = height - j; 3716d522f475Smrg 3717d522f475Smrg TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 3718d522f475Smrg win->height, 3719d522f475Smrg win->width, 3720d522f475Smrg win->fullheight, 3721d522f475Smrg win->fullwidth, 3722d522f475Smrg win->f_height, 3723d522f475Smrg win->f_width, 3724d522f475Smrg win->f_ascent, 3725d522f475Smrg win->f_descent)); 372620d2c4d2Smrg 3727d4fba8b9Smrg checkFontInfo(win->f_height, "height", failed); 3728d4fba8b9Smrg checkFontInfo(win->f_width, "width", failed); 3729d522f475Smrg} 3730d522f475Smrg 3731d522f475Smrg/* save this information as a side-effect for double-sized characters */ 3732d4fba8b9Smrgstatic void 37339a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font) 3734d522f475Smrg{ 3735956cc18dSsnj screen->fnt_wide = (Dimension) (font->max_bounds.width); 3736956cc18dSsnj screen->fnt_high = (Dimension) (font->ascent + font->descent); 3737d522f475Smrg TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 3738d522f475Smrg} 3739d522f475Smrg 3740d522f475Smrg/* 3741d522f475Smrg * After loading a new font, update the structures that use its size. 3742d522f475Smrg */ 3743d522f475Smrgvoid 3744d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize) 3745d522f475Smrg{ 3746956cc18dSsnj TScreen *screen = TScreenOf(xw); 3747d522f475Smrg 3748d522f475Smrg int scrollbar_width; 3749d522f475Smrg VTwin *win = &(screen->fullVwin); 3750d522f475Smrg 3751d4fba8b9Smrg#if USE_DOUBLE_BUFFER 3752d4fba8b9Smrg discardRenderDraw(TScreenOf(xw)); 3753d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */ 3754d4fba8b9Smrg 3755d522f475Smrg scrollbar_width = (xw->misc.scrollbar 3756d522f475Smrg ? (screen->scrollWidget->core.width + 3757d522f475Smrg BorderWidth(screen->scrollWidget)) 3758d522f475Smrg : 0); 3759d4fba8b9Smrg xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width); 3760d4fba8b9Smrg xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs); 3761d522f475Smrg 3762d522f475Smrg if (doresize) { 3763d522f475Smrg if (VWindow(screen)) { 3764d522f475Smrg xtermClear(xw); 3765d522f475Smrg } 3766d4fba8b9Smrg TRACE(("xtermUpdateFontInfo " TRACE_L "\n")); 3767d522f475Smrg DoResizeScreen(xw); /* set to the new natural size */ 3768d522f475Smrg ResizeScrollBar(xw); 3769d522f475Smrg Redraw(); 3770d4fba8b9Smrg TRACE((TRACE_R " xtermUpdateFontInfo\n")); 3771d522f475Smrg#ifdef SCROLLBAR_RIGHT 3772d522f475Smrg updateRightScrollbar(xw); 3773d522f475Smrg#endif 3774d522f475Smrg } 3775d522f475Smrg xtermSetCursorBox(screen); 3776d522f475Smrg} 3777d522f475Smrg 3778fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS 3779d522f475Smrg 3780d522f475Smrg/* 3781d522f475Smrg * Returns true if the given character is missing from the specified font. 3782d522f475Smrg */ 3783d522f475SmrgBool 3784956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font) 3785d522f475Smrg{ 3786956cc18dSsnj Bool result = False; 3787956cc18dSsnj XFontStruct *fs = font->fs; 3788fa3f02f3Smrg XCharStruct *pc = 0; 3789d522f475Smrg 3790d4fba8b9Smrg if (fs == NULL) { 3791d4fba8b9Smrg result = True; 3792d4fba8b9Smrg } else if (fs->max_byte1 == 0) { 3793d522f475Smrg#if OPT_WIDE_CHARS 3794fa3f02f3Smrg if (ch < 256) 3795956cc18dSsnj#endif 3796fa3f02f3Smrg { 3797fa3f02f3Smrg CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc); 3798fa3f02f3Smrg } 3799956cc18dSsnj } 3800d522f475Smrg#if OPT_WIDE_CHARS 3801956cc18dSsnj else { 3802fa3f02f3Smrg unsigned row = (ch >> 8); 3803fa3f02f3Smrg unsigned col = (ch & 0xff); 3804fa3f02f3Smrg CI_GET_CHAR_INFO_2D(fs, row, col, pc); 3805956cc18dSsnj } 3806d522f475Smrg#endif 3807d522f475Smrg 3808fa3f02f3Smrg if (pc == 0 || CI_NONEXISTCHAR(pc)) { 3809c48a5815Smrg TRACE2(("xtermMissingChar %#04x (!exists)\n", ch)); 3810956cc18dSsnj result = True; 3811d522f475Smrg } 3812d1603babSmrg if (ch < MaxUChar) { 3813956cc18dSsnj font->known_missing[ch] = (Char) (result ? 2 : 1); 3814d522f475Smrg } 3815956cc18dSsnj return result; 3816d522f475Smrg} 3817fa3f02f3Smrg#endif 3818d522f475Smrg 3819fa3f02f3Smrg#if OPT_BOX_CHARS 3820d522f475Smrg/* 3821d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in 3822d522f475Smrg * initialization. 3823d522f475Smrg */ 3824d522f475Smrg#define BOX_HIGH 60 3825d522f475Smrg#define BOX_WIDE 60 3826d522f475Smrg 3827d522f475Smrg#define MID_HIGH (BOX_HIGH/2) 3828d522f475Smrg#define MID_WIDE (BOX_WIDE/2) 3829d522f475Smrg 3830d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10) 3831d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10) 3832d522f475Smrg 3833d522f475Smrg/* 3834d522f475Smrg * ...since we'll scale the values anyway. 3835d522f475Smrg */ 3836d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d) 3837d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width) 3838d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height) 3839e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n) 3840e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n) 3841d522f475Smrg 3842d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 3843d522f475Smrg 3844d522f475Smrg/* 3845d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a 3846d522f475Smrg * line-drawing character). 3847d522f475Smrg */ 3848d522f475Smrgvoid 3849d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params, 3850d522f475Smrg unsigned ch, 3851d522f475Smrg GC gc, 3852d522f475Smrg int x, 3853d522f475Smrg int y, 3854d4fba8b9Smrg int cells, 3855d4fba8b9Smrg Bool xftords) 3856d522f475Smrg{ 3857d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 3858d522f475Smrg /* *INDENT-OFF* */ 3859d522f475Smrg static const short glyph_ht[] = { 3860d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 3861d522f475Smrg SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 3862d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 3863d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3864d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3865d522f475Smrg -1 3866d522f475Smrg }, glyph_ff[] = { 3867d522f475Smrg SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 3868d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 3869d522f475Smrg SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 3870d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3871d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3872d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3873d522f475Smrg -1 3874d522f475Smrg }, glyph_lf[] = { 3875d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 3876d522f475Smrg SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 3877d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3878d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3879d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3880d522f475Smrg -1 3881d522f475Smrg }, glyph_nl[] = { 3882d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 3883d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 3884d522f475Smrg SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3885d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 3886d522f475Smrg SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 3887d522f475Smrg -1 3888d522f475Smrg }, glyph_vt[] = { 3889d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 3890d522f475Smrg SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3891d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3892d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3893d522f475Smrg -1 3894d522f475Smrg }, plus_or_minus[] = 3895d522f475Smrg { 3896d522f475Smrg SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 3897d522f475Smrg SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 3898d522f475Smrg SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 3899d522f475Smrg -1 3900d522f475Smrg }, lower_right_corner[] = 3901d522f475Smrg { 3902d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3903d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 3904d522f475Smrg -1 3905d522f475Smrg }, upper_right_corner[] = 3906d522f475Smrg { 3907d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3908d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3909d522f475Smrg -1 3910d522f475Smrg }, upper_left_corner[] = 3911d522f475Smrg { 3912d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3913d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3914d522f475Smrg -1 3915d522f475Smrg }, lower_left_corner[] = 3916d522f475Smrg { 3917d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3918d522f475Smrg SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 3919d522f475Smrg -1 3920d522f475Smrg }, cross[] = 3921d522f475Smrg { 3922d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3923d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3924d522f475Smrg -1 3925d522f475Smrg }, scan_line_1[] = 3926d522f475Smrg { 3927d522f475Smrg SEG( 0, 0, BOX_WIDE, 0), 3928d522f475Smrg -1 3929d522f475Smrg }, scan_line_3[] = 3930d522f475Smrg { 3931d522f475Smrg SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 3932d522f475Smrg -1 3933d522f475Smrg }, scan_line_7[] = 3934d522f475Smrg { 3935d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3936d522f475Smrg -1 3937d522f475Smrg }, scan_line_9[] = 3938d522f475Smrg { 3939d522f475Smrg SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 3940d522f475Smrg -1 3941d522f475Smrg }, horizontal_line[] = 3942d522f475Smrg { 3943d522f475Smrg SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 3944d522f475Smrg -1 3945d522f475Smrg }, left_tee[] = 3946d522f475Smrg { 3947d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3948d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3949d522f475Smrg -1 3950d522f475Smrg }, right_tee[] = 3951d522f475Smrg { 3952d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3953d522f475Smrg SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 3954d522f475Smrg -1 3955d522f475Smrg }, bottom_tee[] = 3956d522f475Smrg { 3957d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3958d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3959d522f475Smrg -1 3960d522f475Smrg }, top_tee[] = 3961d522f475Smrg { 3962d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3963d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3964d522f475Smrg -1 3965d522f475Smrg }, vertical_line[] = 3966d522f475Smrg { 3967d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3968d522f475Smrg -1 3969d522f475Smrg }, less_than_or_equal[] = 3970d522f475Smrg { 3971d522f475Smrg SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 3972d522f475Smrg SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 3973d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3974d522f475Smrg -1 3975d522f475Smrg }, greater_than_or_equal[] = 3976d522f475Smrg { 3977d522f475Smrg SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3978d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3979d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3980d522f475Smrg -1 3981d522f475Smrg }, greek_pi[] = 3982d522f475Smrg { 3983d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3984d522f475Smrg SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 3985d522f475Smrg SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 3986d522f475Smrg -1 3987d522f475Smrg }, not_equal_to[] = 3988d522f475Smrg { 3989d522f475Smrg SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 3990d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 3991d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3992d522f475Smrg -1 3993d522f475Smrg }; 3994d522f475Smrg 3995d4fba8b9Smrg static const struct { 3996d4fba8b9Smrg const int mode; /* 1=y, 2=x, 3=both */ 3997d1603babSmrg const short *const data; 3998d4fba8b9Smrg } lines[] = 3999d522f475Smrg { 4000d4fba8b9Smrg { 0, 0 }, /* 00 (unused) */ 4001d4fba8b9Smrg { 0, 0 }, /* 01 diamond */ 4002d4fba8b9Smrg { 0, 0 }, /* 02 box */ 4003d4fba8b9Smrg { 0, glyph_ht }, /* 03 HT */ 4004d4fba8b9Smrg { 0, glyph_ff }, /* 04 FF */ 4005d4fba8b9Smrg { 0, 0 }, /* 05 CR */ 4006d4fba8b9Smrg { 0, glyph_lf }, /* 06 LF */ 4007d4fba8b9Smrg { 0, 0 }, /* 07 degrees (small circle) */ 4008d4fba8b9Smrg { 3, plus_or_minus }, /* 08 */ 4009d4fba8b9Smrg { 0, glyph_nl }, /* 09 */ 4010d4fba8b9Smrg { 0, glyph_vt }, /* 0A */ 4011d4fba8b9Smrg { 3, lower_right_corner }, /* 0B */ 4012d4fba8b9Smrg { 3, upper_right_corner }, /* 0C */ 4013d4fba8b9Smrg { 3, upper_left_corner }, /* 0D */ 4014d4fba8b9Smrg { 3, lower_left_corner }, /* 0E */ 4015d4fba8b9Smrg { 3, cross }, /* 0F */ 4016d4fba8b9Smrg { 2, scan_line_1 }, /* 10 */ 4017d4fba8b9Smrg { 2, scan_line_3 }, /* 11 */ 4018d4fba8b9Smrg { 2, scan_line_7 }, /* 12 */ 4019d4fba8b9Smrg { 2, scan_line_9 }, /* 13 */ 4020d4fba8b9Smrg { 2, horizontal_line }, /* 14 */ 4021d4fba8b9Smrg { 3, left_tee }, /* 15 */ 4022d4fba8b9Smrg { 3, right_tee }, /* 16 */ 4023d4fba8b9Smrg { 3, bottom_tee }, /* 17 */ 4024d4fba8b9Smrg { 3, top_tee }, /* 18 */ 4025d4fba8b9Smrg { 1, vertical_line }, /* 19 */ 4026d4fba8b9Smrg { 0, less_than_or_equal }, /* 1A */ 4027d4fba8b9Smrg { 0, greater_than_or_equal }, /* 1B */ 4028d4fba8b9Smrg { 0, greek_pi }, /* 1C */ 4029d4fba8b9Smrg { 0, not_equal_to }, /* 1D */ 4030d4fba8b9Smrg { 0, 0 }, /* 1E LB */ 4031d4fba8b9Smrg { 0, 0 }, /* 1F bullet */ 4032d522f475Smrg }; 4033d4fba8b9Smrg /* *INDENT-ON* */ 4034d522f475Smrg 4035d522f475Smrg GC gc2; 4036d522f475Smrg CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 4037d522f475Smrg VTwin *cgsWin = WhichVWin(screen); 4038d522f475Smrg const short *p; 4039d4fba8b9Smrg unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U) 4040d4fba8b9Smrg * screen->fnt_wide); 4041d4fba8b9Smrg unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U) 4042d4fba8b9Smrg * screen->fnt_high); 4043d1603babSmrg unsigned thick; 4044d522f475Smrg 4045d522f475Smrg if (cells > 1) 4046956cc18dSsnj font_width *= (unsigned) cells; 4047d522f475Smrg 4048d522f475Smrg#if OPT_WIDE_CHARS 4049d522f475Smrg /* 4050d522f475Smrg * Try to show line-drawing characters if we happen to be in UTF-8 4051d522f475Smrg * mode, but have gotten an old-style font. 4052d522f475Smrg */ 4053d522f475Smrg if (screen->utf8_mode 4054d522f475Smrg#if OPT_RENDERFONT 4055d4fba8b9Smrg && !UsingRenderFont(params->xw) 4056d522f475Smrg#endif 4057d522f475Smrg && (ch > 127) 4058d522f475Smrg && (ch != UCS_REPL)) { 4059d4fba8b9Smrg int which = (params->attr_flags & BOLD) ? fBold : fNorm; 4060d522f475Smrg unsigned n; 4061d522f475Smrg for (n = 1; n < 32; n++) { 4062d4fba8b9Smrg if (xtermMissingChar(n, getNormalFont(screen, which))) 4063d4fba8b9Smrg continue; 4064d4fba8b9Smrg if (dec2ucs(screen, n) != ch) 4065d4fba8b9Smrg continue; 4066d4fba8b9Smrg TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n)); 4067d4fba8b9Smrg ch = n; 4068d4fba8b9Smrg break; 4069d522f475Smrg } 4070d522f475Smrg } 4071d522f475Smrg#endif 4072d522f475Smrg 4073d4fba8b9Smrg#if OPT_VT52_MODE 4074d4fba8b9Smrg if (!(screen->vtXX_level)) { 4075d4fba8b9Smrg switch (ch) { 4076d4fba8b9Smrg case 6: 4077d4fba8b9Smrg ch = 7; 4078d4fba8b9Smrg break; 4079d4fba8b9Smrg default: 4080d4fba8b9Smrg ch = 256; 4081d4fba8b9Smrg break; 4082d4fba8b9Smrg } 4083d4fba8b9Smrg } 4084d4fba8b9Smrg#endif 4085d4fba8b9Smrg 4086d4fba8b9Smrg /* 4087d4fba8b9Smrg * Line-drawing characters show use the full (scaled) cellsize, while 4088d4fba8b9Smrg * other characters should be shifted to center them vertically. 4089d4fba8b9Smrg */ 4090d4fba8b9Smrg if (!xftords) { 4091d4fba8b9Smrg if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) { 4092d4fba8b9Smrg font_height = (unsigned) ((float) font_height * screen->scale_height); 4093d4fba8b9Smrg } else { 4094d4fba8b9Smrg y += ScaleShift(screen); 4095d4fba8b9Smrg } 4096d4fba8b9Smrg } 4097d4fba8b9Smrg 4098d4fba8b9Smrg TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n", 4099d522f475Smrg ch, font_height, font_width, y, x, 4100d4fba8b9Smrg ((ch >= XtNumber(lines)) 4101d522f475Smrg ? "-BAD" 4102d522f475Smrg : ""))); 4103d522f475Smrg 4104d522f475Smrg if (cgsId == gcDots) { 4105d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4106d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 4107d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4108d522f475Smrg } else { 4109d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4110d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4111d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4112d522f475Smrg } 4113d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 4114d522f475Smrg 4115d4fba8b9Smrg if (!(params->draw_flags & NOBACKGROUND)) { 41160bd37d32Smrg XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 4117d522f475Smrg font_width, 4118d522f475Smrg font_height); 4119d522f475Smrg } 4120d522f475Smrg 4121d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4122d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 4123d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4124d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 4125d522f475Smrg 4126d1603babSmrg thick = ((params->attr_flags & BOLD) 4127d1603babSmrg ? (Max((unsigned) screen->fnt_high / 12, 1)) 4128d1603babSmrg : (Max((unsigned) screen->fnt_high / 16, 1))), 4129d1603babSmrg XSetLineAttributes(screen->display, gc2, 4130d1603babSmrg thick, 4131d1603babSmrg ((ch < XtNumber(lines)) 4132d1603babSmrg ? LineSolid 4133d1603babSmrg : LineOnOffDash), /* like xtermDrawMissing */ 4134d1603babSmrg CapProjecting, 4135d1603babSmrg JoinMiter); 4136d522f475Smrg 4137d522f475Smrg if (ch == 1) { /* diamond */ 4138d522f475Smrg XPoint points[5]; 4139d522f475Smrg int npoints = 5, n; 4140d522f475Smrg 4141d522f475Smrg points[0].x = MID_WIDE; 4142d522f475Smrg points[0].y = BOX_HIGH / 4; 4143d522f475Smrg 4144d522f475Smrg points[1].x = 8 * BOX_WIDE / 8; 4145d522f475Smrg points[1].y = MID_HIGH; 4146d522f475Smrg 4147d522f475Smrg points[2].x = points[0].x; 4148d522f475Smrg points[2].y = 3 * BOX_HIGH / 4; 4149d522f475Smrg 4150d522f475Smrg points[3].x = 0 * BOX_WIDE / 8; 4151d522f475Smrg points[3].y = points[1].y; 4152d522f475Smrg 4153d522f475Smrg points[4].x = points[0].x; 4154d522f475Smrg points[4].y = points[0].y; 4155d522f475Smrg 4156d522f475Smrg for (n = 0; n < npoints; ++n) { 4157d4fba8b9Smrg points[n].x = (short) (SCALED_X(points[n].x)); 4158d4fba8b9Smrg points[n].y = (short) (SCALED_Y(points[n].y)); 4159e39b573cSmrg points[n].x = (short) (points[n].x + x); 4160e39b573cSmrg points[n].y = (short) (points[n].y + y); 4161d522f475Smrg } 4162d522f475Smrg 4163d522f475Smrg XFillPolygon(screen->display, 41640bd37d32Smrg VDrawable(screen), gc2, 4165d522f475Smrg points, npoints, 4166d522f475Smrg Convex, CoordModeOrigin); 4167d522f475Smrg } else if (ch == 7) { /* degrees */ 4168d522f475Smrg unsigned width = (BOX_WIDE / 3); 4169956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 2); 4170956cc18dSsnj int y_coord = MID_HIGH - (int) width; 4171d522f475Smrg 4172d522f475Smrg SCALE_X(x_coord); 4173d522f475Smrg SCALE_Y(y_coord); 4174e39b573cSmrg width = (unsigned) SCALED_X(width); 4175d522f475Smrg 4176d522f475Smrg XDrawArc(screen->display, 41770bd37d32Smrg VDrawable(screen), gc2, 4178d522f475Smrg x + x_coord, y + y_coord, width, width, 4179d522f475Smrg 0, 4180d522f475Smrg 360 * 64); 4181d522f475Smrg } else if (ch == 0x1f) { /* bullet */ 4182d522f475Smrg unsigned width = 7 * BOX_WIDE / 10; 4183956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 3); 4184956cc18dSsnj int y_coord = MID_HIGH - (int) (width / 3); 4185d522f475Smrg 4186d522f475Smrg SCALE_X(x_coord); 4187d522f475Smrg SCALE_Y(y_coord); 4188e39b573cSmrg width = (unsigned) SCALED_X(width); 4189d522f475Smrg 4190d522f475Smrg XDrawArc(screen->display, 41910bd37d32Smrg VDrawable(screen), gc2, 4192d522f475Smrg x + x_coord, y + y_coord, width, width, 4193d522f475Smrg 0, 4194d522f475Smrg 360 * 64); 4195d4fba8b9Smrg } else if (ch < XtNumber(lines) 4196d4fba8b9Smrg && (p = lines[ch].data) != 0) { 4197956cc18dSsnj int coord[4]; 4198d522f475Smrg int n = 0; 4199d522f475Smrg while (*p >= 0) { 4200d522f475Smrg coord[n++] = *p++; 4201d522f475Smrg if (n == 4) { 4202d522f475Smrg SCALE_X(coord[0]); 4203d522f475Smrg SCALE_Y(coord[1]); 4204d522f475Smrg SCALE_X(coord[2]); 4205d522f475Smrg SCALE_Y(coord[3]); 4206d522f475Smrg XDrawLine(screen->display, 42070bd37d32Smrg VDrawable(screen), gc2, 4208d522f475Smrg x + coord[0], y + coord[1], 4209d522f475Smrg x + coord[2], y + coord[3]); 4210d522f475Smrg n = 0; 4211d522f475Smrg } 4212d522f475Smrg } 4213d522f475Smrg } else if (screen->force_all_chars) { 4214d522f475Smrg /* bounding rectangle, for debugging */ 4215d1603babSmrg if ((params->draw_flags & DOUBLEHFONT)) { 4216d1603babSmrg XRectangle clip; 4217d1603babSmrg 4218d1603babSmrg clip.x = 0; 4219d1603babSmrg clip.y = 0; 4220d1603babSmrg clip.width = (unsigned short) ((font_width - 1) + (unsigned) thick); 4221d1603babSmrg clip.height = (unsigned short) ((unsigned) FontHeight(screen) + thick); 4222d1603babSmrg 4223d1603babSmrg if ((params->draw_flags & DOUBLEFIRST)) { 4224d1603babSmrg y -= (2 * FontDescent(screen)); 4225d1603babSmrg clip.height = 4226d1603babSmrg (unsigned short) (clip.height 4227d1603babSmrg - ((unsigned short) FontDescent(screen))); 4228d1603babSmrg } else { 4229d1603babSmrg y -= FontHeight(screen); 4230d1603babSmrg y += FontDescent(screen); 4231d1603babSmrg clip.y = (short) FontHeight(screen); 4232d1603babSmrg } 4233d1603babSmrg XSetClipRectangles(screen->display, gc2, x, y, &clip, 1, Unsorted); 4234d1603babSmrg } 4235d1603babSmrg XDrawRectangle(screen->display, VDrawable(screen), gc2, 4236d1603babSmrg x + (int) thick, y + (int) thick, 4237d1603babSmrg font_width - (2 * thick), 4238d1603babSmrg font_height - (2 * thick)); 4239d1603babSmrg if ((params->draw_flags & DOUBLEHFONT)) { 4240d1603babSmrg XSetClipMask(screen->display, gc2, None); 4241d1603babSmrg } 4242d522f475Smrg } 4243d522f475Smrg} 4244fa3f02f3Smrg#endif /* OPT_BOX_CHARS */ 4245d522f475Smrg 4246d522f475Smrg#if OPT_RENDERFONT 4247d1603babSmrgstatic int 4248d1603babSmrgcheckXftGlyph(XtermWidget xw, XftFont *font, unsigned wc) 4249d1603babSmrg{ 4250d1603babSmrg TScreen *screen = TScreenOf(xw); 4251d1603babSmrg int result = 0; 4252d1603babSmrg int expect; 4253d1603babSmrg 4254d1603babSmrg if ((expect = CharWidth(screen, wc)) > 0) { 4255d1603babSmrg XGlyphInfo gi; 4256d1603babSmrg int actual; 4257d1603babSmrg int limit = (100 + xw->misc.limit_fontwidth); 4258d1603babSmrg 4259d1603babSmrg XftTextExtents32(screen->display, font, &wc, 1, &gi); 4260d1603babSmrg /* 4261d1603babSmrg * Some (more than a few) fonts are sloppy; allow 10% outside 4262d1603babSmrg * the bounding box to accommodate them. 4263d1603babSmrg */ 4264d1603babSmrg actual = ((gi.xOff * 100) >= (limit * FontWidth(screen))) ? 2 : 1; 4265d1603babSmrg if (actual <= expect) { 4266d1603babSmrg /* allow double-cell if wcwidth agrees */ 4267d1603babSmrg result = 1; 4268d1603babSmrg } else { 4269d1603babSmrg /* 4270d1603babSmrg * Do not use this font for this specific character, but 4271d1603babSmrg * possibly other characters can be used. 4272d1603babSmrg */ 4273d1603babSmrg result = -1; 4274d1603babSmrg TRACE(("SKIP U+%04X %d vs %d (%d vs %d) %s\n", 4275d1603babSmrg wc, gi.xOff, FontWidth(screen), actual, expect, 4276d1603babSmrg nameOfXftFont(font))); 4277d1603babSmrg } 4278d1603babSmrg } else { 4279d1603babSmrg result = 1; 4280d1603babSmrg } 4281d1603babSmrg return result; 4282d1603babSmrg} 4283d1603babSmrg 4284d4fba8b9Smrg/* 4285d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out 4286d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline. 4287d4fba8b9Smrg */ 4288d1603babSmrgstatic int 4289d1603babSmrgfoundXftGlyph(XtermWidget xw, XTermXftFonts *data, int fontNum, unsigned wc) 4290d4fba8b9Smrg{ 4291d1603babSmrg XftFont *font = XftFpN(data, fontNum); 4292d1603babSmrg int result = 0; 4293d4fba8b9Smrg 4294d1603babSmrg if (font != 0) { 4295d1603babSmrg if (!xtermXftMissing(xw, data, fontNum, font, wc)) { 4296d4fba8b9Smrg 4297d1603babSmrg if (XftIsN(data, fontNum) == xcBogus) { 4298d1603babSmrg ; 4299d1603babSmrg } else if (XftIsN(data, fontNum) == xcOpened) { 4300d1603babSmrg result = 1; 4301d4fba8b9Smrg } else { 4302d1603babSmrg result = checkXftGlyph(xw, font, wc); 4303d4fba8b9Smrg } 4304d4fba8b9Smrg } 4305d4fba8b9Smrg } 4306d4fba8b9Smrg return result; 4307d4fba8b9Smrg} 4308d4fba8b9Smrg 4309d4fba8b9Smrgstatic void 4310d1603babSmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, int n, unsigned wc) 4311d4fba8b9Smrg{ 4312d1603babSmrg if (XftIsN(which, n) != xcOpened) { 4313d4fba8b9Smrg which->opened++; 4314d1603babSmrg XftIsN(which, n) = xcOpened; 4315d4fba8b9Smrg /* XFT_DEBUG=3 will show useful context for this */ 4316d4fba8b9Smrg if (getenv("XFT_DEBUG") != 0) { 4317d1603babSmrg printf("%s: matched U+%04X in fontset #%d [%u:%u]\n", 4318d1603babSmrg ProgramName, 4319d4fba8b9Smrg wc, n + 1, 4320d4fba8b9Smrg which->opened, 4321d4fba8b9Smrg xw->work.max_fontsets); 4322d4fba8b9Smrg } 4323d4fba8b9Smrg } 4324d4fba8b9Smrg} 4325d4fba8b9Smrg 4326d1603babSmrgstatic char ** 4327d1603babSmrgxftData2List(XtermWidget xw, XTermXftFonts *fontData) 4328d1603babSmrg{ 4329d1603babSmrg TScreen *screen = TScreenOf(xw); 4330d1603babSmrg VTFontList *lists = &xw->work.fonts.xft; 4331d1603babSmrg char **result = NULL; 4332d1603babSmrg int n = screen->menu_font_number; 4333d1603babSmrg 4334d1603babSmrg if (fontData == &screen->renderFontNorm[n]) 4335d1603babSmrg result = lists->list_n; 4336d1603babSmrg else if (fontData == &screen->renderFontBold[n]) 4337d1603babSmrg result = lists->list_b; 4338d1603babSmrg else if (fontData == &screen->renderFontItal[n]) 4339d1603babSmrg result = lists->list_i; 4340d1603babSmrg else if (fontData == &screen->renderFontBtal[n]) 4341d1603babSmrg result = lists->list_bi; 4342d1603babSmrg#if OPT_RENDERWIDE 4343d1603babSmrg if (fontData == &screen->renderWideNorm[n]) 4344d1603babSmrg result = lists->list_w; 4345d1603babSmrg else if (fontData == &screen->renderWideBold[n]) 4346d1603babSmrg result = lists->list_wb; 4347d1603babSmrg else if (fontData == &screen->renderWideItal[n]) 4348d1603babSmrg result = lists->list_wi; 4349d1603babSmrg else if (fontData == &screen->renderWideBtal[n]) 4350d1603babSmrg result = lists->list_wbi; 4351d1603babSmrg#endif 4352d1603babSmrg return result; 4353d1603babSmrg} 4354d1603babSmrg 4355d1603babSmrgstatic FcPattern * 4356d1603babSmrgmergeXftStyle(XtermWidget xw, FcPattern * myPattern, XTermXftFonts *fontData) 4357d1603babSmrg{ 4358d1603babSmrg TScreen *screen = TScreenOf(xw); 4359d1603babSmrg Display *dpy = screen->display; 4360d1603babSmrg XftFont *given = XftFp(fontData); 4361d1603babSmrg XftResult mStatus; 4362d1603babSmrg int iValue; 4363d1603babSmrg double dValue; 4364d1603babSmrg 4365d1603babSmrg if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_WEIGHT, 0, &iValue))) { 4366d1603babSmrg FcPatternAddInteger(myPattern, XFT_WEIGHT, iValue); 4367d1603babSmrg } 4368d1603babSmrg if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_SLANT, 0, &iValue))) { 4369d1603babSmrg FcPatternAddInteger(myPattern, XFT_SLANT, iValue); 4370d1603babSmrg } 4371d1603babSmrg if (FcOK(FcPatternGetDouble(fontData->pattern, FC_ASPECT, 0, &dValue))) { 4372d1603babSmrg FcPatternAddDouble(myPattern, FC_ASPECT, dValue); 4373d1603babSmrg } 4374d1603babSmrg if (FcOK(FcPatternGetDouble(fontData->pattern, XFT_SIZE, 0, &dValue))) { 4375d1603babSmrg FcPatternAddDouble(myPattern, XFT_SIZE, dValue); 4376d1603babSmrg } 4377d1603babSmrg FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4378d1603babSmrg FcPatternAddInteger(myPattern, XFT_SPACING, XFT_MONO); 4379d1603babSmrg FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4380d1603babSmrg#ifdef FC_COLOR 4381d1603babSmrg#if !USE_FC_COLOR 4382d1603babSmrg FcPatternAddBool(myPattern, FC_COLOR, FcFalse); 4383d1603babSmrg#endif 4384d1603babSmrg FcPatternAddBool(myPattern, FC_OUTLINE, FcTrue); 4385d1603babSmrg#endif 4386d1603babSmrg 4387d1603babSmrg FcConfigSubstitute(NULL, myPattern, FcMatchPattern); 4388d1603babSmrg XftDefaultSubstitute(dpy, DefaultScreen(dpy), myPattern); 4389d1603babSmrg 4390d1603babSmrg return FcFontMatch(NULL, myPattern, &mStatus); 4391d1603babSmrg} 4392d1603babSmrg 4393d4fba8b9Smrg/* 4394d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4395d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph. 4396d1603babSmrg * 4397d1603babSmrg * Return -1 if nothing is found. Otherwise, return the index in the cache. 4398d4fba8b9Smrg */ 4399d1603babSmrgint 4400d1603babSmrgfindXftGlyph(XtermWidget xw, XTermXftFonts *fontData, unsigned wc) 4401d4fba8b9Smrg{ 4402d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4403d1603babSmrg XftFont *given; 4404d1603babSmrg XftFont *actual = NULL; 4405d4fba8b9Smrg FcResult status; 4406d1603babSmrg int n; 4407d1603babSmrg int result = -1; 4408d1603babSmrg 4409d1603babSmrg /* sanity-check */ 4410d1603babSmrg if (fontData == NULL) 4411d1603babSmrg return result; 4412d1603babSmrg given = XftFp(fontData); 4413d4fba8b9Smrg 4414d4fba8b9Smrg /* if fontsets are not wanted, just leave */ 4415d4fba8b9Smrg if (xw->work.max_fontsets == 0) { 4416d1603babSmrg return result; 4417d4fba8b9Smrg } 4418d4fba8b9Smrg 4419d4fba8b9Smrg /* ignore codes in private use areas */ 4420d4fba8b9Smrg if ((wc >= 0xe000 && wc <= 0xf8ff) 4421d4fba8b9Smrg || (wc >= 0xf0000 && wc <= 0xffffd) 4422d4fba8b9Smrg || (wc >= 0x100000 && wc <= 0x10fffd)) { 4423d1603babSmrg return result; 4424d4fba8b9Smrg } 4425d4fba8b9Smrg /* the end of the BMP is reserved for non-characters */ 4426d4fba8b9Smrg if (wc >= 0xfff0 && wc <= 0xffff) { 4427d1603babSmrg return result; 4428d4fba8b9Smrg } 4429d4fba8b9Smrg 4430d1603babSmrg /* initialize on the first call */ 4431d1603babSmrg if (fontData->fontset == NULL && fontData->pattern != NULL) { 4432d1603babSmrg FcFontSet *sortedFonts; 4433d1603babSmrg FcPattern *myPattern; 4434d1603babSmrg int j; 4435d1603babSmrg char **my_list; 4436d4fba8b9Smrg 4437d1603babSmrg myPattern = FcPatternDuplicate(fontData->pattern); 4438d4fba8b9Smrg 4439d1603babSmrg FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4440d1603babSmrg FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4441d4fba8b9Smrg 4442d1603babSmrg FcConfigSubstitute(FcConfigGetCurrent(), 4443d1603babSmrg myPattern, 4444d1603babSmrg FcMatchPattern); 4445d1603babSmrg FcDefaultSubstitute(myPattern); 4446d4fba8b9Smrg 4447d1603babSmrg sortedFonts = FcFontSort(NULL, myPattern, FcTrue, NULL, &status); 4448d4fba8b9Smrg 4449d1603babSmrg fontData->fontset = FcFontSetCreate(); 4450d4fba8b9Smrg 4451d1603babSmrg if (fontData->fontset == 0 || !sortedFonts || sortedFonts->nfont <= 0) { 4452d1603babSmrg xtermWarning("did not find any usable TrueType font\n"); 4453d1603babSmrg return 0; 4454d1603babSmrg } 4455d1603babSmrg 4456d1603babSmrg /* 4457d1603babSmrg * Check if there are additional fonts in the XtermFontNames.xft for 4458d1603babSmrg * this font-data. 4459d1603babSmrg */ 4460d1603babSmrg if ((my_list = xftData2List(xw, fontData)) != NULL 4461d1603babSmrg && *++my_list != NULL) { 4462d1603babSmrg for (j = 0; my_list[j] != NULL; ++j) { 4463d1603babSmrg FcPattern *extraPattern; 4464d1603babSmrg if ((extraPattern = XftNameParse(my_list[j])) != 0) { 4465d1603babSmrg FcPattern *match; 4466d1603babSmrg 4467d1603babSmrg match = mergeXftStyle(xw, extraPattern, fontData); 4468d1603babSmrg 4469d1603babSmrg if (match != NULL) { 4470d1603babSmrg FcFontSetAdd(fontData->fontset, match); 4471d1603babSmrg } 4472d1603babSmrg FcPatternDestroy(extraPattern); 4473d1603babSmrg } 4474d4fba8b9Smrg } 4475d1603babSmrg } 4476d1603babSmrg 4477d1603babSmrg for (j = 0; j < sortedFonts->nfont; j++) { 4478d1603babSmrg FcPattern *font_pattern; 4479d4fba8b9Smrg 4480d1603babSmrg font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(), 4481d1603babSmrg myPattern, 4482d1603babSmrg sortedFonts->fonts[j]); 4483d1603babSmrg if (font_pattern) { 4484d1603babSmrg FcFontSetAdd(fontData->fontset, font_pattern); 4485d1603babSmrg } 4486d4fba8b9Smrg } 4487d1603babSmrg 4488d1603babSmrg FcFontSetSortDestroy(sortedFonts); 4489d1603babSmrg FcPatternDestroy(myPattern); 4490d1603babSmrg 4491d1603babSmrg fontData->fs_size = Min(MaxXftCache, fontData->fontset->nfont); 4492d1603babSmrg } 4493d1603babSmrg if (fontData->fontset != NULL && fontData->fs_size > 0) { 4494d1603babSmrg XftFont *check; 4495d1603babSmrg int empty = fontData->fs_size; 4496d1603babSmrg 4497d1603babSmrg for (n = 1; n <= fontData->fs_size; ++n) { 4498d1603babSmrg XTermXftState usage = XftIsN(fontData, n); 4499d1603babSmrg if (usage == xcEmpty) { 4500d1603babSmrg if (empty > n) 4501d1603babSmrg empty = n; 4502d1603babSmrg } else if (usage == xcOpened 4503d1603babSmrg || (usage == xcUnused 4504d1603babSmrg && (fontData->opened < xw->work.max_fontsets))) { 4505d1603babSmrg check = XftFpN(fontData, n); 4506d1603babSmrg if (foundXftGlyph(xw, fontData, (int) n, wc)) { 4507d1603babSmrg markXftOpened(xw, fontData, n, wc); 4508d1603babSmrg actual = check; 4509d1603babSmrg result = (int) n; 4510d1603babSmrg TRACE_FALLBACK(xw, "old", wc, result, actual); 4511d1603babSmrg break; 4512d4fba8b9Smrg } 4513d4fba8b9Smrg } 4514d1603babSmrg } 4515d4fba8b9Smrg 4516d1603babSmrg if ((actual == NULL) 4517d1603babSmrg && (empty <= fontData->fs_size) 4518d1603babSmrg && (fontData->opened < xw->work.max_fontsets)) { 4519d1603babSmrg FcPattern *myPattern = NULL; 4520d1603babSmrg FcPattern *myReport = NULL; 4521d1603babSmrg int defer = -1; 4522d1603babSmrg 4523d1603babSmrg if (empty == 0) /* should not happen */ 4524d1603babSmrg empty++; 4525d1603babSmrg 4526d1603babSmrg for (n = empty; n <= fontData->fs_size; ++n) { 4527d1603babSmrg int found; 4528d1603babSmrg int nn = n - 1; 4529d1603babSmrg 4530d1603babSmrg if (XftIsN(fontData, n) != xcEmpty) { 4531d1603babSmrg continue; 4532d1603babSmrg } 4533d1603babSmrg if (resource.reportFonts) { 4534d1603babSmrg if (myReport != NULL) 4535d1603babSmrg FcPatternDestroy(myReport); 4536d1603babSmrg myReport = FcPatternDuplicate(fontData->fontset->fonts[nn]); 4537d1603babSmrg } 4538d1603babSmrg myPattern = FcPatternDuplicate(fontData->fontset->fonts[nn]); 4539d1603babSmrg check = XftFontOpenPattern(screen->display, myPattern); 4540d1603babSmrg (void) maybeXftCache(xw, check); 4541d1603babSmrg XftFpN(fontData, n) = check; 4542d1603babSmrg if (check == NULL) { 4543d1603babSmrg ; /* shouldn't happen... */ 4544d1603babSmrg } else 4545d4fba8b9Smrg#ifdef FC_COLOR 4546d1603babSmrg if (isBogusXft(check)) { 4547d1603babSmrg XftIsN(fontData, n) = xcBogus; 4548d1603babSmrg } else 4549d4fba8b9Smrg#endif 4550d1603babSmrg if ((found = foundXftGlyph(xw, fontData, (int) n, wc)) 4551d1603babSmrg != 0) { 4552d1603babSmrg markXftOpened(xw, fontData, n, wc); 4553d1603babSmrg reportXftFallbackFont(xw, fontData, (int) n, check, myReport); 4554d1603babSmrg if (found < 0) { 4555d1603babSmrg if (defer < 0) { 4556d1603babSmrg defer = (int) n; 4557d1603babSmrg TRACE(("Deferring font choice #%d\n", n + 1)); 4558d1603babSmrg continue; 4559d1603babSmrg } else if (slowXftMissing(xw, check, wc)) { 4560d1603babSmrg TRACE(("Deferred, continuing #%d\n", n + 1)); 4561d1603babSmrg continue; 4562d1603babSmrg } 4563d1603babSmrg } else if (defer >= 0) { 4564d1603babSmrg defer = -1; 4565d1603babSmrg TRACE(("Deferred, replacing %d with %d\n", 4566d1603babSmrg defer + 1, n + 1)); 4567d1603babSmrg } 4568d1603babSmrg actual = check; 4569d1603babSmrg result = (int) n; 4570d1603babSmrg TRACE_FALLBACK(xw, "new", wc, result, actual); 4571d1603babSmrg break; 4572d1603babSmrg } else { 4573d1603babSmrg Bool ok; 4574d1603babSmrg if (defer >= 0 4575d1603babSmrg && (ok = !slowXftMissing(xw, check, wc)) 4576d1603babSmrg && checkXftGlyph(xw, check, wc)) { 4577d1603babSmrg XTermFontMap *font_map = &(fontData->font_map); 4578d1603babSmrg TRACE(("checkrecover2 %d\n", n)); 4579d1603babSmrg markXftOpened(xw, fontData, n, wc); 4580d1603babSmrg reportXftFallbackFont(xw, fontData, (int) n, check, myReport); 4581d1603babSmrg actual = check; 4582d1603babSmrg result = (int) n; 4583d1603babSmrg TRACE_FALLBACK(xw, "fix", wc, result, actual); 4584d1603babSmrg font_map->per_font[wc] = (XTfontNum) (result + 1); 4585d4fba8b9Smrg break; 4586d1603babSmrg } else { 4587d1603babSmrg /* 4588d1603babSmrg * The slot is opened, but we are not using it yet. 4589d1603babSmrg */ 4590d1603babSmrg XftIsN(fontData, n) = xcUnused; 4591d4fba8b9Smrg } 4592d4fba8b9Smrg } 4593d4fba8b9Smrg } 4594d1603babSmrg if (myReport != NULL) 4595d1603babSmrg FcPatternDestroy(myReport); 4596d4fba8b9Smrg } 4597d4fba8b9Smrg } 4598d4fba8b9Smrg return result; 4599d4fba8b9Smrg} 4600d522f475Smrg 4601d522f475Smrg/* 4602d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4603d4fba8b9Smrg * return true. 4604d522f475Smrg * 4605d522f475Smrg * see xc/lib/Xft/xftglyphs.c 4606d522f475Smrg */ 4607d522f475SmrgBool 4608d1603babSmrgxtermXftMissing(XtermWidget xw, 4609d1603babSmrg XTermXftFonts *data, 4610d1603babSmrg int fontNum, /* 0=primary, 1+ is fallback */ 4611d1603babSmrg XftFont *font, /* actual font if no data */ 4612d1603babSmrg unsigned wc) 4613d522f475Smrg{ 4614d1603babSmrg Bool result = True; 4615d522f475Smrg 4616d1603babSmrg (void) xw; 4617d1603babSmrg if (data != NULL && font != NULL) { 4618d1603babSmrg XTermFontMap *font_map = &(data->font_map); 4619d1603babSmrg /* 4620d1603babSmrg * Each fallback font has one chance to be scanned/cached. 4621d1603babSmrg * We record in per_font[] the index of the first font containing a 4622d1603babSmrg * given glyph. 4623d1603babSmrg */ 4624d1603babSmrg if (font_map->depth <= fontNum) { 4625d1603babSmrg FcChar32 last = (xtermXftLastChar(font) | 255) + 1; 4626d1603babSmrg FcChar32 base; 4627d1603babSmrg FcChar32 nextPage; 4628d1603babSmrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 4629d1603babSmrg unsigned added = 0; 4630d1603babSmrg unsigned actual = 0; 4631d1603babSmrg 4632d1603babSmrg font_map->depth = (fontNum + 1); 4633d1603babSmrg /* allocate space */ 4634d1603babSmrg if (last > font_map->last_char) { 4635d1603babSmrg size_t need = (last * sizeof(XTfontNum)); 4636d1603babSmrg size_t c1st = (font_map->last_char * sizeof(XTfontNum)); 4637d1603babSmrg font_map->per_font = realloc(font_map->per_font, need); 4638d1603babSmrg memset(font_map->per_font + font_map->last_char, 0, (need - c1st)); 4639d1603babSmrg font_map->last_char = last; 4640d1603babSmrg } 4641d1603babSmrg 4642d1603babSmrg /* scan new font */ 4643d1603babSmrg base = FcCharSetFirstPage(font->charset, map, &nextPage); 4644d1603babSmrg do { 4645d1603babSmrg unsigned row; 4646d1603babSmrg unsigned col; 4647d1603babSmrg FcChar32 bits; 4648d1603babSmrg for (row = 0; row < FC_CHARSET_MAP_SIZE; ++row) { 4649d1603babSmrg bits = map[row]; 4650d1603babSmrg for (col = 0; col < 32; ++col) { 4651d1603babSmrg if ((bits & 1) != 0) { 4652d1603babSmrg actual++; 4653d1603babSmrg if (!font_map->per_font[base]) { 4654d1603babSmrg font_map->per_font[base] = (Char) font_map->depth; 4655d1603babSmrg ++added; 4656d1603babSmrg } 4657d1603babSmrg } 4658d1603babSmrg bits >>= 1; 4659d1603babSmrg ++base; 4660d1603babSmrg } 4661d1603babSmrg } 4662d1603babSmrg } while ((base = FcCharSetNextPage(font->charset, map, 4663d1603babSmrg &nextPage)) != FC_CHARSET_DONE); 4664d1603babSmrg (void) added; 4665d1603babSmrg (void) actual; 4666d1603babSmrg TRACE(("xtermXftMissing U+%04X #%-3d %6u added vs %6u of %6ld %s: %s\n", 4667d1603babSmrg wc, 4668d1603babSmrg font_map->depth, 4669d1603babSmrg added, actual, 4670d1603babSmrg font_map->last_char + 1, 4671d1603babSmrg whichXftFonts(xw, data), 4672d1603babSmrg nameOfXftFont(font))); 4673d1603babSmrg } 4674d1603babSmrg if (wc < font_map->last_char) { 4675d1603babSmrg result = (font_map->per_font[wc] != (fontNum + 1)); 4676d522f475Smrg } 4677d522f475Smrg } 4678d522f475Smrg return result; 4679d522f475Smrg} 4680fa3f02f3Smrg#endif /* OPT_RENDERFONT */ 4681d522f475Smrg 4682d522f475Smrg#if OPT_WIDE_CHARS 4683d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break 4684d522f475Smrgunsigned 4685d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch) 4686d522f475Smrg{ 4687d522f475Smrg unsigned result = ch; 4688d4fba8b9Smrg 4689d4fba8b9Smrg (void) screen; 4690d522f475Smrg if ((ch > 127) 4691d522f475Smrg && (ch != UCS_REPL)) { 4692d4fba8b9Smrg#if OPT_VT52_MODE 4693d4fba8b9Smrg if (screen != 0 && !(screen->vtXX_level)) { 4694d4fba8b9Smrg /* 4695d4fba8b9Smrg * Intentionally empty: it would be possible to use the built-in 4696d4fba8b9Smrg * line-drawing fallback in xtermDrawBoxChar(), but for testing 4697d4fba8b9Smrg * ncurses, this is good enough. 4698d4fba8b9Smrg */ 4699d4fba8b9Smrg ; 4700d4fba8b9Smrg } else 4701d4fba8b9Smrg#endif 4702d4fba8b9Smrg switch (ch) { 4703d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4704d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4705d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4706d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4707d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4708d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4709d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4710d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4711d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4712d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4713d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4714d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4715d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4716d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4717d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4718d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4719d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4720d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4721d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4722d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4723d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4724d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4725d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4726d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4727d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4728d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4729d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4730d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4731d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4732d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4733d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4734d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4735d4fba8b9Smrg } 4736d522f475Smrg } 4737d522f475Smrg return result; 4738d522f475Smrg} 4739d522f475Smrg 4740d522f475Smrg#undef MY_UCS 4741d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break 4742d522f475Smrg 4743d522f475Smrgunsigned 4744d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch) 4745d522f475Smrg{ 4746d522f475Smrg unsigned result = ch; 4747d4fba8b9Smrg 4748d4fba8b9Smrg (void) screen; 4749d522f475Smrg if (xtermIsDecGraphic(ch)) { 4750d4fba8b9Smrg#if OPT_VT52_MODE 4751d4fba8b9Smrg if (screen != 0 && !(screen->vtXX_level)) { 4752d4fba8b9Smrg switch (ch) { 4753d4fba8b9Smrg MY_UCS(0x0020, 0); /* nbsp, treat as blank */ 4754d4fba8b9Smrg MY_UCS(0x0020, 1); /* reserved, treat as blank */ 4755d4fba8b9Smrg MY_UCS(0x25ae, 2); /* black vertical rectangle */ 4756d4fba8b9Smrg MY_UCS(0x215f, 3); /* "1/" */ 4757d4fba8b9Smrg MY_UCS(0x0020, 4); /* "3/", not in Unicode, ignore */ 4758d4fba8b9Smrg MY_UCS(0x0020, 5); /* "5/", not in Unicode, ignore */ 4759d4fba8b9Smrg MY_UCS(0x0020, 6); /* "7/", not in Unicode, ignore */ 4760d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4761d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4762d4fba8b9Smrg MY_UCS(0x2192, 9); /* right-arrow */ 4763d4fba8b9Smrg MY_UCS(0x2026, 10); /* ellipsis */ 4764d4fba8b9Smrg MY_UCS(0x00f7, 11); /* divide by */ 4765d4fba8b9Smrg MY_UCS(0x2193, 12); /* down arrow */ 4766d4fba8b9Smrg MY_UCS(0x23ba, 13); /* bar at scan 0 */ 4767d4fba8b9Smrg MY_UCS(0x23ba, 14); /* bar at scan 1 */ 4768d4fba8b9Smrg MY_UCS(0x23bb, 15); /* bar at scan 2 */ 4769d4fba8b9Smrg MY_UCS(0x23bb, 16); /* bar at scan 3 */ 4770d4fba8b9Smrg MY_UCS(0x23bc, 17); /* bar at scan 4 */ 4771d4fba8b9Smrg MY_UCS(0x23bc, 18); /* bar at scan 5 */ 4772d4fba8b9Smrg MY_UCS(0x23bd, 19); /* bar at scan 6 */ 4773d4fba8b9Smrg MY_UCS(0x23bd, 20); /* bar at scan 7 */ 4774d4fba8b9Smrg MY_UCS(0x2080, 21); /* subscript 0 */ 4775d4fba8b9Smrg MY_UCS(0x2081, 22); /* subscript 1 */ 4776d4fba8b9Smrg MY_UCS(0x2082, 23); /* subscript 2 */ 4777d4fba8b9Smrg MY_UCS(0x2083, 24); /* subscript 3 */ 4778d4fba8b9Smrg MY_UCS(0x2084, 25); /* subscript 4 */ 4779d4fba8b9Smrg MY_UCS(0x2085, 26); /* subscript 5 */ 4780d4fba8b9Smrg MY_UCS(0x2086, 27); /* subscript 6 */ 4781d4fba8b9Smrg MY_UCS(0x2087, 28); /* subscript 7 */ 4782d4fba8b9Smrg MY_UCS(0x2088, 29); /* subscript 8 */ 4783d4fba8b9Smrg MY_UCS(0x2089, 30); /* subscript 9 */ 4784d4fba8b9Smrg MY_UCS(0x00b6, 31); /* paragraph */ 4785d4fba8b9Smrg } 4786d4fba8b9Smrg } else 4787d4fba8b9Smrg#endif 4788d4fba8b9Smrg switch (ch) { 4789d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4790d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4791d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4792d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4793d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4794d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4795d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4796d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4797d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4798d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4799d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4800d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4801d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4802d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4803d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4804d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4805d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4806d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4807d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4808d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4809d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4810d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4811d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4812d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4813d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4814d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4815d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4816d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4817d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4818d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4819d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4820d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4821d4fba8b9Smrg } 4822d522f475Smrg } 4823d522f475Smrg return result; 4824d522f475Smrg} 4825d522f475Smrg 4826d522f475Smrg#endif /* OPT_WIDE_CHARS */ 4827d522f475Smrg 4828b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS 48290bd37d32Smrgstatic int 4830d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum) 4831d522f475Smrg{ 4832d522f475Smrg TScreen *screen = TScreenOf(xw); 4833d522f475Smrg 4834d522f475Smrg if (screen->menu_font_sizes[fontnum] == 0) { 4835d522f475Smrg XTermFonts fnt; 4836d522f475Smrg 4837d522f475Smrg memset(&fnt, 0, sizeof(fnt)); 4838d522f475Smrg screen->menu_font_sizes[fontnum] = -1; 4839d1603babSmrg if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, NULL, True)) { 484020d2c4d2Smrg if (fontnum <= fontMenu_lastBuiltin 48410bd37d32Smrg || strcmp(fnt.fn, DEFFONT)) { 484220d2c4d2Smrg screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 48430bd37d32Smrg if (screen->menu_font_sizes[fontnum] <= 0) 48440bd37d32Smrg screen->menu_font_sizes[fontnum] = -1; 48450bd37d32Smrg } 4846d522f475Smrg xtermCloseFont(xw, &fnt); 4847d522f475Smrg } 4848d522f475Smrg } 48490bd37d32Smrg return (screen->menu_font_sizes[fontnum] > 0); 4850d522f475Smrg} 4851d522f475Smrg 4852d522f475Smrg/* 4853d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 4854d522f475Smrg */ 4855d522f475Smrgstatic void 4856d522f475SmrglookupFontSizes(XtermWidget xw) 4857d522f475Smrg{ 4858d522f475Smrg int n; 4859d522f475Smrg 4860d522f475Smrg for (n = 0; n < NMENUFONTS; n++) { 48610bd37d32Smrg (void) lookupOneFontSize(xw, n); 4862d522f475Smrg } 4863d522f475Smrg} 4864b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 4865d522f475Smrg 48662eaa94a1Schristos#if OPT_RENDERFONT 48679a64e1c5Smrgstatic double 48689a64e1c5SmrgdefaultFaceSize(void) 48699a64e1c5Smrg{ 48709a64e1c5Smrg double result; 48719a64e1c5Smrg float value; 48729a64e1c5Smrg 48739a64e1c5Smrg if (sscanf(DEFFACESIZE, "%f", &value) == 1) 4874d4fba8b9Smrg result = (double) value; 48759a64e1c5Smrg else 48769a64e1c5Smrg result = 14.0; 48779a64e1c5Smrg return result; 48789a64e1c5Smrg} 48799a64e1c5Smrg 48800bd37d32Smrgstatic void 48810bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum) 48820bd37d32Smrg{ 48830bd37d32Smrg TScreen *screen = TScreenOf(xw); 4884d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 48850bd37d32Smrg 48860bd37d32Smrg if (face_size <= 0.0) { 48870bd37d32Smrg#if OPT_SHIFT_FONTS 48880bd37d32Smrg /* 48890bd37d32Smrg * If the user is switching font-sizes, make it follow by 48900bd37d32Smrg * default the same ratios to the default as the fixed fonts 48910bd37d32Smrg * would, for easy comparison. There will be some differences 48920bd37d32Smrg * since the fixed fonts have a variety of height/width ratios, 48930bd37d32Smrg * but this is simpler than adding another resource value - and 48940bd37d32Smrg * as noted above, the data for the fixed fonts are available. 48950bd37d32Smrg */ 48960bd37d32Smrg (void) lookupOneFontSize(xw, 0); 48970bd37d32Smrg if (fontnum == fontMenu_default) { 48989a64e1c5Smrg face_size = defaultFaceSize(); 48990bd37d32Smrg } else if (lookupOneFontSize(xw, fontnum) 49000bd37d32Smrg && (screen->menu_font_sizes[0] 49010bd37d32Smrg != screen->menu_font_sizes[fontnum])) { 49020bd37d32Smrg double ratio; 49030bd37d32Smrg long num = screen->menu_font_sizes[fontnum]; 49040bd37d32Smrg long den = screen->menu_font_sizes[0]; 49050bd37d32Smrg 49060bd37d32Smrg if (den <= 0) 49070bd37d32Smrg den = 1; 49080bd37d32Smrg ratio = dimSquareRoot((double) num / (double) den); 49090bd37d32Smrg 4910d4fba8b9Smrg face_size = (ratio * (double) xw->misc.face_size[0]); 49110bd37d32Smrg TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 49120bd37d32Smrg fontnum, num, den, ratio, face_size)); 49130bd37d32Smrg } else 49140bd37d32Smrg#endif 49150bd37d32Smrg { 4916d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default]) 49170bd37d32Smrg switch (fontnum) { 49180bd37d32Smrg case fontMenu_font1: 49190bd37d32Smrg face_size = LikeBitmap(2.0); 49200bd37d32Smrg break; 49210bd37d32Smrg case fontMenu_font2: 49220bd37d32Smrg face_size = LikeBitmap(35.0); 49230bd37d32Smrg break; 49240bd37d32Smrg case fontMenu_font3: 49250bd37d32Smrg face_size = LikeBitmap(60.0); 49260bd37d32Smrg break; 49270bd37d32Smrg default: 49289a64e1c5Smrg face_size = defaultFaceSize(); 49290bd37d32Smrg break; 49300bd37d32Smrg case fontMenu_font4: 49310bd37d32Smrg face_size = LikeBitmap(90.0); 49320bd37d32Smrg break; 49330bd37d32Smrg case fontMenu_font5: 49340bd37d32Smrg face_size = LikeBitmap(135.0); 49350bd37d32Smrg break; 49360bd37d32Smrg case fontMenu_font6: 49370bd37d32Smrg face_size = LikeBitmap(200.0); 49380bd37d32Smrg break; 4939d4fba8b9Smrg case fontMenu_font7: 4940d4fba8b9Smrg face_size = LikeBitmap(240.0); 4941d4fba8b9Smrg break; 49420bd37d32Smrg } 49430bd37d32Smrg TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 49440bd37d32Smrg } 49450bd37d32Smrg xw->misc.face_size[fontnum] = (float) face_size; 49460bd37d32Smrg } 49470bd37d32Smrg} 49480bd37d32Smrg 49490bd37d32Smrg/* no selection or escape */ 49500bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 49510bd37d32Smrg 49520bd37d32Smrg/* 49530bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font 49540bd37d32Smrg * sizes are the same, and if we're using TrueType fonts. 49550bd37d32Smrg */ 49562eaa94a1Schristosstatic Boolean 49572eaa94a1SchristosuseFaceSizes(XtermWidget xw) 49582eaa94a1Schristos{ 49592eaa94a1Schristos Boolean result = False; 49602eaa94a1Schristos 4961d4fba8b9Smrg TRACE(("useFaceSizes " TRACE_L "\n")); 49622eaa94a1Schristos if (UsingRenderFont(xw)) { 49630bd37d32Smrg Boolean nonzero = True; 4964037a25ddSmrg int n; 49650bd37d32Smrg 49662eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 4967d4fba8b9Smrg if (xw->misc.face_size[n] <= 0.0f) { 49680bd37d32Smrg nonzero = False; 49692eaa94a1Schristos break; 49702eaa94a1Schristos } 49712eaa94a1Schristos } 49720bd37d32Smrg if (!nonzero) { 4973956cc18dSsnj Boolean broken_fonts = True; 4974956cc18dSsnj TScreen *screen = TScreenOf(xw); 49750bd37d32Smrg long first; 4976956cc18dSsnj 4977956cc18dSsnj lookupFontSizes(xw); 49780bd37d32Smrg first = screen->menu_font_sizes[0]; 4979956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 4980956cc18dSsnj if (screen->menu_font_sizes[n] > 0 4981956cc18dSsnj && screen->menu_font_sizes[n] != first) { 4982956cc18dSsnj broken_fonts = False; 4983956cc18dSsnj break; 4984956cc18dSsnj } 4985956cc18dSsnj } 4986956cc18dSsnj 4987956cc18dSsnj if (broken_fonts) { 4988956cc18dSsnj 4989956cc18dSsnj TRACE(("bitmap fonts are broken - set faceSize resources\n")); 4990956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 49910bd37d32Smrg fillInFaceSize(xw, n); 4992956cc18dSsnj } 4993956cc18dSsnj 4994956cc18dSsnj } 4995956cc18dSsnj } 49960bd37d32Smrg result = True; 49972eaa94a1Schristos } 4998d4fba8b9Smrg TRACE((TRACE_R " useFaceSizes %d\n", result)); 49992eaa94a1Schristos return result; 50002eaa94a1Schristos} 50010bd37d32Smrg#endif /* OPT_RENDERFONT */ 50022eaa94a1Schristos 5003b6fea0ceSmrg#if OPT_SHIFT_FONTS 5004d522f475Smrg/* 5005d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative' 5006d522f475Smrg * and its magnitude), starting from the 'old' index. 5007d522f475Smrg */ 5008d522f475Smrgint 5009d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative) 5010d522f475Smrg{ 5011d522f475Smrg TScreen *screen = TScreenOf(xw); 5012037a25ddSmrg int m = -1; 5013d522f475Smrg 50142eaa94a1Schristos TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 5015d522f475Smrg if (!IsIcon(screen)) { 50162eaa94a1Schristos#if OPT_RENDERFONT 50172eaa94a1Schristos if (useFaceSizes(xw)) { 50182eaa94a1Schristos TRACE(("...using FaceSize\n")); 50192eaa94a1Schristos if (relative != 0) { 5020037a25ddSmrg int n; 50212eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 50220bd37d32Smrg fillInFaceSize(xw, n); 50232eaa94a1Schristos if (xw->misc.face_size[n] > 0 && 50242eaa94a1Schristos xw->misc.face_size[n] != xw->misc.face_size[old]) { 50252eaa94a1Schristos int cmp_0 = ((xw->misc.face_size[n] > 50262eaa94a1Schristos xw->misc.face_size[old]) 50272eaa94a1Schristos ? relative 50282eaa94a1Schristos : -relative); 50292eaa94a1Schristos int cmp_m = ((m < 0) 50302eaa94a1Schristos ? 1 50312eaa94a1Schristos : ((xw->misc.face_size[n] < 50322eaa94a1Schristos xw->misc.face_size[m]) 50332eaa94a1Schristos ? relative 50342eaa94a1Schristos : -relative)); 50352eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 50362eaa94a1Schristos m = n; 50372eaa94a1Schristos } 5038d522f475Smrg } 5039d522f475Smrg } 5040d522f475Smrg } 50412eaa94a1Schristos } else 50422eaa94a1Schristos#endif 50432eaa94a1Schristos { 50442eaa94a1Schristos TRACE(("...using bitmap areas\n")); 50452eaa94a1Schristos lookupFontSizes(xw); 50462eaa94a1Schristos if (relative != 0) { 5047037a25ddSmrg int n; 50482eaa94a1Schristos for (n = 0; n < NMENUFONTS; ++n) { 50492eaa94a1Schristos if (screen->menu_font_sizes[n] > 0 && 50502eaa94a1Schristos screen->menu_font_sizes[n] != 50512eaa94a1Schristos screen->menu_font_sizes[old]) { 50522eaa94a1Schristos int cmp_0 = ((screen->menu_font_sizes[n] > 50532eaa94a1Schristos screen->menu_font_sizes[old]) 50542eaa94a1Schristos ? relative 50552eaa94a1Schristos : -relative); 50562eaa94a1Schristos int cmp_m = ((m < 0) 50572eaa94a1Schristos ? 1 50582eaa94a1Schristos : ((screen->menu_font_sizes[n] < 50592eaa94a1Schristos screen->menu_font_sizes[m]) 50602eaa94a1Schristos ? relative 50612eaa94a1Schristos : -relative)); 50622eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 50632eaa94a1Schristos m = n; 50642eaa94a1Schristos } 50652eaa94a1Schristos } 50662eaa94a1Schristos } 5067d522f475Smrg } 5068d522f475Smrg } 50692eaa94a1Schristos TRACE(("...new index %d\n", m)); 50702eaa94a1Schristos if (m >= 0) { 50712eaa94a1Schristos if (relative > 1) 50722eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative - 1); 50732eaa94a1Schristos else if (relative < -1) 50742eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative + 1); 50752eaa94a1Schristos } 5076d522f475Smrg } 5077d522f475Smrg return m; 5078d522f475Smrg} 5079d522f475Smrg 5080d522f475Smrg/* ARGSUSED */ 5081d522f475Smrgvoid 5082d4fba8b9SmrgHandleLargerFont(Widget w, 50839a64e1c5Smrg XEvent *event GCC_UNUSED, 5084fa3f02f3Smrg String *params GCC_UNUSED, 5085d522f475Smrg Cardinal *param_count GCC_UNUSED) 5086d522f475Smrg{ 5087956cc18dSsnj XtermWidget xw; 5088d522f475Smrg 508920d2c4d2Smrg TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 5090956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 5091d522f475Smrg if (xw->misc.shift_fonts) { 5092956cc18dSsnj TScreen *screen = TScreenOf(xw); 5093d522f475Smrg int m; 5094d522f475Smrg 5095d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 5096d522f475Smrg if (m >= 0) { 5097d522f475Smrg SetVTFont(xw, m, True, NULL); 5098d522f475Smrg } else { 509920d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5100d522f475Smrg } 5101d522f475Smrg } 5102d522f475Smrg } 5103d522f475Smrg} 5104d522f475Smrg 5105d522f475Smrg/* ARGSUSED */ 5106d522f475Smrgvoid 5107d4fba8b9SmrgHandleSmallerFont(Widget w, 51089a64e1c5Smrg XEvent *event GCC_UNUSED, 5109fa3f02f3Smrg String *params GCC_UNUSED, 5110d522f475Smrg Cardinal *param_count GCC_UNUSED) 5111d522f475Smrg{ 5112956cc18dSsnj XtermWidget xw; 5113d522f475Smrg 511420d2c4d2Smrg TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 5115956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 5116d522f475Smrg if (xw->misc.shift_fonts) { 5117956cc18dSsnj TScreen *screen = TScreenOf(xw); 5118d522f475Smrg int m; 5119d522f475Smrg 5120d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 5121d522f475Smrg if (m >= 0) { 5122d522f475Smrg SetVTFont(xw, m, True, NULL); 5123d522f475Smrg } else { 512420d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5125d522f475Smrg } 5126d522f475Smrg } 5127d522f475Smrg } 5128d522f475Smrg} 5129b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */ 5130d522f475Smrg 5131d522f475Smrgint 5132d522f475SmrgxtermGetFont(const char *param) 5133d522f475Smrg{ 5134d522f475Smrg int fontnum; 5135d522f475Smrg 5136d1603babSmrg if (param == NULL) 5137d1603babSmrg param = ""; 5138d1603babSmrg 5139d522f475Smrg switch (param[0]) { 5140d522f475Smrg case 'd': 5141d522f475Smrg case 'D': 5142d522f475Smrg case '0': 5143d522f475Smrg fontnum = fontMenu_default; 5144d522f475Smrg break; 5145d522f475Smrg case '1': 5146d522f475Smrg fontnum = fontMenu_font1; 5147d522f475Smrg break; 5148d522f475Smrg case '2': 5149d522f475Smrg fontnum = fontMenu_font2; 5150d522f475Smrg break; 5151d522f475Smrg case '3': 5152d522f475Smrg fontnum = fontMenu_font3; 5153d522f475Smrg break; 5154d522f475Smrg case '4': 5155d522f475Smrg fontnum = fontMenu_font4; 5156d522f475Smrg break; 5157d522f475Smrg case '5': 5158d522f475Smrg fontnum = fontMenu_font5; 5159d522f475Smrg break; 5160d522f475Smrg case '6': 5161d522f475Smrg fontnum = fontMenu_font6; 5162d522f475Smrg break; 5163d4fba8b9Smrg case '7': 5164d4fba8b9Smrg fontnum = fontMenu_font7; 5165d4fba8b9Smrg break; 5166d522f475Smrg case 'e': 5167d522f475Smrg case 'E': 5168d522f475Smrg fontnum = fontMenu_fontescape; 5169d522f475Smrg break; 5170d522f475Smrg case 's': 5171d522f475Smrg case 'S': 5172d522f475Smrg fontnum = fontMenu_fontsel; 5173d522f475Smrg break; 5174d522f475Smrg default: 5175d522f475Smrg fontnum = -1; 5176d522f475Smrg break; 5177d522f475Smrg } 5178d1603babSmrg TRACE(("xtermGetFont(%s) ->%d\n", param, fontnum)); 5179d522f475Smrg return fontnum; 5180d522f475Smrg} 5181d522f475Smrg 5182d522f475Smrg/* ARGSUSED */ 5183d522f475Smrgvoid 5184d4fba8b9SmrgHandleSetFont(Widget w, 51859a64e1c5Smrg XEvent *event GCC_UNUSED, 5186fa3f02f3Smrg String *params, 5187d522f475Smrg Cardinal *param_count) 5188d522f475Smrg{ 5189956cc18dSsnj XtermWidget xw; 5190956cc18dSsnj 5191956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 5192d522f475Smrg int fontnum; 5193d522f475Smrg VTFontNames fonts; 5194d522f475Smrg 5195d522f475Smrg memset(&fonts, 0, sizeof(fonts)); 5196d522f475Smrg 5197d522f475Smrg if (*param_count == 0) { 5198d522f475Smrg fontnum = fontMenu_default; 5199d522f475Smrg } else { 5200d522f475Smrg Cardinal maxparams = 1; /* total number of params allowed */ 5201d522f475Smrg int result = xtermGetFont(params[0]); 5202d522f475Smrg 5203d522f475Smrg switch (result) { 5204d522f475Smrg case fontMenu_default: /* FALLTHRU */ 5205d522f475Smrg case fontMenu_font1: /* FALLTHRU */ 5206d522f475Smrg case fontMenu_font2: /* FALLTHRU */ 5207d522f475Smrg case fontMenu_font3: /* FALLTHRU */ 5208d522f475Smrg case fontMenu_font4: /* FALLTHRU */ 5209d522f475Smrg case fontMenu_font5: /* FALLTHRU */ 5210d522f475Smrg case fontMenu_font6: /* FALLTHRU */ 5211d4fba8b9Smrg case fontMenu_font7: /* FALLTHRU */ 5212d522f475Smrg break; 5213d522f475Smrg case fontMenu_fontescape: 5214d522f475Smrg#if OPT_WIDE_CHARS 5215d522f475Smrg maxparams = 5; 5216d522f475Smrg#else 5217d522f475Smrg maxparams = 3; 5218d522f475Smrg#endif 5219d522f475Smrg break; 5220d522f475Smrg case fontMenu_fontsel: 5221d522f475Smrg maxparams = 2; 5222d522f475Smrg break; 5223d522f475Smrg default: 522420d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5225d522f475Smrg return; 5226d522f475Smrg } 5227d522f475Smrg fontnum = result; 5228d522f475Smrg 5229d522f475Smrg if (*param_count > maxparams) { /* see if extra args given */ 523020d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5231d522f475Smrg return; 5232d522f475Smrg } 5233d522f475Smrg switch (*param_count) { /* assign 'em */ 5234d522f475Smrg#if OPT_WIDE_CHARS 5235d522f475Smrg case 5: 5236dfb07bc7Smrg fonts.f_wb = x_strdup(params[4]); 5237d522f475Smrg /* FALLTHRU */ 5238d522f475Smrg case 4: 5239dfb07bc7Smrg fonts.f_w = x_strdup(params[3]); 5240d522f475Smrg#endif 5241dfb07bc7Smrg /* FALLTHRU */ 5242d522f475Smrg case 3: 5243dfb07bc7Smrg fonts.f_b = x_strdup(params[2]); 5244d522f475Smrg /* FALLTHRU */ 5245d522f475Smrg case 2: 5246dfb07bc7Smrg fonts.f_n = x_strdup(params[1]); 5247d522f475Smrg break; 5248d522f475Smrg } 5249d522f475Smrg } 5250d522f475Smrg 5251956cc18dSsnj SetVTFont(xw, fontnum, True, &fonts); 5252d522f475Smrg } 5253d522f475Smrg} 5254d522f475Smrg 5255d1603babSmrgBool 5256d522f475SmrgSetVTFont(XtermWidget xw, 5257d522f475Smrg int which, 5258d522f475Smrg Bool doresize, 5259d522f475Smrg const VTFontNames * fonts) 5260d522f475Smrg{ 5261956cc18dSsnj TScreen *screen = TScreenOf(xw); 5262d1603babSmrg Bool result = False; 5263d522f475Smrg 5264d522f475Smrg TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 5265d522f475Smrg (fonts && fonts->f_n) ? fonts->f_n : "<null>", 5266d522f475Smrg (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 5267d522f475Smrg 5268d522f475Smrg if (IsIcon(screen)) { 526920d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5270d522f475Smrg } else if (which >= 0 && which < NMENUFONTS) { 5271d1603babSmrg VTFontNames new_fnames; 5272d522f475Smrg 5273d1603babSmrg memset(&new_fnames, 0, sizeof(new_fnames)); 5274d522f475Smrg if (fonts != 0) 5275d1603babSmrg new_fnames = *fonts; 5276d522f475Smrg 5277d522f475Smrg if (which == fontMenu_fontsel) { /* go get the selection */ 5278d1603babSmrg result = FindFontSelection(xw, new_fnames.f_n, False); 5279d522f475Smrg } else { 5280d522f475Smrg#define USE_CACHED(field, name) \ 5281d1603babSmrg if (new_fnames.field == NULL) { \ 5282d1603babSmrg new_fnames.field = x_strdup(screen->menu_font_names[which][name]); \ 5283d1603babSmrg TRACE(("set new_fnames." #field " from menu_font_names[%d][" #name "] %s\n", \ 5284d1603babSmrg which, NonNull(new_fnames.field))); \ 5285d522f475Smrg } else { \ 5286d1603babSmrg TRACE(("set new_fnames." #field " reused\n")); \ 5287d522f475Smrg } 528820d2c4d2Smrg#define SAVE_FNAME(field, name) \ 5289d1603babSmrg if (new_fnames.field != NULL \ 5290d1603babSmrg && (screen->menu_font_names[which][name] == NULL \ 5291d1603babSmrg || strcmp(screen->menu_font_names[which][name], new_fnames.field))) { \ 5292d1603babSmrg TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \ 5293d1603babSmrg which, new_fnames.field)); \ 5294d1603babSmrg FREE_STRING(screen->menu_font_names[which][name]); \ 5295d1603babSmrg screen->menu_font_names[which][name] = x_strdup(new_fnames.field); \ 529620d2c4d2Smrg } 529720d2c4d2Smrg 5298d522f475Smrg USE_CACHED(f_n, fNorm); 5299d522f475Smrg USE_CACHED(f_b, fBold); 5300d522f475Smrg#if OPT_WIDE_CHARS 5301d522f475Smrg USE_CACHED(f_w, fWide); 5302d522f475Smrg USE_CACHED(f_wb, fWBold); 5303d522f475Smrg#endif 5304d522f475Smrg if (xtermLoadFont(xw, 5305d1603babSmrg &new_fnames, 5306d522f475Smrg doresize, which)) { 530720d2c4d2Smrg /* 530820d2c4d2Smrg * If successful, save the data so that a subsequent query via 530920d2c4d2Smrg * OSC-50 will return the expected values. 531020d2c4d2Smrg */ 531120d2c4d2Smrg SAVE_FNAME(f_n, fNorm); 531220d2c4d2Smrg SAVE_FNAME(f_b, fBold); 531320d2c4d2Smrg#if OPT_WIDE_CHARS 531420d2c4d2Smrg SAVE_FNAME(f_w, fWide); 531520d2c4d2Smrg SAVE_FNAME(f_wb, fWBold); 531620d2c4d2Smrg#endif 5317d1603babSmrg result = True; 5318d522f475Smrg } else { 531920d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5320d522f475Smrg } 53219a64e1c5Smrg FREE_FNAME(f_n); 53229a64e1c5Smrg FREE_FNAME(f_b); 53239a64e1c5Smrg#if OPT_WIDE_CHARS 53249a64e1c5Smrg FREE_FNAME(f_w); 53259a64e1c5Smrg FREE_FNAME(f_wb); 53269a64e1c5Smrg#endif 5327d522f475Smrg } 532820d2c4d2Smrg } else { 532920d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5330d522f475Smrg } 5331d1603babSmrg TRACE(("...SetVTFont: %d\n", result)); 5332d1603babSmrg return result; 5333d522f475Smrg} 5334dfb07bc7Smrg 5335dfb07bc7Smrg#if OPT_RENDERFONT 5336dfb07bc7Smrgstatic void 5337dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size) 5338dfb07bc7Smrg{ 5339dfb07bc7Smrg char *first = strstr(face_name, ":size="); 5340dfb07bc7Smrg if (first == 0) { 5341dfb07bc7Smrg first = face_name; 5342dfb07bc7Smrg } else { 5343dfb07bc7Smrg first++; 5344dfb07bc7Smrg } 5345dfb07bc7Smrg if (!strncmp(first, "size=", (size_t) 5)) { 5346dfb07bc7Smrg char *last = strchr(first, ':'); 5347dfb07bc7Smrg char mark; 5348dfb07bc7Smrg float value; 5349dfb07bc7Smrg char extra; 5350dfb07bc7Smrg TRACE(("...before trimming, font = \"%s\"\n", face_name)); 5351dfb07bc7Smrg if (last == 0) 5352dfb07bc7Smrg last = first + strlen(first); 5353dfb07bc7Smrg mark = *last; 5354dfb07bc7Smrg *last = '\0'; 5355dfb07bc7Smrg if (sscanf(first, "size=%g%c", &value, &extra) == 1) { 5356dfb07bc7Smrg TRACE(("...trimmed size from font: %g\n", value)); 5357dfb07bc7Smrg if (face_size != 0) 5358dfb07bc7Smrg *face_size = value; 5359dfb07bc7Smrg } 5360dfb07bc7Smrg if (mark) { 5361dfb07bc7Smrg while ((*first++ = *++last) != '\0') { 5362dfb07bc7Smrg ; 5363dfb07bc7Smrg } 5364dfb07bc7Smrg } else { 5365dfb07bc7Smrg if (first != face_name) 5366dfb07bc7Smrg --first; 5367dfb07bc7Smrg *first = '\0'; 5368dfb07bc7Smrg } 5369dfb07bc7Smrg TRACE(("...after trimming, font = \"%s\"\n", face_name)); 5370dfb07bc7Smrg } 5371dfb07bc7Smrg} 5372dfb07bc7Smrg#endif 5373dfb07bc7Smrg 5374dfb07bc7Smrg/* 5375dfb07bc7Smrg * Save a font specification to the proper list. 5376dfb07bc7Smrg */ 5377dfb07bc7Smrgstatic void 5378dfb07bc7Smrgsave2FontList(XtermWidget xw, 5379dfb07bc7Smrg const char *name, 5380dfb07bc7Smrg XtermFontNames * fontnames, 5381dfb07bc7Smrg VTFontEnum which, 5382dfb07bc7Smrg const char *source, 5383d1603babSmrg Bool check, 5384dfb07bc7Smrg Bool ttf) 5385dfb07bc7Smrg{ 5386dfb07bc7Smrg char *value; 5387dfb07bc7Smrg size_t plen; 5388dfb07bc7Smrg Bool marked = False; 5389dfb07bc7Smrg Bool use_ttf = ttf; 5390dfb07bc7Smrg 5391dfb07bc7Smrg (void) xw; 5392dfb07bc7Smrg 5393dfb07bc7Smrg if (source == 0) 5394dfb07bc7Smrg source = ""; 5395dfb07bc7Smrg while (isspace(CharOf(*source))) 5396dfb07bc7Smrg ++source; 5397dfb07bc7Smrg 5398dfb07bc7Smrg /* fontconfig patterns can contain ':' separators, but we'll treat 5399dfb07bc7Smrg * a leading prefix specially to denote whether the pattern might be 5400dfb07bc7Smrg * XLFD ("x" or "xlfd") versus Xft ("xft"). 5401dfb07bc7Smrg */ 5402dfb07bc7Smrg for (plen = 0; source[plen] != '\0'; ++plen) { 5403dfb07bc7Smrg if (source[plen] == ':') { 5404dfb07bc7Smrg marked = True; 5405dfb07bc7Smrg switch (plen) { 5406dfb07bc7Smrg case 0: 5407dfb07bc7Smrg ++plen; /* trim leading ':' */ 5408dfb07bc7Smrg break; 5409dfb07bc7Smrg case 1: 5410dfb07bc7Smrg if (!strncmp(source, "x", plen)) { 5411dfb07bc7Smrg ++plen; 5412dfb07bc7Smrg use_ttf = False; 5413dfb07bc7Smrg } else { 5414dfb07bc7Smrg marked = False; 5415dfb07bc7Smrg } 5416dfb07bc7Smrg break; 5417dfb07bc7Smrg case 3: 5418dfb07bc7Smrg if (!strncmp(source, "xft", plen)) { 5419dfb07bc7Smrg ++plen; 5420dfb07bc7Smrg use_ttf = True; 5421dfb07bc7Smrg } else { 5422dfb07bc7Smrg marked = False; 5423dfb07bc7Smrg } 5424dfb07bc7Smrg break; 5425dfb07bc7Smrg case 4: 5426dfb07bc7Smrg if (!strncmp(source, "xlfd", plen)) { 5427dfb07bc7Smrg ++plen; 5428dfb07bc7Smrg use_ttf = False; 5429dfb07bc7Smrg } else { 5430dfb07bc7Smrg marked = False; 5431dfb07bc7Smrg } 5432dfb07bc7Smrg break; 5433dfb07bc7Smrg default: 5434dfb07bc7Smrg marked = False; 5435dfb07bc7Smrg plen = 0; 5436dfb07bc7Smrg break; 5437dfb07bc7Smrg } 5438dfb07bc7Smrg break; 5439dfb07bc7Smrg } 5440dfb07bc7Smrg } 5441dfb07bc7Smrg if (!marked) 5442dfb07bc7Smrg plen = 0; 5443dfb07bc7Smrg value = x_strtrim(source + plen); 5444dfb07bc7Smrg if (value != 0) { 5445dfb07bc7Smrg Bool success = False; 5446dfb07bc7Smrg#if OPT_RENDERFONT 5447dfb07bc7Smrg VTFontList *target = (use_ttf 5448dfb07bc7Smrg ? &(fontnames->xft) 5449dfb07bc7Smrg : &(fontnames->x11)); 5450dfb07bc7Smrg#else 5451dfb07bc7Smrg VTFontList *target = &(fontnames->x11); 5452dfb07bc7Smrg#endif 5453dfb07bc7Smrg char ***list = 0; 5454dfb07bc7Smrg char **next = 0; 5455dfb07bc7Smrg size_t count = 0; 5456dfb07bc7Smrg 5457dfb07bc7Smrg (void) use_ttf; 5458dfb07bc7Smrg switch (which) { 5459dfb07bc7Smrg case fNorm: 5460dfb07bc7Smrg list = &(target->list_n); 5461dfb07bc7Smrg break; 5462dfb07bc7Smrg case fBold: 5463dfb07bc7Smrg list = &(target->list_b); 5464dfb07bc7Smrg break; 5465dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5466dfb07bc7Smrg case fItal: 5467dfb07bc7Smrg list = &(target->list_i); 5468dfb07bc7Smrg break; 5469d4fba8b9Smrg case fBtal: 5470d4fba8b9Smrg list = &(target->list_bi); 5471d4fba8b9Smrg break; 5472dfb07bc7Smrg#endif 5473dfb07bc7Smrg#if OPT_WIDE_CHARS 5474dfb07bc7Smrg case fWide: 5475dfb07bc7Smrg list = &(target->list_w); 5476dfb07bc7Smrg break; 5477dfb07bc7Smrg case fWBold: 5478dfb07bc7Smrg list = &(target->list_wb); 5479dfb07bc7Smrg break; 5480dfb07bc7Smrg case fWItal: 5481dfb07bc7Smrg list = &(target->list_wi); 5482dfb07bc7Smrg break; 5483d4fba8b9Smrg case fWBtal: 5484d4fba8b9Smrg list = &(target->list_wbi); 5485d4fba8b9Smrg break; 5486dfb07bc7Smrg#endif 5487dfb07bc7Smrg case fMAX: 5488dfb07bc7Smrg list = 0; 5489dfb07bc7Smrg break; 5490dfb07bc7Smrg } 5491dfb07bc7Smrg 5492dfb07bc7Smrg if (list != 0) { 5493dfb07bc7Smrg success = True; 5494dfb07bc7Smrg if (*list != 0) { 5495dfb07bc7Smrg while ((*list)[count] != 0) { 5496dfb07bc7Smrg if (IsEmpty((*list)[count])) { 5497dfb07bc7Smrg TRACE(("... initial %s\n", value)); 5498dfb07bc7Smrg free((*list)[count]); 5499dfb07bc7Smrg break; 5500dfb07bc7Smrg } else if (!strcmp(value, (*list)[count])) { 5501dfb07bc7Smrg TRACE(("... duplicate %s\n", value)); 5502dfb07bc7Smrg success = False; 5503dfb07bc7Smrg break; 5504dfb07bc7Smrg } 5505dfb07bc7Smrg ++count; 5506dfb07bc7Smrg } 5507dfb07bc7Smrg } 5508dfb07bc7Smrg if (success) { 5509d1603babSmrg next = (char **) realloc(*list, sizeof(char *) * (count + 2)); 5510dfb07bc7Smrg if (next != 0) { 5511dfb07bc7Smrg#if OPT_RENDERFONT 5512dfb07bc7Smrg if (use_ttf) { 5513dfb07bc7Smrg trimSizeFromFace(value, 5514dfb07bc7Smrg (count == 0 && which == fNorm) 5515dfb07bc7Smrg ? &(xw->misc.face_size[0]) 5516dfb07bc7Smrg : (float *) 0); 5517dfb07bc7Smrg } 5518dfb07bc7Smrg#endif 5519dfb07bc7Smrg next[count++] = value; 5520dfb07bc7Smrg next[count] = 0; 5521dfb07bc7Smrg *list = next; 55228f44fb3bSmrg TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n", 5523dfb07bc7Smrg whichFontList(xw, target), 5524dfb07bc7Smrg whichFontList2(xw, *list), 5525dfb07bc7Smrg (unsigned long) count, 5526dfb07bc7Smrg value)); 5527dfb07bc7Smrg } else { 5528d1603babSmrg xtermWarning("realloc failure in save2FontList(%s)\n", name); 5529dfb07bc7Smrg freeFontList(list); 5530dfb07bc7Smrg success = False; 5531dfb07bc7Smrg } 5532dfb07bc7Smrg } 5533dfb07bc7Smrg } 5534dfb07bc7Smrg if (success) { 5535d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS) 5536d4fba8b9Smrg size_t limit = MAX_XFT_FONTS; 5537d4fba8b9Smrg#else 5538dfb07bc7Smrg size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS; 5539d4fba8b9Smrg#endif 5540d4fba8b9Smrg if (count > limit && *x_skip_blanks(value)) { 5541d1603babSmrg if (check) { 5542d1603babSmrg xtermWarning("too many fonts for %s, ignoring %s\n", 5543d1603babSmrg whichFontEnum(which), 5544d1603babSmrg value); 5545d1603babSmrg } 5546dfb07bc7Smrg if (list && *list) { 5547dfb07bc7Smrg free((*list)[limit]); 5548dfb07bc7Smrg (*list)[limit] = 0; 5549dfb07bc7Smrg } 5550dfb07bc7Smrg } 5551dfb07bc7Smrg } else { 5552dfb07bc7Smrg free(value); 5553dfb07bc7Smrg } 5554dfb07bc7Smrg } 5555dfb07bc7Smrg} 5556dfb07bc7Smrg 5557dfb07bc7Smrg/* 5558dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list 5559dfb07bc7Smrg * of font-names. That would be bad for performance, but as a basis for an 5560dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating 5561dfb07bc7Smrg * an array of font-names. 5562dfb07bc7Smrg */ 5563dfb07bc7Smrgvoid 5564dfb07bc7SmrgallocFontList(XtermWidget xw, 5565dfb07bc7Smrg const char *name, 5566dfb07bc7Smrg XtermFontNames * target, 5567dfb07bc7Smrg VTFontEnum which, 5568dfb07bc7Smrg const char *source, 5569dfb07bc7Smrg Bool ttf) 5570dfb07bc7Smrg{ 5571dfb07bc7Smrg char *blob; 5572dfb07bc7Smrg 5573dfb07bc7Smrg blob = x_strdup(source); 5574d4fba8b9Smrg if (blob != 0) { 5575dfb07bc7Smrg int n; 5576dfb07bc7Smrg int pass; 5577dfb07bc7Smrg char **list = 0; 5578dfb07bc7Smrg 55798f44fb3bSmrg TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n", 55808f44fb3bSmrg whichFontEnum(which), name, blob)); 5581dfb07bc7Smrg 5582dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5583dfb07bc7Smrg unsigned count = 0; 5584dfb07bc7Smrg if (pass) 5585dfb07bc7Smrg list[0] = blob; 5586dfb07bc7Smrg for (n = 0; blob[n] != '\0'; ++n) { 5587dfb07bc7Smrg if (blob[n] == ',') { 5588dfb07bc7Smrg ++count; 5589dfb07bc7Smrg if (pass != 0) { 5590dfb07bc7Smrg blob[n] = '\0'; 5591dfb07bc7Smrg list[count] = blob + n + 1; 5592dfb07bc7Smrg } 5593dfb07bc7Smrg } 5594dfb07bc7Smrg } 5595dfb07bc7Smrg if (!pass) { 5596dfb07bc7Smrg if (count == 0 && *blob == '\0') 5597dfb07bc7Smrg break; 5598dfb07bc7Smrg list = TypeCallocN(char *, count + 2); 5599dfb07bc7Smrg if (list == 0) 5600dfb07bc7Smrg break; 5601dfb07bc7Smrg } 5602dfb07bc7Smrg } 5603dfb07bc7Smrg if (list) { 5604dfb07bc7Smrg for (n = 0; list[n] != 0; ++n) { 5605dfb07bc7Smrg if (*list[n]) { 5606d1603babSmrg save2FontList(xw, name, target, which, list[n], True, ttf); 5607dfb07bc7Smrg } 5608dfb07bc7Smrg } 5609dfb07bc7Smrg free(list); 5610dfb07bc7Smrg } 5611dfb07bc7Smrg } 5612dfb07bc7Smrg free(blob); 5613dfb07bc7Smrg} 5614dfb07bc7Smrg 5615dfb07bc7Smrgstatic void 5616dfb07bc7SmrginitFontList(XtermWidget xw, 5617dfb07bc7Smrg const char *name, 5618dfb07bc7Smrg XtermFontNames * target, 5619dfb07bc7Smrg Bool ttf) 5620dfb07bc7Smrg{ 5621dfb07bc7Smrg int which; 5622dfb07bc7Smrg 5623dfb07bc7Smrg TRACE(("initFontList(%s)\n", name)); 5624dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5625d1603babSmrg save2FontList(xw, name, target, (VTFontEnum) which, "", False, ttf); 5626dfb07bc7Smrg } 5627dfb07bc7Smrg} 5628dfb07bc7Smrg 5629dfb07bc7Smrgvoid 5630dfb07bc7SmrginitFontLists(XtermWidget xw) 5631dfb07bc7Smrg{ 5632dfb07bc7Smrg TRACE(("initFontLists\n")); 5633dfb07bc7Smrg initFontList(xw, "x11 font", &(xw->work.fonts), False); 5634dfb07bc7Smrg#if OPT_RENDERFONT 5635dfb07bc7Smrg initFontList(xw, "xft font", &(xw->work.fonts), True); 5636dfb07bc7Smrg#endif 5637dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5638dfb07bc7Smrg initFontList(xw, "cached font", 5639dfb07bc7Smrg &(xw->screen.cacheVTFonts.fonts), False); 5640dfb07bc7Smrg#endif 5641dfb07bc7Smrg} 5642dfb07bc7Smrg 5643dfb07bc7Smrgvoid 5644dfb07bc7SmrgcopyFontList(char ***targetp, char **source) 5645dfb07bc7Smrg{ 5646dfb07bc7Smrg freeFontList(targetp); 5647dfb07bc7Smrg 5648dfb07bc7Smrg if (source != 0) { 5649dfb07bc7Smrg int pass; 5650dfb07bc7Smrg size_t count; 5651dfb07bc7Smrg 5652dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5653dfb07bc7Smrg for (count = 0; source[count] != 0; ++count) { 5654dfb07bc7Smrg if (pass) 5655dfb07bc7Smrg (*targetp)[count] = x_strdup(source[count]); 5656dfb07bc7Smrg } 5657dfb07bc7Smrg if (!pass) { 5658dfb07bc7Smrg ++count; 5659dfb07bc7Smrg *targetp = TypeCallocN(char *, count); 5660dfb07bc7Smrg } 5661dfb07bc7Smrg } 5662dfb07bc7Smrg } else { 5663dfb07bc7Smrg *targetp = TypeCallocN(char *, 2); 5664dfb07bc7Smrg (*targetp)[0] = x_strdup(""); 5665dfb07bc7Smrg } 5666dfb07bc7Smrg} 5667dfb07bc7Smrg 5668dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5669dfb07bc7Smrgstatic Boolean 5670dfb07bc7Smrgmerge_sublist(char ***targetp, char **source) 5671dfb07bc7Smrg{ 5672dfb07bc7Smrg Boolean result = False; 5673dfb07bc7Smrg if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) { 5674dfb07bc7Smrg copyFontList(targetp, source); 5675dfb07bc7Smrg result = True; 5676dfb07bc7Smrg } 5677dfb07bc7Smrg return result; 5678dfb07bc7Smrg} 5679dfb07bc7Smrg#endif 5680dfb07bc7Smrg 5681dfb07bc7Smrgvoid 5682dfb07bc7SmrgfreeFontList(char ***targetp) 5683dfb07bc7Smrg{ 5684dfb07bc7Smrg if (targetp != 0) { 5685dfb07bc7Smrg char **target = *targetp; 5686dfb07bc7Smrg if (target != 0) { 5687dfb07bc7Smrg int n; 5688dfb07bc7Smrg for (n = 0; target[n] != 0; ++n) { 5689dfb07bc7Smrg free(target[n]); 5690dfb07bc7Smrg } 5691dfb07bc7Smrg free(target); 5692dfb07bc7Smrg *targetp = 0; 5693dfb07bc7Smrg } 5694dfb07bc7Smrg } 5695dfb07bc7Smrg} 5696dfb07bc7Smrg 5697dfb07bc7Smrgvoid 5698dfb07bc7SmrgfreeFontLists(VTFontList * lists) 5699dfb07bc7Smrg{ 5700dfb07bc7Smrg int which; 5701dfb07bc7Smrg 5702dfb07bc7Smrg TRACE(("freeFontLists\n")); 5703dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5704dfb07bc7Smrg char ***target = 0; 5705dfb07bc7Smrg switch (which) { 5706dfb07bc7Smrg case fNorm: 5707dfb07bc7Smrg target = &(lists->list_n); 5708dfb07bc7Smrg break; 5709dfb07bc7Smrg case fBold: 5710dfb07bc7Smrg target = &(lists->list_b); 5711dfb07bc7Smrg break; 5712dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5713dfb07bc7Smrg case fItal: 5714dfb07bc7Smrg target = &(lists->list_i); 5715dfb07bc7Smrg break; 5716d4fba8b9Smrg case fBtal: 5717d4fba8b9Smrg target = &(lists->list_bi); 5718d4fba8b9Smrg break; 5719dfb07bc7Smrg#endif 5720dfb07bc7Smrg#if OPT_WIDE_CHARS 5721dfb07bc7Smrg case fWide: 5722dfb07bc7Smrg target = &(lists->list_w); 5723dfb07bc7Smrg break; 5724dfb07bc7Smrg case fWBold: 5725dfb07bc7Smrg target = &(lists->list_wb); 5726dfb07bc7Smrg break; 5727dfb07bc7Smrg case fWItal: 5728dfb07bc7Smrg target = &(lists->list_wi); 5729dfb07bc7Smrg break; 5730d4fba8b9Smrg case fWBtal: 5731d4fba8b9Smrg target = &(lists->list_wbi); 5732d4fba8b9Smrg break; 5733dfb07bc7Smrg#endif 5734dfb07bc7Smrg default: 5735dfb07bc7Smrg target = 0; 5736dfb07bc7Smrg break; 5737dfb07bc7Smrg } 5738dfb07bc7Smrg freeFontList(target); 5739dfb07bc7Smrg } 5740dfb07bc7Smrg} 5741dfb07bc7Smrg 5742dfb07bc7Smrg/* 5743dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class. 5744dfb07bc7Smrg * XXX make this allocate the font on demand. 5745dfb07bc7Smrg */ 5746dfb07bc7SmrgXTermFonts * 5747dfb07bc7SmrggetNormalFont(TScreen *screen, int which) 5748dfb07bc7Smrg{ 5749dfb07bc7Smrg XTermFonts *result = 0; 5750dfb07bc7Smrg if (which >= 0 && which < fMAX) 5751d4fba8b9Smrg result = GetNormalFont(screen, which); 5752dfb07bc7Smrg return result; 5753dfb07bc7Smrg} 5754dfb07bc7Smrg 5755dfb07bc7Smrg#if OPT_DEC_CHRSET 5756dfb07bc7SmrgXTermFonts * 5757dfb07bc7SmrggetDoubleFont(TScreen *screen, int which) 5758dfb07bc7Smrg{ 5759dfb07bc7Smrg XTermFonts *result = 0; 5760dfb07bc7Smrg if ((int) which >= 0 && which < NUM_CHRSET) 5761d4fba8b9Smrg result = GetDoubleFont(screen, which); 5762d4fba8b9Smrg return result; 5763d4fba8b9Smrg} 5764d4fba8b9Smrg 5765d4fba8b9Smrg#if OPT_RENDERFONT 5766d1603babSmrgvoid 5767d1603babSmrggetDoubleXftFont(XTermDraw * params, XTermXftFonts *data, unsigned chrset, unsigned attr_flags) 5768d4fba8b9Smrg{ 5769d4fba8b9Smrg XtermWidget xw = params->xw; 5770d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 5771d4fba8b9Smrg XftPattern *top_pattern; 5772d4fba8b9Smrg int fontnum = screen->menu_font_number; 5773d4fba8b9Smrg const char *face_name = getFaceName(xw, False); 5774d4fba8b9Smrg 5775d4fba8b9Smrg if (chrset != CSET_SWL 5776d4fba8b9Smrg && (top_pattern = XftNameParse(face_name)) != 0) { 5777d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 5778d4fba8b9Smrg XftPattern *sub_pattern = XftPatternDuplicate(top_pattern); 5779d1603babSmrg const char *category = "doublesize"; 5780d4fba8b9Smrg 5781d4fba8b9Smrg switch (chrset) { 5782d4fba8b9Smrg case CSET_DHL_TOP: 5783d1603babSmrg category = "DHL_TOP"; 5784d1603babSmrg goto double_high; 5785d4fba8b9Smrg case CSET_DHL_BOT: 5786d1603babSmrg category = "DHL_BOT"; 5787d1603babSmrg double_high: 5788d4fba8b9Smrg face_size *= 2; 5789d4fba8b9Smrg XftPatternBuild(sub_pattern, 5790d4fba8b9Smrg NormXftPattern, 5791d4fba8b9Smrg (void *) 0); 5792d4fba8b9Smrg break; 5793d4fba8b9Smrg case CSET_DWL: 5794d1603babSmrg category = "DWL"; 5795d4fba8b9Smrg XftPatternBuild(sub_pattern, 5796d4fba8b9Smrg NormXftPattern, 5797d4fba8b9Smrg FC_ASPECT, XftTypeDouble, 2.0, 5798d4fba8b9Smrg (void *) 0); 5799d4fba8b9Smrg break; 5800d4fba8b9Smrg } 5801d4fba8b9Smrg if (attr_flags & BOLD) { 5802d4fba8b9Smrg XftPatternBuild(sub_pattern, 5803d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, 5804d4fba8b9Smrg (void *) 0); 5805d4fba8b9Smrg } 5806d1603babSmrg xtermOpenXft(xw, data, 0, face_name, sub_pattern, category); 5807d1603babSmrg data->pattern = sub_pattern; 5808d4fba8b9Smrg } 5809dfb07bc7Smrg} 5810dfb07bc7Smrg#endif 5811d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */ 5812dfb07bc7Smrg 5813dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5814dfb07bc7SmrgXTermFonts * 5815dfb07bc7SmrggetItalicFont(TScreen *screen, int which) 5816dfb07bc7Smrg{ 5817dfb07bc7Smrg XTermFonts *result = 0; 5818dfb07bc7Smrg#if OPT_WIDE_ATTRS 5819dfb07bc7Smrg if (which >= 0 && which < fMAX) 5820d4fba8b9Smrg result = GetItalicFont(screen, which); 5821dfb07bc7Smrg#else 5822dfb07bc7Smrg (void) screen; 5823dfb07bc7Smrg (void) which; 5824dfb07bc7Smrg#endif 5825dfb07bc7Smrg return result; 5826dfb07bc7Smrg} 5827dfb07bc7Smrg#endif 5828dfb07bc7Smrg 5829dfb07bc7Smrg#if OPT_RENDERFONT 5830dfb07bc7Smrg/* 5831dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font. 5832dfb07bc7Smrg * XXX make this allocate the font on demand. 5833dfb07bc7Smrg */ 5834dfb07bc7SmrgXTermXftFonts * 5835dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum) 5836dfb07bc7Smrg{ 5837dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 5838dfb07bc7Smrg XTermXftFonts *result = 0; 5839dfb07bc7Smrg if (fontnum >= 0 && fontnum < NMENUFONTS) { 5840dfb07bc7Smrg switch ((VTFontEnum) which) { 5841dfb07bc7Smrg case fNorm: 5842dfb07bc7Smrg result = &(screen->renderFontNorm[fontnum]); 5843dfb07bc7Smrg break; 5844dfb07bc7Smrg case fBold: 5845dfb07bc7Smrg result = &(screen->renderFontBold[fontnum]); 5846dfb07bc7Smrg break; 5847dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5848dfb07bc7Smrg case fItal: 5849dfb07bc7Smrg result = &(screen->renderFontItal[fontnum]); 5850dfb07bc7Smrg break; 5851d4fba8b9Smrg case fBtal: 5852d4fba8b9Smrg result = &(screen->renderFontBtal[fontnum]); 5853d4fba8b9Smrg break; 5854dfb07bc7Smrg#endif 5855dfb07bc7Smrg#if OPT_WIDE_CHARS 5856dfb07bc7Smrg case fWide: 5857dfb07bc7Smrg result = &(screen->renderWideNorm[fontnum]); 5858dfb07bc7Smrg break; 5859dfb07bc7Smrg case fWBold: 5860dfb07bc7Smrg result = &(screen->renderWideBold[fontnum]); 5861dfb07bc7Smrg break; 5862dfb07bc7Smrg case fWItal: 5863dfb07bc7Smrg result = &(screen->renderWideItal[fontnum]); 5864dfb07bc7Smrg break; 5865d4fba8b9Smrg case fWBtal: 5866d4fba8b9Smrg result = &(screen->renderWideBtal[fontnum]); 5867d4fba8b9Smrg break; 5868dfb07bc7Smrg#endif 5869dfb07bc7Smrg case fMAX: 5870dfb07bc7Smrg break; 5871dfb07bc7Smrg } 5872dfb07bc7Smrg } 5873dfb07bc7Smrg return result; 5874dfb07bc7Smrg} 5875dfb07bc7Smrg 5876d1603babSmrgconst char * 5877d1603babSmrgwhichXftFonts(XtermWidget xw, XTermXftFonts *data) 5878d1603babSmrg{ 5879d1603babSmrg TScreen *screen = TScreenOf(xw); 5880d1603babSmrg const char *result = "?"; 5881d1603babSmrg#define CHECK(name) ((data >= &(screen->name[0])) && (data < &(screen->name[NMENUFONTS]))) result = #name 5882d1603babSmrg if CHECK 5883d1603babSmrg (renderFontNorm); 5884d1603babSmrg else if CHECK 5885d1603babSmrg (renderFontBold); 5886d1603babSmrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5887d1603babSmrg else if CHECK 5888d1603babSmrg (renderFontItal); 5889d1603babSmrg else if CHECK 5890d1603babSmrg (renderFontBtal); 5891d1603babSmrg#endif 5892d1603babSmrg#if OPT_WIDE_CHARS 5893d1603babSmrg else if CHECK 5894d1603babSmrg (renderWideNorm); 5895d1603babSmrg else if CHECK 5896d1603babSmrg (renderWideBold); 5897d1603babSmrg else if CHECK 5898d1603babSmrg (renderWideItal); 5899d1603babSmrg else if CHECK 5900d1603babSmrg (renderWideBtal); 5901d1603babSmrg#endif 5902d1603babSmrg#if OPT_DEC_CHRSET 5903d1603babSmrg#if OPT_RENDERFONT 5904d1603babSmrg else { 5905d1603babSmrg int n; 5906d1603babSmrg for (n = 0; n < NUM_CHRSET; ++n) { 5907d1603babSmrg if (data == &screen->double_xft_fonts[n]) { 5908d1603babSmrg result = "double_xft_fonts"; 5909d1603babSmrg break; 5910d1603babSmrg } 5911d1603babSmrg } 5912d1603babSmrg } 5913d1603babSmrg#endif 5914d1603babSmrg#endif /* OPT_DEC_CHRSET */ 5915d1603babSmrg return result; 5916d1603babSmrg} 5917d1603babSmrg 5918dfb07bc7SmrgXftFont * 5919dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum) 5920dfb07bc7Smrg{ 5921d4fba8b9Smrg XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum); 5922dfb07bc7Smrg XftFont *result = 0; 5923dfb07bc7Smrg if (data != 0) 5924d1603babSmrg result = XftFp(data); 5925dfb07bc7Smrg return result; 5926dfb07bc7Smrg} 5927dfb07bc7Smrg#endif 5928dfb07bc7Smrg 5929dfb07bc7Smrgconst char * 5930dfb07bc7SmrgwhichFontEnum(VTFontEnum value) 5931dfb07bc7Smrg{ 5932dfb07bc7Smrg const char *result = "?"; 5933dfb07bc7Smrg#define DATA(name) case name: result = #name; break 5934dfb07bc7Smrg switch (value) { 5935dfb07bc7Smrg DATA(fNorm); 5936dfb07bc7Smrg DATA(fBold); 5937dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5938dfb07bc7Smrg DATA(fItal); 5939d4fba8b9Smrg DATA(fBtal); 5940dfb07bc7Smrg#endif 5941dfb07bc7Smrg#if OPT_WIDE_CHARS 5942dfb07bc7Smrg DATA(fWide); 5943dfb07bc7Smrg DATA(fWBold); 5944dfb07bc7Smrg DATA(fWItal); 5945d4fba8b9Smrg DATA(fWBtal); 5946dfb07bc7Smrg#endif 5947dfb07bc7Smrg DATA(fMAX); 5948dfb07bc7Smrg } 5949dfb07bc7Smrg#undef DATA 5950dfb07bc7Smrg return result; 5951dfb07bc7Smrg} 5952dfb07bc7Smrg 5953dfb07bc7Smrgconst char * 5954dfb07bc7SmrgwhichFontList(XtermWidget xw, VTFontList * value) 5955dfb07bc7Smrg{ 5956dfb07bc7Smrg const char *result = "?"; 5957dfb07bc7Smrg if (value == &(xw->work.fonts.x11)) 5958dfb07bc7Smrg result = "x11_fontnames"; 5959dfb07bc7Smrg#if OPT_RENDERFONT 5960dfb07bc7Smrg else if (value == &(xw->work.fonts.xft)) 5961dfb07bc7Smrg result = "xft_fontnames"; 5962dfb07bc7Smrg#endif 5963dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5964dfb07bc7Smrg else if (value == &(xw->screen.cacheVTFonts.fonts.x11)) 5965dfb07bc7Smrg result = "cached_fontnames"; 5966dfb07bc7Smrg#endif 5967dfb07bc7Smrg return result; 5968dfb07bc7Smrg} 5969dfb07bc7Smrg 5970dfb07bc7Smrgstatic const char * 5971dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value) 5972dfb07bc7Smrg{ 5973dfb07bc7Smrg const char *result = 0; 5974dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name 5975dfb07bc7Smrg DATA(list_n); 5976dfb07bc7Smrg DATA(list_b); 5977dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5978dfb07bc7Smrg DATA(list_i); 5979d4fba8b9Smrg DATA(list_bi); 5980dfb07bc7Smrg#endif 5981dfb07bc7Smrg#if OPT_WIDE_CHARS 5982dfb07bc7Smrg DATA(list_w); 5983dfb07bc7Smrg DATA(list_wb); 5984dfb07bc7Smrg DATA(list_wi); 5985d4fba8b9Smrg DATA(list_wbi); 5986dfb07bc7Smrg#endif 5987dfb07bc7Smrg#undef DATA 5988dfb07bc7Smrg return result; 5989dfb07bc7Smrg} 5990dfb07bc7Smrg 5991dfb07bc7Smrgconst char * 5992dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value) 5993dfb07bc7Smrg{ 5994dfb07bc7Smrg const char *result = 0; 5995dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value)) 5996dfb07bc7Smrg if (DATA(work.fonts.x11) == 0) { 5997dfb07bc7Smrg#if OPT_RENDERFONT 5998dfb07bc7Smrg if (DATA(work.fonts.xft) == 0) 5999dfb07bc7Smrg#endif 6000dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 6001dfb07bc7Smrg if (DATA(screen.cacheVTFonts.fonts.x11) == 0) 6002dfb07bc7Smrg#endif 6003dfb07bc7Smrg result = "?"; 6004dfb07bc7Smrg } 6005dfb07bc7Smrg#undef DATA 6006dfb07bc7Smrg return result; 6007dfb07bc7Smrg} 6008