fontutils.c revision d1603bab
1/* $XTermId: fontutils.c,v 1.773 2023/05/08 00:00:38 tom Exp $ */ 2 3/* 4 * Copyright 1998-2022,2023 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33/* 34 * A portion of this module (for FontNameProperties) was adapted from EMU 1.3; 35 * it constructs font names with specific properties changed, e.g., for bold 36 * and double-size characters. 37 */ 38 39#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field) 40 41#include <fontutils.h> 42#include <X11/Xmu/Drawing.h> 43#include <X11/Xmu/CharSet.h> 44 45#include <main.h> 46#include <data.h> 47#include <menu.h> 48#include <xstrings.h> 49#include <xterm.h> 50 51#include <stdio.h> 52#include <ctype.h> 53 54#define USE_FC_COLOR 0 55#if OPT_RENDERFONT 56#if XftVersion > 20304 57#undef USE_FC_COLOR 58#define USE_FC_COLOR 1 59#endif 60#endif 61 62#define FcOK(func) (func == FcResultMatch) 63 64#define NoFontWarning(data) (data)->warn = fwAlways 65 66#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 67#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((double)((screen)->scale_height * (float) (src))) 68 69/* from X11/Xlibint.h - not all vendors install this file */ 70#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 71 (((cs)->rbearing|(cs)->lbearing| \ 72 (cs)->ascent|(cs)->descent) == 0)) 73 74#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 75{ \ 76 cs = 0; \ 77 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 78 if (fs->per_char == NULL) { \ 79 cs = &fs->min_bounds; \ 80 } else { \ 81 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 82 } \ 83 if (CI_NONEXISTCHAR(cs)) cs = 0; \ 84 } \ 85} 86 87#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 88{ \ 89 cs = 0; \ 90 if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 91 col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 92 if (fs->per_char == NULL) { \ 93 cs = &fs->min_bounds; \ 94 } else { \ 95 cs = &fs->per_char[((row - fs->min_byte1) * \ 96 (fs->max_char_or_byte2 - \ 97 fs->min_char_or_byte2 + 1)) + \ 98 (col - fs->min_char_or_byte2)]; \ 99 } \ 100 if (CI_NONEXISTCHAR(cs)) cs = 0; \ 101 } \ 102} 103 104#define FREE_FNAME(field) \ 105 if (fonts == 0 || new_fnames.field != fonts->field) { \ 106 FREE_STRING(new_fnames.field); \ 107 new_fnames.field = 0; \ 108 } 109 110/* 111 * A structure to hold the relevant properties from a font 112 * we need to make a well formed font name for it. 113 */ 114typedef struct { 115 /* registry, foundry, family */ 116 const char *beginning; 117 /* weight */ 118 const char *weight; 119 /* slant */ 120 const char *slant; 121 /* wideness */ 122 const char *wideness; 123 /* add style */ 124 const char *add_style; 125 int pixel_size; 126 const char *point_size; 127 int res_x; 128 int res_y; 129 const char *spacing; 130 int average_width; 131 /* charset registry, charset encoding */ 132 char *end; 133} FontNameProperties; 134 135#if OPT_WIDE_CHARS && (OPT_RENDERFONT || (OPT_TRACE > 1)) 136#define MY_UCS(code,high,wide,name) { code, high, wide, #name } 137static const struct { 138 unsigned code, high, wide; 139 const char *name; 140} unicode_boxes[] = { 141 142 MY_UCS(0x2500, 0, 1, box drawings light horizontal), 143 MY_UCS(0x2502, 1, 0, box drawings light vertical), 144 MY_UCS(0x250c, 2, 2, box drawings light down and right), 145 MY_UCS(0x2510, 2, 2, box drawings light down and left), 146 MY_UCS(0x2514, 2, 2, box drawings light up and right), 147 MY_UCS(0x2518, 2, 2, box drawings light up and left), 148 MY_UCS(0x251c, 1, 2, box drawings light vertical and right), 149 MY_UCS(0x2524, 1, 2, box drawings light vertical and left), 150 MY_UCS(0x252c, 2, 1, box drawings light down and horizontal), 151 MY_UCS(0x2534, 2, 1, box drawings light up and horizontal), 152 MY_UCS(0x253c, 1, 1, box drawings light vertical and horizontal), 153 { 154 0, 0, 0, NULL 155 } 156}; 157 158#undef MY_UCS 159#endif /* OPT_WIDE_CHARS */ 160 161#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 162static Boolean merge_sublist(char ***, char **); 163#endif 164 165static void save2FontList(XtermWidget, const char *, XtermFontNames *, 166 VTFontEnum, const char *, Bool, Bool); 167 168#if OPT_RENDERFONT 169static void fillInFaceSize(XtermWidget, int); 170#endif 171 172#if OPT_REPORT_FONTS && OPT_TRACE 173static void 174report_fonts(const char *fmt, ...) 175{ 176 va_list ap; 177 va_start(ap, fmt); 178 vfprintf(stdout, fmt, ap); 179 va_end(ap); 180#if OPT_TRACE 181 va_start(ap, fmt); 182 TraceVA(fmt, ap); 183 va_end(ap); 184#endif 185} 186 187#define ReportFonts report_fonts 188#else 189#define ReportFonts printf 190#endif 191 192#if OPT_TRACE 193static void 194set_font_height(TScreen *screen, VTwin *win, int height) 195{ 196 SetFontHeight(screen, win, height); 197 TRACE(("SetFontHeight %d\n", win->f_height)); 198#undef SetFontHeight 199#define SetFontHeight(screen, win, height) set_font_height(screen, win, height) 200} 201 202static void 203set_font_width(TScreen *screen, VTwin *win, int width) 204{ 205 (void) screen; 206 SetFontWidth(screen, win, width); 207 TRACE(("SetFontWidth %d\n", win->f_width)); 208#undef SetFontWidth 209#define SetFontWidth(screen, win, width) set_font_width(screen, win, width) 210} 211#endif 212 213#if OPT_REPORT_FONTS || OPT_WIDE_CHARS 214static unsigned 215countGlyphs(XFontStruct *fp) 216{ 217 unsigned count = 0; 218 219 if (fp != 0) { 220 if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 221 count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1; 222 } else if (fp->min_char_or_byte2 < 256 223 && fp->max_char_or_byte2 < 256) { 224 unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 225 unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 226 count = last + 1 - first; 227 } 228 } 229 return count; 230} 231#endif 232 233#if OPT_WIDE_CHARS 234/* 235 * Verify that the wide-bold font is at least a bold font with roughly as many 236 * glyphs as the wide font. The counts should be the same, but settle for 237 * filtering out the worst of the font mismatches. 238 */ 239static Bool 240compatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs) 241{ 242 unsigned count_w = countGlyphs(wfs); 243 unsigned count_wb = countGlyphs(wbfs); 244 if (count_w <= 256 || 245 count_wb <= 256 || 246 ((count_w / 4) * 3) > count_wb) { 247 TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 248 count_w, count_wb)); 249 return False; 250 } 251 return True; 252} 253#endif /* OPT_WIDE_CHARS */ 254 255#if OPT_BOX_CHARS 256static void 257setupPackedFonts(XtermWidget xw) 258{ 259 TScreen *screen = TScreenOf(xw); 260 Bool value = False; 261 262#if OPT_RENDERFONT 263 if (xw->work.render_font == True) { 264 int e; 265 266 for (e = 0; e < fMAX; ++e) { 267 XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number); 268 if (data != 0) { 269 if (data->font_info.mixed) { 270 screen->allow_packing = True; 271 break; 272 } 273 } 274 } 275 } 276#endif /* OPT_RENDERFONT */ 277 278 value = screen->allow_packing; 279 280 SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 281} 282#endif 283 284typedef struct _nameList { 285 struct _nameList *next; 286 char *name; 287} NameList; 288 289static NameList *derived_fonts; 290 291static Boolean 292is_derived_font_name(const char *name) 293{ 294 Boolean result = False; 295 NameList *list; 296 if (!IsEmpty(name)) { 297 for (list = derived_fonts; list != 0; list = list->next) { 298 if (!x_strcasecmp(name, list->name)) { 299 result = True; 300 break; 301 } 302 } 303 } 304 return result; 305} 306 307void 308xtermDerivedFont(const char *name) 309{ 310 if (!IsEmpty(name) && !is_derived_font_name(name)) { 311 NameList *list = TypeCalloc(NameList); 312 list->name = x_strdup(name); 313 list->next = derived_fonts; 314 derived_fonts = list; 315 } 316} 317 318/* 319 * Returns the fields from start to stop in a dash- separated string. This 320 * function will modify the source, putting '\0's in the appropriate place and 321 * moving the beginning forward to after the '\0' 322 * 323 * This will NOT work for the last field (but we won't need it). 324 */ 325static char * 326n_fields(char **source, int start, int stop) 327{ 328 int i; 329 char *str, *str1; 330 331 /* 332 * find the start-1th dash 333 */ 334 for (i = start - 1, str = *source; i; i--, str++) { 335 if ((str = strchr(str, '-')) == 0) 336 return 0; 337 } 338 339 /* 340 * find the stopth dash 341 */ 342 for (i = stop - start + 1, str1 = str; i; i--, str1++) { 343 if ((str1 = strchr(str1, '-')) == 0) 344 return 0; 345 } 346 347 /* 348 * put a \0 at the end of the fields 349 */ 350 *(str1 - 1) = '\0'; 351 352 /* 353 * move source forward 354 */ 355 *source = str1; 356 357 return str; 358} 359 360static Boolean 361check_fontname(const char *name) 362{ 363 Boolean result = True; 364 365 if (IsEmpty(name)) { 366 TRACE(("fontname missing\n")); 367 result = False; 368 } 369 return result; 370} 371 372/* 373 * Gets the font properties from a given font structure. We use the FONT name 374 * to find them out, since that seems easier. 375 * 376 * Returns a pointer to a static FontNameProperties structure 377 * or NULL on error. 378 */ 379static FontNameProperties * 380get_font_name_props(Display *dpy, XFontStruct *fs, char **result) 381{ 382 static FontNameProperties props; 383 static char *last_name; 384 385 Atom fontatom; 386 char *name; 387 char *str; 388 389 if (fs == NULL) 390 return NULL; 391 392 /* 393 * first get the full font name 394 */ 395 name = 0; 396 fontatom = XInternAtom(dpy, "FONT", False); 397 if (fontatom != 0) { 398 XFontProp *fp; 399 int i; 400 401 for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 402 if (fp->name == fontatom) { 403 name = XGetAtomName(dpy, fp->card32); 404 break; 405 } 406 } 407 } 408 409 if (name == 0) 410 return 0; 411 412 /* 413 * XGetAtomName allocates memory - don't leak 414 */ 415 XFree(last_name); 416 last_name = name; 417 418 if (result != 0) { 419 if (!check_fontname(name)) 420 return 0; 421 free(*result); 422 *result = x_strdup(name); 423 } 424 425 /* 426 * Now split it up into parts and put them in 427 * their places. Since we are using parts of 428 * the original string, we must not free the Atom Name 429 */ 430 431 /* registry, foundry, family */ 432 if ((props.beginning = n_fields(&name, 1, 3)) == 0) 433 return 0; 434 435 /* weight is the next */ 436 if ((props.weight = n_fields(&name, 1, 1)) == 0) 437 return 0; 438 439 /* slant */ 440 if ((props.slant = n_fields(&name, 1, 1)) == 0) 441 return 0; 442 443 /* width */ 444 if ((props.wideness = n_fields(&name, 1, 1)) == 0) 445 return 0; 446 447 /* add style */ 448 if ((props.add_style = n_fields(&name, 1, 1)) == 0) 449 return 0; 450 451 /* pixel size */ 452 if ((str = n_fields(&name, 1, 1)) == 0) 453 return 0; 454 if ((props.pixel_size = atoi(str)) == 0) 455 return 0; 456 457 /* point size */ 458 if ((props.point_size = n_fields(&name, 1, 1)) == 0) 459 return 0; 460 461 /* res_x */ 462 if ((str = n_fields(&name, 1, 1)) == 0) 463 return 0; 464 if ((props.res_x = atoi(str)) == 0) 465 return 0; 466 467 /* res_y */ 468 if ((str = n_fields(&name, 1, 1)) == 0) 469 return 0; 470 if ((props.res_y = atoi(str)) == 0) 471 return 0; 472 473 /* spacing */ 474 if ((props.spacing = n_fields(&name, 1, 1)) == 0) 475 return 0; 476 477 /* average width */ 478 if ((str = n_fields(&name, 1, 1)) == 0) 479 return 0; 480 if ((props.average_width = atoi(str)) == 0) 481 return 0; 482 483 /* the rest: charset registry and charset encoding */ 484 props.end = name; 485 486 return &props; 487} 488 489#define ALLOCHUNK(n) ((n | 127) + 1) 490 491static void 492alloca_fontname(char **result, size_t next) 493{ 494 size_t last = (*result != 0) ? strlen(*result) : 0; 495 size_t have = (*result != 0) ? ALLOCHUNK(last) : 0; 496 size_t want = last + next + 2; 497 498 if (want >= have) { 499 char *save = *result; 500 want = ALLOCHUNK(want); 501 if (last != 0) { 502 *result = TypeRealloc(char, want, *result); 503 if (*result == 0) 504 free(save); 505 } else { 506 if ((*result = TypeMallocN(char, want)) != 0) { 507 free(save); 508 **result = '\0'; 509 } 510 } 511 } 512} 513 514static void 515append_fontname_str(char **result, const char *value) 516{ 517 if (value == 0) 518 value = "*"; 519 alloca_fontname(result, strlen(value)); 520 if (*result != 0) { 521 if (**result != '\0') 522 strcat(*result, "-"); 523 strcat(*result, value); 524 } 525} 526 527static void 528append_fontname_num(char **result, int value) 529{ 530 if (value < 0) { 531 append_fontname_str(result, "*"); 532 } else { 533 char temp[100]; 534 sprintf(temp, "%d", value); 535 append_fontname_str(result, temp); 536 } 537} 538 539/* 540 * Take the given font props and try to make a well formed font name specifying 541 * the same base font and size and everything, but with different weight/width 542 * according to the parameters. The return value is allocated, should be freed 543 * by the caller. 544 */ 545static char * 546derive_font_name(FontNameProperties *props, 547 const char *use_weight, 548 int use_average_width, 549 const char *use_encoding) 550{ 551 char *result = 0; 552 553 append_fontname_str(&result, props->beginning); 554 append_fontname_str(&result, use_weight); 555 append_fontname_str(&result, props->slant); 556 append_fontname_str(&result, 0); 557 append_fontname_str(&result, 0); 558 append_fontname_num(&result, props->pixel_size); 559 append_fontname_str(&result, props->point_size); 560 append_fontname_num(&result, props->res_x); 561 append_fontname_num(&result, props->res_y); 562 append_fontname_str(&result, props->spacing); 563 append_fontname_num(&result, use_average_width); 564 append_fontname_str(&result, use_encoding); 565 566 xtermDerivedFont(result); 567 return result; 568} 569 570static char * 571bold_font_name(FontNameProperties *props, int use_average_width) 572{ 573 return derive_font_name(props, "bold", use_average_width, props->end); 574} 575 576#if OPT_WIDE_ATTRS 577static char * 578italic_font_name(FontNameProperties *props, const char *slant) 579{ 580 FontNameProperties myprops = *props; 581 myprops.slant = slant; 582 return derive_font_name(&myprops, props->weight, myprops.average_width, props->end); 583} 584 585static Boolean 586open_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data) 587{ 588 static const char *const slant[] = 589 { 590 "o", 591 "i" 592 }; 593 Cardinal pass; 594 Boolean result = False; 595 596 NoFontWarning(data); 597 for (pass = 0; pass < XtNumber(slant); ++pass) { 598 char *name; 599 if ((name = italic_font_name(fp, slant[pass])) != 0) { 600 TRACE(("open_italic_font %s %s\n", 601 whichFontEnum((VTFontEnum) n), name)); 602 if (xtermOpenFont(xw, name, data, NULL, False)) { 603 result = (data->fs != 0); 604#if OPT_REPORT_FONTS 605 if (resource.reportFonts) { 606 ReportFonts("opened italic version of %s:\n\t%s\n", 607 whichFontEnum((VTFontEnum) n), 608 name); 609 } 610#endif 611 } 612 free(name); 613 if (result) 614 break; 615 } 616 } 617#if OPT_TRACE 618 if (result) { 619 XFontStruct *fs = data->fs; 620 if (fs != 0) { 621 TRACE(("...actual size %dx%d (ascent %d, descent %d)\n", 622 fs->ascent + 623 fs->descent, 624 fs->max_bounds.width, 625 fs->ascent, 626 fs->descent)); 627 } 628 } 629#endif 630 return result; 631} 632#endif 633 634#if OPT_WIDE_CHARS 635#define derive_wide_font(props, weight) \ 636 derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 637 638static char * 639wide_font_name(FontNameProperties *props) 640{ 641 return derive_wide_font(props, "medium"); 642} 643 644static char * 645widebold_font_name(FontNameProperties *props) 646{ 647 return derive_wide_font(props, "bold"); 648} 649#endif /* OPT_WIDE_CHARS */ 650 651#if OPT_DEC_CHRSET 652/* 653 * Take the given font props and try to make a well formed font name specifying 654 * the same base font but changed depending on the given attributes and chrset. 655 * 656 * For double width fonts, we just double the X-resolution, for double height 657 * fonts we double the pixel-size and Y-resolution 658 */ 659char * 660xtermSpecialFont(XTermDraw * params) 661{ 662 TScreen *screen = TScreenOf(params->xw); 663#if OPT_TRACE 664 static char old_spacing[80]; 665 static FontNameProperties old_props; 666#endif 667 FontNameProperties *props; 668 char *result = 0; 669 const char *weight; 670 int pixel_size; 671 int res_x; 672 int res_y; 673 674 props = get_font_name_props(screen->display, 675 GetNormalFont(screen, fNorm)->fs, 0); 676 if (props == 0) 677 return result; 678 679 pixel_size = props->pixel_size; 680 res_x = props->res_x; 681 res_y = props->res_y; 682 if (params->attr_flags & BOLD) 683 weight = "bold"; 684 else 685 weight = props->weight; 686 687 if (CSET_DOUBLE(params->this_chrset)) 688 res_x *= 2; 689 690 if (params->this_chrset == CSET_DHL_TOP 691 || params->this_chrset == CSET_DHL_BOT) { 692 res_y *= 2; 693 pixel_size *= 2; 694 } 695#if OPT_TRACE 696 if (old_props.res_x != res_x 697 || old_props.res_x != res_y 698 || old_props.pixel_size != pixel_size 699 || strcmp(old_props.spacing, props->spacing)) { 700 TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n", 701 params->attr_flags, params->draw_flags, params->this_chrset)); 702 TRACE(("res_x = %d\n", res_x)); 703 TRACE(("res_y = %d\n", res_y)); 704 TRACE(("point_size = %s\n", props->point_size)); 705 TRACE(("pixel_size = %d\n", pixel_size)); 706 TRACE(("spacing = %s\n", props->spacing)); 707 old_props.res_x = res_x; 708 old_props.res_y = res_y; 709 old_props.pixel_size = pixel_size; 710 old_props.spacing = old_spacing; 711 sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 712 } 713#endif 714 715 append_fontname_str(&result, props->beginning); 716 append_fontname_str(&result, weight); 717 append_fontname_str(&result, props->slant); 718 append_fontname_str(&result, props->wideness); 719 append_fontname_str(&result, props->add_style); 720 append_fontname_num(&result, pixel_size); 721 append_fontname_str(&result, props->point_size); 722 append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x); 723 append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y); 724 append_fontname_str(&result, props->spacing); 725 append_fontname_str(&result, 0); 726 append_fontname_str(&result, props->end); 727 728 xtermDerivedFont(result); 729 return result; 730} 731#endif /* OPT_DEC_CHRSET */ 732 733/* 734 * Case-independent comparison for font-names, including wildcards. 735 * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 736 * to use it). 737 */ 738static Bool 739same_font_name(const char *pattern, const char *match) 740{ 741 Bool result = False; 742 743 if (pattern && match) { 744 while (*pattern && *match) { 745 if (*pattern == *match) { 746 pattern++; 747 match++; 748 } else if (*pattern == '*' || *match == '*') { 749 if (same_font_name(pattern + 1, match)) { 750 return True; 751 } else if (same_font_name(pattern, match + 1)) { 752 return True; 753 } else { 754 return False; 755 } 756 } else { 757 int p = x_toupper(*pattern++); 758 int m = x_toupper(*match++); 759 if (p != m) 760 return False; 761 } 762 } 763 result = (*pattern == *match); /* both should be NUL */ 764 } 765 return result; 766} 767 768/* 769 * Double-check the fontname that we asked for versus what the font server 770 * actually gave us. The larger fixed fonts do not always have a matching bold 771 * font, and the font server may try to scale another font or otherwise 772 * substitute a mismatched font. 773 * 774 * If we cannot get what we requested, we will fallback to the original 775 * behavior, which simulates bold by overstriking each character at one pixel 776 * offset. 777 */ 778static int 779got_bold_font(Display *dpy, XFontStruct *fs, String requested) 780{ 781 char *actual = 0; 782 int got; 783 784 if (get_font_name_props(dpy, fs, &actual) == 0) 785 got = 0; 786 else 787 got = same_font_name(requested, actual); 788 free(actual); 789 return got; 790} 791 792/* 793 * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able 794 * to check for missing glyphs in a comparable manner. 795 */ 796static int 797comparable_metrics(XFontStruct *normal, XFontStruct *bold) 798{ 799#define DATA "comparable_metrics: " 800 int result = 0; 801 802 if (normal == 0 || bold == 0) { 803 ; 804 } else if (normal->all_chars_exist) { 805 if (bold->all_chars_exist) { 806 result = 1; 807 } else { 808 TRACE((DATA "all chars exist in normal font, but not in bold\n")); 809 } 810 } else if (normal->per_char != 0) { 811 if (bold->per_char != 0) { 812 result = 1; 813 } else { 814 TRACE((DATA "normal font has per-char metrics, but not bold\n")); 815 } 816 } else { 817 TRACE((DATA "normal font is not very good!\n")); 818 result = 1; /* give in (we're not going in reverse) */ 819 } 820 return result; 821#undef DATA 822} 823 824/* 825 * If the font server tries to adjust another font, it may not adjust it 826 * properly. Check that the bounding boxes are compatible. Otherwise we'll 827 * leave trash on the display when we mix normal and bold fonts. 828 */ 829static int 830same_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs) 831{ 832 TScreen *screen = TScreenOf(xw); 833 int result = 0; 834 835 if (nfs != 0 && bfs != 0) { 836 TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 837 nfs->ascent + nfs->descent, 838 bfs->ascent + bfs->descent, 839 nfs->min_bounds.width, bfs->min_bounds.width, 840 nfs->max_bounds.width, bfs->max_bounds.width)); 841 result = screen->free_bold_box 842 || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 843 && (nfs->min_bounds.width == bfs->min_bounds.width 844 || nfs->min_bounds.width == bfs->min_bounds.width + 1) 845 && (nfs->max_bounds.width == bfs->max_bounds.width 846 || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 847 } 848 return result; 849} 850 851/* 852 * Check if the font looks like it has fixed width 853 */ 854static int 855is_fixed_font(XFontStruct *fs) 856{ 857 if (fs) 858 return (fs->min_bounds.width == fs->max_bounds.width); 859 return 1; 860} 861 862static int 863differing_widths(XFontStruct *a, XFontStruct *b) 864{ 865 int result = 0; 866 if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width) 867 result = 1; 868 return result; 869} 870 871/* 872 * Check if the font looks like a double width font (i.e. contains 873 * characters of width X and 2X 874 */ 875#if OPT_WIDE_CHARS 876static int 877is_double_width_font(XFontStruct *fs) 878{ 879 return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width)); 880} 881#else 882#define is_double_width_font(fs) 0 883#endif 884 885#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 886#define HALF_WIDTH_TEST_STRING "1234567890" 887 888/* '1234567890' in Chinese characters in UTF-8 */ 889#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 890 "\xe5\x9b\x9b\xe4\xba\x94" \ 891 "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 892 "\xe4\xb9\x9d\xef\xa6\xb2" 893 894/* '1234567890' in Korean script in UTF-8 */ 895#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 896 "\xec\x82\xac\xec\x98\xa4" \ 897 "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 898 "\xea\xb5\xac\xec\x98\x81" 899 900#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 901#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 902#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 903#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 904 905static Bool 906is_double_width_font_xft(Display *dpy, XftFont *font) 907{ 908 XGlyphInfo gi1, gi2; 909 FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 910 String fwstr = FULL_WIDTH_TEST_STRING; 911 String hwstr = HALF_WIDTH_TEST_STRING; 912 913 /* Some Korean fonts don't have Chinese characters at all. */ 914 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 915 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 916 return False; /* Not a CJK font */ 917 else /* a Korean font without CJK Ideographs */ 918 fwstr = FULL_WIDTH_TEST_STRING2; 919 } 920 921 XftTextExtents32(dpy, font, &c1, 1, &gi1); 922 XftTextExtents32(dpy, font, &c2, 1, &gi2); 923 if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 924 return False; 925 926 XftTextExtentsUtf8(dpy, 927 font, 928 (_Xconst FcChar8 *) hwstr, 929 (int) strlen(hwstr), 930 &gi1); 931 XftTextExtentsUtf8(dpy, 932 font, 933 (_Xconst FcChar8 *) fwstr, 934 (int) strlen(fwstr), 935 &gi2); 936 937 /* 938 * fontconfig and Xft prior to 2.2(?) set the width of half-width 939 * characters identical to that of full-width character in CJK double-width 940 * (bi-width / monospace) font even though the former is half as wide as 941 * the latter. This was fixed sometime before the release of fontconfig 942 * 2.2 in early 2003. See 943 * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 944 * In the meantime, we have to check both possibilities. 945 */ 946 return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 947} 948#else 949#define is_double_width_font_xft(dpy, xftfont) 0 950#endif 951 952#define EmptyFont(fs) (fs != 0 \ 953 && ((fs)->ascent + (fs)->descent == 0 \ 954 || (fs)->max_bounds.width == 0)) 955 956#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 957 * (fs)->max_bounds.width) 958 959const VTFontNames * 960xtermFontName(const char *normal) 961{ 962 static VTFontNames data; 963 FREE_STRING(data.f_n); 964 memset(&data, 0, sizeof(data)); 965 if (normal) 966 data.f_n = x_strdup(normal); 967 return &data; 968} 969 970const VTFontNames * 971defaultVTFontNames(XtermWidget xw) 972{ 973 static VTFontNames data; 974 memset(&data, 0, sizeof(data)); 975 data.f_n = DefaultFontN(xw); 976 data.f_b = DefaultFontB(xw); 977#if OPT_WIDE_CHARS 978 data.f_w = DefaultFontW(xw); 979 data.f_wb = DefaultFontWB(xw); 980#endif 981 return &data; 982} 983 984static void 985cache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 986{ 987 if (name != 0) { 988 String last = screen->menu_font_names[fontnum][which]; 989 if (last != 0) { 990 if (strcmp(last, name)) { 991 FREE_STRING(last); 992 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 993 screen->menu_font_names[fontnum][which] = x_strdup(name); 994 } 995 } else { 996 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 997 screen->menu_font_names[fontnum][which] = x_strdup(name); 998 } 999 } 1000} 1001 1002static void 1003cannotFont(XtermWidget xw, const char *who, const char *tag, const char *name) 1004{ 1005 static NameList *reported; 1006 NameList *list; 1007 1008 switch (xw->misc.fontWarnings) { 1009 case fwNever: 1010 return; 1011 case fwResource: 1012 if (is_derived_font_name(name)) 1013 return; 1014 break; 1015 case fwAlways: 1016 break; 1017 } 1018 for (list = reported; list != 0; list = list->next) { 1019 if (!x_strcasecmp(name, list->name)) { 1020 return; 1021 } 1022 } 1023 if ((list = TypeMalloc(NameList)) != 0) { 1024 list->name = x_strdup(name); 1025 list->next = reported; 1026 reported = list; 1027 } 1028 xtermWarning("cannot %s%s%s %sfont \"%s\"\n", 1029 who, *tag ? " " : "", tag, 1030 is_derived_font_name(name) ? "derived " : "", 1031 name); 1032} 1033 1034#if OPT_RENDERFONT 1035static void 1036noUsableXft(XtermWidget xw, const char *name) 1037{ 1038 switch (xw->misc.fontWarnings) { 1039 case fwNever: 1040 return; 1041 case fwResource: 1042 /* these combinations of wide/bold/italic are all "derived" */ 1043 return; 1044 case fwAlways: 1045 break; 1046 } 1047 xtermWarning("did not find a usable %s TrueType font\n", name); 1048} 1049#endif 1050 1051XFontStruct * 1052xtermLoadQueryFont(XtermWidget xw, const char *name) 1053{ 1054 XFontStruct *result = NULL; 1055 size_t have = strlen(name); 1056 if (have == 0 || have > MAX_U_STRING) { 1057 ; /* just ignore it */ 1058 } else { 1059 TScreen *screen = TScreenOf(xw); 1060 result = XLoadQueryFont(screen->display, name); 1061 } 1062 return result; 1063} 1064 1065/* 1066 * Open the given font and verify that it is non-empty. Return false on 1067 * failure. 1068 */ 1069Bool 1070xtermOpenFont(XtermWidget xw, 1071 const char *name, 1072 XTermFonts * result, 1073 XTermFonts * current, 1074 Bool force) 1075{ 1076 Bool code = False; 1077 1078 TRACE(("xtermOpenFont %d:%d '%s'\n", 1079 result->warn, xw->misc.fontWarnings, NonNull(name))); 1080 1081 if (!IsEmpty(name)) { 1082 Bool existing = (current != NULL 1083 && current->fs != NULL 1084 && current->fn != NULL); 1085 1086 if ((result->fs = xtermLoadQueryFont(xw, name)) != 0) { 1087 code = True; 1088 if (EmptyFont(result->fs)) { 1089 xtermCloseFont(xw, result); 1090 code = False; 1091 } else { 1092 result->fn = x_strdup(name); 1093 } 1094 } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 1095 if (result->warn <= xw->misc.fontWarnings 1096#if OPT_RENDERFONT 1097 && !UsingRenderFont(xw) 1098#endif 1099 ) { 1100 cannotFont(xw, "load", "", name); 1101 } else { 1102 TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 1103 } 1104 if (existing) { 1105 TRACE(("...continue using font '%s'\n", current->fn)); 1106 result->fn = x_strdup(current->fn); 1107 result->fs = current->fs; 1108 } else if (force) { 1109 NoFontWarning(result); 1110 code = xtermOpenFont(xw, DEFFONT, result, NULL, True); 1111 } 1112 } 1113 } 1114 NoFontWarning(result); 1115 return code; 1116} 1117 1118/* 1119 * Close the font and free the font info. 1120 */ 1121void 1122xtermCloseFont(XtermWidget xw, XTermFonts * fnt) 1123{ 1124 if (fnt != 0 && fnt->fs != 0) { 1125 TScreen *screen = TScreenOf(xw); 1126 1127 clrCgsFonts(xw, WhichVWin(screen), fnt); 1128 XFreeFont(screen->display, fnt->fs); 1129 xtermFreeFontInfo(fnt); 1130 } 1131} 1132 1133/* 1134 * Close and free the font (as well as any aliases). 1135 */ 1136static void 1137xtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which) 1138{ 1139 XFontStruct *thisFont = fnts[which].fs; 1140 1141 if (thisFont != 0) { 1142 int k; 1143 1144 xtermCloseFont(xw, &fnts[which]); 1145 for (k = 0; k < fMAX; ++k) { 1146 if (k != which) { 1147 if (thisFont == fnts[k].fs) { 1148 xtermFreeFontInfo(&fnts[k]); 1149 } 1150 } 1151 } 1152 } 1153} 1154 1155/* 1156 * Close the listed fonts, noting that some may use copies of the pointer. 1157 */ 1158void 1159xtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 1160{ 1161 int j; 1162 1163 for (j = 0; j < fMAX; ++j) { 1164 xtermCloseFont2(xw, fnts, j); 1165 } 1166} 1167 1168/* 1169 * Make a copy of the source, assuming the XFontStruct's to be unique, but 1170 * ensuring that the names are reallocated to simplify freeing. 1171 */ 1172void 1173xtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 1174{ 1175 xtermFreeFontInfo(target); 1176 target->chrset = source->chrset; 1177 target->flags = source->flags; 1178 target->fn = x_strdup(source->fn); 1179 target->fs = source->fs; 1180 target->warn = source->warn; 1181} 1182 1183void 1184xtermFreeFontInfo(XTermFonts * target) 1185{ 1186 target->chrset = 0; 1187 target->flags = 0; 1188 FreeAndNull(target->fn); 1189 target->fs = 0; 1190} 1191 1192#if OPT_REPORT_FONTS 1193static void 1194reportXCharStruct(const char *tag, XCharStruct * cs) 1195{ 1196 ReportFonts("\t\t%s:\n", tag); 1197 ReportFonts("\t\t\tlbearing: %d\n", cs->lbearing); 1198 ReportFonts("\t\t\trbearing: %d\n", cs->rbearing); 1199 ReportFonts("\t\t\twidth: %d\n", cs->width); 1200 ReportFonts("\t\t\tascent: %d\n", cs->ascent); 1201 ReportFonts("\t\t\tdescent: %d\n", cs->descent); 1202} 1203 1204static void 1205reportOneVTFont(const char *tag, 1206 XTermFonts * fnt) 1207{ 1208 if (!IsEmpty(fnt->fn) && fnt->fs != 0) { 1209 XFontStruct *fs = fnt->fs; 1210 unsigned first_char = 0; 1211 unsigned last_char = 0; 1212 1213 if (fs->max_byte1 == 0) { 1214 first_char = fs->min_char_or_byte2; 1215 last_char = fs->max_char_or_byte2; 1216 } else { 1217 first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1218 last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1219 } 1220 1221 ReportFonts("\t%s: %s\n", tag, NonNull(fnt->fn)); 1222 ReportFonts("\t\tall chars: %s\n", (fs->all_chars_exist 1223 ? "yes" 1224 : "no")); 1225 ReportFonts("\t\tdefault char: %u\n", fs->default_char); 1226 ReportFonts("\t\tdirection: %u\n", fs->direction); 1227 ReportFonts("\t\tascent: %d\n", fs->ascent); 1228 ReportFonts("\t\tdescent: %d\n", fs->descent); 1229 ReportFonts("\t\tfirst char: %u\n", first_char); 1230 ReportFonts("\t\tlast char: %u\n", last_char); 1231 ReportFonts("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 1232 if (FontLacksMetrics(fnt)) { 1233 ReportFonts("\t\tmissing-chars: ?\n"); 1234 ReportFonts("\t\tpresent-chars: ?\n"); 1235 } else { 1236 unsigned missing = 0; 1237 unsigned ch; 1238 for (ch = first_char; ch <= last_char; ++ch) { 1239 if (xtermMissingChar(ch, fnt)) { 1240 ++missing; 1241 } 1242 } 1243 ReportFonts("\t\tmissing-chars: %u\n", missing); 1244 ReportFonts("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 1245 } 1246 ReportFonts("\t\tmin_byte1: %u\n", fs->min_byte1); 1247 ReportFonts("\t\tmax_byte1: %u\n", fs->max_byte1); 1248 ReportFonts("\t\tproperties: %d\n", fs->n_properties); 1249 reportXCharStruct("min_bounds", &(fs->min_bounds)); 1250 reportXCharStruct("max_bounds", &(fs->max_bounds)); 1251 /* TODO: report fs->properties and fs->per_char */ 1252 } 1253} 1254 1255static void 1256reportVTFontInfo(XtermWidget xw, int fontnum) 1257{ 1258 if (resource.reportFonts) { 1259 TScreen *screen = TScreenOf(xw); 1260 1261 if (fontnum) { 1262 ReportFonts("Loaded VTFonts(font%d)\n", fontnum); 1263 } else { 1264 ReportFonts("Loaded VTFonts(default)\n"); 1265 } 1266 1267 reportOneVTFont("fNorm", GetNormalFont(screen, fNorm)); 1268 reportOneVTFont("fBold", GetNormalFont(screen, fBold)); 1269#if OPT_WIDE_CHARS 1270 reportOneVTFont("fWide", GetNormalFont(screen, fWide)); 1271 reportOneVTFont("fWBold", GetNormalFont(screen, fWBold)); 1272#endif 1273 } 1274} 1275#endif 1276 1277void 1278xtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc) 1279{ 1280 TScreen *screen = TScreenOf(xw); 1281 VTwin *win = WhichVWin(screen); 1282 Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground); 1283 Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background); 1284 1285 setCgsFore(xw, win, gcNorm, new_normal); 1286 setCgsBack(xw, win, gcNorm, new_revers); 1287 setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm)); 1288 1289 copyCgs(xw, win, gcBold, gcNorm); 1290 setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold); 1291 1292 setCgsFore(xw, win, gcNormReverse, new_revers); 1293 setCgsBack(xw, win, gcNormReverse, new_normal); 1294 setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm)); 1295 1296 copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1297 setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold); 1298 1299 if_OPT_WIDE_CHARS(screen, { 1300 XTermFonts *wide_xx = myfunc(screen, fWide); 1301 XTermFonts *bold_xx = myfunc(screen, fWBold); 1302 if (wide_xx->fs != 0 1303 && bold_xx->fs != 0) { 1304 setCgsFore(xw, win, gcWide, new_normal); 1305 setCgsBack(xw, win, gcWide, new_revers); 1306 setCgsFont(xw, win, gcWide, wide_xx); 1307 1308 copyCgs(xw, win, gcWBold, gcWide); 1309 setCgsFont(xw, win, gcWBold, bold_xx); 1310 1311 setCgsFore(xw, win, gcWideReverse, new_revers); 1312 setCgsBack(xw, win, gcWideReverse, new_normal); 1313 setCgsFont(xw, win, gcWideReverse, wide_xx); 1314 1315 copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1316 setCgsFont(xw, win, gcWBoldReverse, bold_xx); 1317 } 1318 }); 1319} 1320 1321#if OPT_WIDE_ATTRS 1322unsigned 1323xtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs) 1324{ 1325 TScreen *screen = TScreenOf(xw); 1326 1327 (void) screen; 1328 if (UseItalicFont(screen)) { 1329 if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) { 1330 xtermLoadItalics(xw); 1331 xtermUpdateFontGCs(xw, getItalicFont); 1332 } else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) { 1333 xtermUpdateFontGCs(xw, getNormalFont); 1334 } 1335 } 1336 return new_attrs; 1337} 1338#endif 1339 1340#if OPT_TRACE && OPT_BOX_CHARS 1341static void 1342show_font_misses(const char *name, XTermFonts * fp) 1343{ 1344 if (fp->fs != 0) { 1345 if (FontLacksMetrics(fp)) { 1346 TRACE(("%s font lacks metrics\n", name)); 1347 } else if (FontIsIncomplete(fp)) { 1348 TRACE(("%s font is incomplete\n", name)); 1349 } else { 1350 TRACE(("%s font is complete\n", name)); 1351 } 1352 } else { 1353 TRACE(("%s font is missing\n", name)); 1354 } 1355} 1356#endif 1357 1358static Bool 1359loadNormFP(XtermWidget xw, 1360 char **nameOutP, 1361 XTermFonts * infoOut, 1362 XTermFonts * current, 1363 int fontnum) 1364{ 1365 Bool status = True; 1366 1367 TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP))); 1368 1369 if (!xtermOpenFont(xw, 1370 *nameOutP, 1371 infoOut, 1372 current, (fontnum == fontMenu_default))) { 1373 /* 1374 * If we are opening the default font, and it happens to be missing, 1375 * force that to the compiled-in default font, e.g., "fixed". If we 1376 * cannot open the font, disable it from the menu. 1377 */ 1378 if (fontnum != fontMenu_fontsel) { 1379 SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1380 } 1381 status = False; 1382 } 1383 return status; 1384} 1385 1386static Bool 1387loadBoldFP(XtermWidget xw, 1388 char **nameOutP, 1389 XTermFonts * infoOut, 1390 const char *nameRef, 1391 XTermFonts * infoRef, 1392 int fontnum) 1393{ 1394 TScreen *screen = TScreenOf(xw); 1395 Bool status = True; 1396 1397 TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP))); 1398 1399 if (!check_fontname(*nameOutP)) { 1400 FontNameProperties *fp; 1401 char *normal = x_strdup(nameRef); 1402 1403 fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1404 if (fp != 0) { 1405 NoFontWarning(infoOut); 1406 *nameOutP = bold_font_name(fp, fp->average_width); 1407 if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) { 1408 free(*nameOutP); 1409 *nameOutP = bold_font_name(fp, -1); 1410 xtermOpenFont(xw, *nameOutP, infoOut, NULL, False); 1411 } 1412 TRACE(("...derived bold '%s'\n", NonNull(*nameOutP))); 1413 } 1414 if (fp == 0 || infoOut->fs == 0) { 1415 xtermCopyFontInfo(infoOut, infoRef); 1416 TRACE(("...cannot load a matching bold font\n")); 1417 } else if (comparable_metrics(infoRef->fs, infoOut->fs) 1418 && same_font_size(xw, infoRef->fs, infoOut->fs) 1419 && got_bold_font(screen->display, infoOut->fs, *nameOutP)) { 1420 TRACE(("...got a matching bold font\n")); 1421 cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1422 } else { 1423 xtermCloseFont2(xw, infoOut - fBold, fBold); 1424 *infoOut = *infoRef; 1425 TRACE(("...did not get a matching bold font\n")); 1426 } 1427 free(normal); 1428 } else if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) { 1429 xtermCopyFontInfo(infoOut, infoRef); 1430 TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP))); 1431 } else { 1432 cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1433 } 1434 1435 /* 1436 * Most of the time this call to load the font will succeed, even if 1437 * there is no wide font : the X server doubles the width of the 1438 * normal font, or similar. 1439 * 1440 * But if it did fail for some reason, then nevermind. 1441 */ 1442 if (EmptyFont(infoOut->fs)) 1443 status = False; /* can't use a 0-sized font */ 1444 1445 if (!same_font_size(xw, infoRef->fs, infoOut->fs) 1446 && (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) { 1447 TRACE(("...ignoring mismatched normal/bold fonts\n")); 1448 xtermCloseFont2(xw, infoOut - fBold, fBold); 1449 xtermCopyFontInfo(infoOut, infoRef); 1450 } 1451 1452 return status; 1453} 1454 1455#if OPT_WIDE_CHARS 1456static Bool 1457loadWideFP(XtermWidget xw, 1458 char **nameOutP, 1459 XTermFonts * infoOut, 1460 const char *nameRef, 1461 XTermFonts * infoRef, 1462 int fontnum) 1463{ 1464 TScreen *screen = TScreenOf(xw); 1465 Bool status = True; 1466 1467 TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP))); 1468 1469 if (!check_fontname(*nameOutP) 1470 && (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) { 1471 char *normal = x_strdup(nameRef); 1472 FontNameProperties *fp = get_font_name_props(screen->display, 1473 infoRef->fs, &normal); 1474 if (fp != 0) { 1475 *nameOutP = wide_font_name(fp); 1476 NoFontWarning(infoOut); 1477 } 1478 free(normal); 1479 } 1480 1481 if (check_fontname(*nameOutP)) { 1482 if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False) 1483 && is_derived_font_name(*nameOutP) 1484 && EmptyFont(infoOut->fs)) { 1485 xtermCloseFont2(xw, infoOut - fWide, fWide); 1486 } 1487 if (infoOut->fs == 0) { 1488 xtermCopyFontInfo(infoOut, infoRef); 1489 } else { 1490 TRACE(("...%s wide %s\n", 1491 is_derived_font_name(*nameOutP) ? "derived" : "given", 1492 NonNull(*nameOutP))); 1493 cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1494 } 1495 } else { 1496 xtermCopyFontInfo(infoOut, infoRef); 1497 } 1498#define MinWidthOf(fs) fs->min_bounds.width 1499#define MaxWidthOf(fs) fs->max_bounds.width 1500 xw->work.force_wideFont = False; 1501 if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) { 1502 TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs))); 1503 TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs))); 1504 TRACE(("...actual width %d\n", MaxWidthOf(infoOut->fs))); 1505 xw->work.force_wideFont = True; 1506 } 1507 return status; 1508} 1509 1510static Bool 1511loadWBoldFP(XtermWidget xw, 1512 char **nameOutP, 1513 XTermFonts * infoOut, 1514 const char *wideNameRef, XTermFonts * wideInfoRef, 1515 const char *boldNameRef, XTermFonts * boldInfoRef, 1516 int fontnum) 1517{ 1518 TScreen *screen = TScreenOf(xw); 1519 Bool status = True; 1520 char *bold = NULL; 1521 1522 TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP))); 1523 1524 if (!check_fontname(*nameOutP)) { 1525 FontNameProperties *fp; 1526 fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold); 1527 if (fp != 0) { 1528 *nameOutP = widebold_font_name(fp); 1529 NoFontWarning(infoOut); 1530 } 1531 } 1532 1533 if (check_fontname(*nameOutP)) { 1534 1535 if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False) 1536 && is_derived_font_name(*nameOutP) 1537 && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) { 1538 xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1539 } 1540 1541 if (infoOut->fs == 0) { 1542 if (is_derived_font_name(*nameOutP)) 1543 free(*nameOutP); 1544 if (IsEmpty(wideNameRef)) { 1545 *nameOutP = x_strdup(boldNameRef); 1546 xtermCopyFontInfo(infoOut, boldInfoRef); 1547 TRACE(("...cannot load wide-bold, use bold %s\n", 1548 NonNull(boldNameRef))); 1549 } else { 1550 *nameOutP = x_strdup(wideNameRef); 1551 xtermCopyFontInfo(infoOut, wideInfoRef); 1552 TRACE(("...cannot load wide-bold, use wide %s\n", 1553 NonNull(wideNameRef))); 1554 } 1555 } else { 1556 TRACE(("...%s wide/bold %s\n", 1557 is_derived_font_name(*nameOutP) ? "derived" : "given", 1558 NonNull(*nameOutP))); 1559 cache_menu_font_name(screen, fontnum, fWBold, *nameOutP); 1560 } 1561 } else if (is_double_width_font(boldInfoRef->fs)) { 1562 xtermCopyFontInfo(infoOut, boldInfoRef); 1563 TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef))); 1564 } else { 1565 xtermCopyFontInfo(infoOut, wideInfoRef); 1566 TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef))); 1567 } 1568 1569 free(bold); 1570 1571 if (EmptyFont(infoOut->fs)) { 1572 status = False; /* can't use a 0-sized font */ 1573 } else { 1574 if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs) 1575 || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs) 1576 && is_fixed_font(wideInfoRef->fs) 1577 && is_fixed_font(infoOut->fs)))) { 1578 TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1579 xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1580 xtermCopyFontInfo(infoOut, wideInfoRef); 1581 } 1582 } 1583 1584 return status; 1585} 1586#endif 1587 1588/* 1589 * Load a given bitmap font, along with the bold/wide variants. 1590 * Returns nonzero on success. 1591 */ 1592int 1593xtermLoadFont(XtermWidget xw, 1594 const VTFontNames * fonts, 1595 Bool doresize, 1596 int fontnum) 1597{ 1598 TScreen *screen = TScreenOf(xw); 1599 VTwin *win = WhichVWin(screen); 1600 1601 VTFontNames new_fnames; 1602 XTermFonts new_fonts[fMAX]; 1603 XTermFonts old_fonts[fMAX]; 1604 char *tmpname = NULL; 1605 Boolean proportional = False; 1606 Boolean recovered; 1607 int code = 0; 1608 1609 memset(&new_fnames, 0, sizeof(new_fnames)); 1610 memset(new_fonts, 0, sizeof(new_fonts)); 1611 memcpy(&old_fonts, screen->fnts, sizeof(old_fonts)); 1612 1613 if (fonts != 0) 1614 new_fnames = *fonts; 1615 if (!check_fontname(new_fnames.f_n)) 1616 return code; 1617 1618 if (fontnum == fontMenu_fontescape 1619 && new_fnames.f_n != screen->MenuFontName(fontnum)) { 1620 if ((tmpname = x_strdup(new_fnames.f_n)) == 0) 1621 return code; 1622 } 1623 1624 TRACE(("Begin Cgs - xtermLoadFont(%s)\n", new_fnames.f_n)); 1625 releaseWindowGCs(xw, win); 1626 1627#define DbgResource(name, field, index) \ 1628 TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1629 fontnum, \ 1630 (new_fonts[index].warn == fwResource) ? "*" : " ", \ 1631 NonNull(new_fnames.field))) 1632 DbgResource("normal", f_n, fNorm); 1633 DbgResource("bold ", f_b, fBold); 1634#if OPT_WIDE_CHARS 1635 DbgResource("wide ", f_w, fWide); 1636 DbgResource("w/bold", f_wb, fWBold); 1637#endif 1638 1639 if (!loadNormFP(xw, 1640 &new_fnames.f_n, 1641 &new_fonts[fNorm], 1642 &old_fonts[fNorm], 1643 fontnum)) 1644 goto bad; 1645 1646 if (!loadBoldFP(xw, 1647 &new_fnames.f_b, 1648 &new_fonts[fBold], 1649 new_fnames.f_n, 1650 &new_fonts[fNorm], 1651 fontnum)) 1652 goto bad; 1653 1654 /* 1655 * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1656 * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1657 * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1658 */ 1659 if_OPT_WIDE_CHARS(screen, { 1660 1661 if (!loadWideFP(xw, 1662 &new_fnames.f_w, 1663 &new_fonts[fWide], 1664 new_fnames.f_n, 1665 &new_fonts[fNorm], 1666 fontnum)) 1667 goto bad; 1668 1669 if (!loadWBoldFP(xw, 1670 &new_fnames.f_wb, 1671 &new_fonts[fWBold], 1672 new_fnames.f_w, 1673 &new_fonts[fWide], 1674 new_fnames.f_b, 1675 &new_fonts[fBold], 1676 fontnum)) 1677 goto bad; 1678 1679 }); 1680 1681 /* 1682 * Normal/bold fonts should be the same width. Also, the min/max 1683 * values should be the same. 1684 */ 1685 if (new_fonts[fNorm].fs != 0 1686 && new_fonts[fBold].fs != 0 1687 && (!is_fixed_font(new_fonts[fNorm].fs) 1688 || !is_fixed_font(new_fonts[fBold].fs) 1689 || differing_widths(new_fonts[fNorm].fs, new_fonts[fBold].fs))) { 1690 TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1691 new_fonts[fNorm].fs->min_bounds.width, 1692 new_fonts[fNorm].fs->max_bounds.width, 1693 new_fonts[fBold].fs->min_bounds.width, 1694 new_fonts[fBold].fs->max_bounds.width)); 1695 proportional = True; 1696 } 1697 1698 if_OPT_WIDE_CHARS(screen, { 1699 if (new_fonts[fWide].fs != 0 1700 && new_fonts[fWBold].fs != 0 1701 && (!is_fixed_font(new_fonts[fWide].fs) 1702 || !is_fixed_font(new_fonts[fWBold].fs) 1703 || differing_widths(new_fonts[fWide].fs, new_fonts[fWBold].fs))) { 1704 TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1705 new_fonts[fWide].fs->min_bounds.width, 1706 new_fonts[fWide].fs->max_bounds.width, 1707 new_fonts[fWBold].fs->min_bounds.width, 1708 new_fonts[fWBold].fs->max_bounds.width)); 1709 proportional = True; 1710 } 1711 }); 1712 1713 /* TODO : enforce that the width of the wide font is 2* the width 1714 of the narrow font */ 1715 1716 /* 1717 * If we're switching fonts, free the old ones. Otherwise we'll leak 1718 * the memory that is associated with the old fonts. The 1719 * XLoadQueryFont call allocates a new XFontStruct. 1720 */ 1721 xtermCloseFonts(xw, screen->fnts); 1722#if OPT_WIDE_ATTRS 1723 xtermCloseFonts(xw, screen->ifnts); 1724 screen->ifnts_ok = False; 1725#endif 1726 1727 xtermCopyFontInfo(GetNormalFont(screen, fNorm), &new_fonts[fNorm]); 1728 xtermCopyFontInfo(GetNormalFont(screen, fBold), &new_fonts[fBold]); 1729#if OPT_WIDE_CHARS 1730 xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]); 1731 if (new_fonts[fWBold].fs == NULL) 1732 xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]); 1733 xtermCopyFontInfo(GetNormalFont(screen, fWBold), &new_fonts[fWBold]); 1734#endif 1735 1736 xtermUpdateFontGCs(xw, getNormalFont); 1737 1738#if OPT_BOX_CHARS 1739 screen->allow_packing = proportional; 1740 setupPackedFonts(xw); 1741#endif 1742 screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1743 screen->fnt_boxes = 1; 1744 1745#if OPT_BOX_CHARS 1746 /* 1747 * xterm uses character positions 1-31 of a font for the line-drawing 1748 * characters. Check that they are all present. The null character 1749 * (0) is special, and is not used. 1750 */ 1751#if OPT_RENDERFONT 1752 if (UsingRenderFont(xw)) { 1753 /* 1754 * FIXME: we shouldn't even be here if we're using Xft. 1755 */ 1756 screen->fnt_boxes = 0; 1757 TRACE(("assume Xft missing line-drawing chars\n")); 1758 } else 1759#endif 1760 { 1761 unsigned ch; 1762 1763#if OPT_TRACE 1764#define TRACE_MISS(index) show_font_misses(#index, &new_fonts[index]) 1765 TRACE_MISS(fNorm); 1766 TRACE_MISS(fBold); 1767#if OPT_WIDE_CHARS 1768 TRACE_MISS(fWide); 1769 TRACE_MISS(fWBold); 1770#endif 1771#endif 1772 1773#if OPT_WIDE_CHARS 1774 if (screen->utf8_mode || screen->unicode_font) { 1775 UIntSet(screen->fnt_boxes, 2); 1776 for (ch = 1; ch < 32; ch++) { 1777 unsigned n = dec2ucs(screen, ch); 1778 if ((n != UCS_REPL) 1779 && (n != ch) 1780 && (screen->fnt_boxes & 2)) { 1781 if (xtermMissingChar(n, &new_fonts[fNorm]) || 1782 xtermMissingChar(n, &new_fonts[fBold])) { 1783 UIntClr(screen->fnt_boxes, 2); 1784 TRACE(("missing graphics character #%d, U+%04X\n", 1785 ch, n)); 1786 break; 1787 } 1788 } 1789 } 1790 } 1791#endif 1792 1793 for (ch = 1; ch < 32; ch++) { 1794 if (xtermMissingChar(ch, &new_fonts[fNorm])) { 1795 TRACE(("missing normal char #%d\n", ch)); 1796 UIntClr(screen->fnt_boxes, 1); 1797 break; 1798 } 1799 if (xtermMissingChar(ch, &new_fonts[fBold])) { 1800 TRACE(("missing bold char #%d\n", ch)); 1801 UIntClr(screen->fnt_boxes, 1); 1802 break; 1803 } 1804 } 1805 1806 TRACE(("Will %suse internal line-drawing characters (mode %d)\n", 1807 screen->fnt_boxes ? "not " : "", 1808 screen->fnt_boxes)); 1809 } 1810#endif 1811 1812 if (screen->always_bold_mode) { 1813 screen->enbolden = screen->bold_mode; 1814 } else { 1815 screen->enbolden = screen->bold_mode 1816 && ((new_fonts[fNorm].fs == new_fonts[fBold].fs) 1817 || same_font_name(new_fnames.f_n, new_fnames.f_b)); 1818 } 1819 TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1820 screen->enbolden ? "" : "not ")); 1821 1822 set_menu_font(False); 1823 screen->menu_font_number = fontnum; 1824 set_menu_font(True); 1825 if (tmpname) { /* if setting escape or sel */ 1826 if (screen->MenuFontName(fontnum)) 1827 FREE_STRING(screen->MenuFontName(fontnum)); 1828 screen->MenuFontName(fontnum) = tmpname; 1829 if (fontnum == fontMenu_fontescape) { 1830 update_font_escape(); 1831 } 1832#if OPT_SHIFT_FONTS 1833 screen->menu_font_sizes[fontnum] = FontSize(new_fonts[fNorm].fs); 1834#endif 1835 } 1836 set_cursor_gcs(xw); 1837 xtermUpdateFontInfo(xw, doresize); 1838 TRACE(("Success Cgs - xtermLoadFont\n")); 1839#if OPT_REPORT_FONTS 1840 reportVTFontInfo(xw, fontnum); 1841#endif 1842 FREE_FNAME(f_n); 1843 FREE_FNAME(f_b); 1844#if OPT_WIDE_CHARS 1845 FREE_FNAME(f_w); 1846 FREE_FNAME(f_wb); 1847#endif 1848 if (new_fonts[fNorm].fn == new_fonts[fBold].fn) { 1849 free(new_fonts[fNorm].fn); 1850 } else { 1851 free(new_fonts[fNorm].fn); 1852 free(new_fonts[fBold].fn); 1853 } 1854#if OPT_WIDE_CHARS 1855 free(new_fonts[fWide].fn); 1856 free(new_fonts[fWBold].fn); 1857#endif 1858 xtermSetWinSize(xw); 1859 return 1; 1860 1861 bad: 1862 recovered = False; 1863 free(tmpname); 1864 1865#if OPT_RENDERFONT 1866 if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) { 1867 int old_fontnum = screen->menu_font_number; 1868#if OPT_TOOLBAR 1869 SetItemSensitivity(fontMenuEntries[fontnum].widget, True); 1870#endif 1871 Bell(xw, XkbBI_MinorError, 0); 1872 new_fnames.f_n = screen->MenuFontName(old_fontnum); 1873 if (xtermLoadFont(xw, &new_fnames, doresize, old_fontnum)) 1874 recovered = True; 1875 } else if (x_strcasecmp(new_fnames.f_n, DEFFONT) 1876 && x_strcasecmp(new_fnames.f_n, old_fonts[fNorm].fn)) { 1877 new_fnames.f_n = x_strdup(old_fonts[fNorm].fn); 1878 TRACE(("...recovering from failed font-load\n")); 1879 if (xtermLoadFont(xw, &new_fnames, doresize, fontnum)) { 1880 recovered = True; 1881 if (fontnum != fontMenu_fontsel) { 1882 SetItemSensitivity(fontMenuEntries[fontnum].widget, 1883 UsingRenderFont(xw)); 1884 } 1885 TRACE(("...recovered size %dx%d\n", 1886 FontHeight(screen), 1887 FontWidth(screen))); 1888 } 1889 } 1890#endif 1891 if (!recovered) { 1892 releaseWindowGCs(xw, win); 1893 xtermCloseFonts(xw, new_fonts); 1894 TRACE(("Fail Cgs - xtermLoadFont\n")); 1895 code = 0; 1896 } 1897 return code; 1898} 1899 1900#if OPT_WIDE_ATTRS 1901/* 1902 * (Attempt to) load matching italics for the current normal/bold/etc fonts. 1903 * If the attempt fails for a given style, use the non-italic font. 1904 */ 1905void 1906xtermLoadItalics(XtermWidget xw) 1907{ 1908 TScreen *screen = TScreenOf(xw); 1909 1910 if (UseItalicFont(screen) && !screen->ifnts_ok) { 1911 int n; 1912 FontNameProperties *fp; 1913 XTermFonts *data; 1914 1915 screen->ifnts_ok = True; 1916 for (n = 0; n < fMAX; ++n) { 1917 switch (n) { 1918 case fNorm: 1919 /* FALLTHRU */ 1920 case fBold: 1921 /* FALLTHRU */ 1922#if OPT_WIDE_CHARS 1923 case fWide: 1924 /* FALLTHRU */ 1925 case fWBold: 1926#endif 1927 /* FALLTHRU */ 1928 data = getItalicFont(screen, n); 1929 1930 /* 1931 * FIXME - need to handle font-leaks 1932 */ 1933 data->fs = 0; 1934 if (getNormalFont(screen, n)->fs != 0 && 1935 (fp = get_font_name_props(screen->display, 1936 getNormalFont(screen, n)->fs, 1937 0)) != 0) { 1938 if (!open_italic_font(xw, n, fp, data)) { 1939 if (n > 0) { 1940 xtermCopyFontInfo(data, 1941 getItalicFont(screen, n - 1)); 1942 } else { 1943 xtermOpenFont(xw, 1944 getNormalFont(screen, n)->fn, 1945 data, NULL, False); 1946 } 1947 } 1948 } 1949 break; 1950 } 1951 } 1952 } 1953} 1954#endif 1955 1956#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1957/* 1958 * Collect font-names that we can modify with the load-vt-fonts() action. 1959 */ 1960#define MERGE_SUBFONT(dst,src,name) \ 1961 if (IsEmpty(dst.name)) { \ 1962 TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \ 1963 dst.name = x_strdup(src.name); \ 1964 } else { \ 1965 TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1966 } 1967#define MERGE_SUBLIST(dst,src,name) \ 1968 if (dst.fonts.x11.name == NULL) \ 1969 dst.fonts.x11.name = TypeCalloc(char *); \ 1970 if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \ 1971 TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \ 1972 } else { \ 1973 TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \ 1974 } 1975 1976#define INFER_SUBFONT(dst,src,name) \ 1977 if (IsEmpty(dst.name)) { \ 1978 TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1979 dst.name = x_strdup(""); \ 1980 } else { \ 1981 TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1982 } 1983 1984#define FREE_MENU_FONTS(dst) \ 1985 TRACE(("FREE_MENU_FONTS " #dst "\n")); \ 1986 for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1987 for (m = 0; m < fMAX; ++m) { \ 1988 FREE_STRING(dst.menu_font_names[n][m]); \ 1989 dst.menu_font_names[n][m] = 0; \ 1990 } \ 1991 } 1992 1993#define COPY_MENU_FONTS(dst,src) \ 1994 TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1995 for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1996 for (m = 0; m < fMAX; ++m) { \ 1997 FREE_STRING(dst.menu_font_names[n][m]); \ 1998 dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1999 } \ 2000 TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \ 2001 } 2002 2003#define COPY_DEFAULT_FONTS(target, source) \ 2004 TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \ 2005 xtermCopyVTFontNames(&target.default_font, &source.default_font) 2006 2007#define COPY_X11_FONTLISTS(target, source) \ 2008 TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \ 2009 xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11) 2010 2011static void 2012xtermCopyVTFontNames(VTFontNames * target, VTFontNames * source) 2013{ 2014#define COPY_IT(name,field) \ 2015 TRACE((".. "#name" = %s\n", NonNull(source->field))); \ 2016 free(target->field); \ 2017 target->field = x_strdup(source->field) 2018 2019 TRACE(("xtermCopyVTFontNames\n")); 2020 2021 COPY_IT(font, f_n); 2022 COPY_IT(boldFont, f_b); 2023 2024#if OPT_WIDE_CHARS 2025 COPY_IT(wideFont, f_w); 2026 COPY_IT(wideBoldFont, f_wb); 2027#endif 2028#undef COPY_IT 2029} 2030 2031static void 2032xtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source) 2033{ 2034#define COPY_IT(name,field) \ 2035 copyFontList(&(target->field), source->field); \ 2036 TRACE_ARGV(".. " #name, source->field) 2037 2038 (void) xw; 2039 TRACE(("xtermCopyFontLists %s ->%s\n", 2040 whichFontList(xw, source), 2041 whichFontList(xw, target))); 2042 2043 COPY_IT(font, list_n); 2044 COPY_IT(fontBold, list_b); 2045#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 2046 COPY_IT(fontItal, list_i); 2047 COPY_IT(fontBtal, list_bi); 2048#endif 2049#if OPT_WIDE_CHARS 2050 COPY_IT(wideFont, list_w); 2051 COPY_IT(wideBoldFont, list_wb); 2052 COPY_IT(wideItalFont, list_wi); 2053 COPY_IT(wideBtalFont, list_wbi); 2054#endif 2055#undef COPY_IT 2056} 2057 2058void 2059xtermSaveVTFonts(XtermWidget xw) 2060{ 2061 TScreen *screen = TScreenOf(xw); 2062 Cardinal n, m; 2063 2064 if (!screen->savedVTFonts) { 2065 2066 screen->savedVTFonts = True; 2067 TRACE(("xtermSaveVTFonts saving original\n")); 2068 COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc); 2069 COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work); 2070 COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 2071 } 2072} 2073 2074#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 2075#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 2076 2077static Boolean 2078sameSubResources(SubResourceRec * a, SubResourceRec * b) 2079{ 2080 Boolean result = True; 2081 2082 if (!SAME_MEMBER(default_font.f_n) 2083 || !SAME_MEMBER(default_font.f_b) 2084#if OPT_WIDE_CHARS 2085 || !SAME_MEMBER(default_font.f_w) 2086 || !SAME_MEMBER(default_font.f_wb) 2087#endif 2088 ) { 2089 TRACE(("sameSubResources: default_font differs\n")); 2090 result = False; 2091 } else { 2092 int n; 2093 2094 for (n = 0; n < NMENUFONTS; ++n) { 2095 if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 2096 TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 2097 result = False; 2098 break; 2099 } 2100 } 2101 } 2102 2103 return result; 2104} 2105 2106/* 2107 * Load the "VT" font names from the given subresource name/class. These 2108 * correspond to the VT100 resources. 2109 */ 2110static Bool 2111xtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 2112{ 2113 SubResourceRec subresourceRec; 2114 SubResourceRec referenceRec; 2115 2116 /* 2117 * These are duplicates of the VT100 font resources, but with a special 2118 * application/classname passed in to distinguish them. 2119 */ 2120 static XtResource font_resources[] = 2121 { 2122 Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 2123 Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 2124#if OPT_WIDE_CHARS 2125 Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 2126 Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 2127#endif 2128 Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 2129 Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 2130 Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 2131 Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 2132 Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 2133 Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 2134 Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL), 2135 }; 2136 Cardinal n, m; 2137 Bool status = True; 2138 TScreen *screen = TScreenOf(xw); 2139 2140 TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 2141 NonNull(myName), NonNull(myClass))); 2142 2143 xtermSaveVTFonts(xw); 2144 2145 if (IsEmpty(myName)) { 2146 TRACE(("xtermLoadVTFonts restoring original\n")); 2147 COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts); 2148 COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts); 2149 FREE_MENU_FONTS(xw->screen); 2150 COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 2151 } else { 2152 TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 2153 2154 memset(&referenceRec, 0, sizeof(referenceRec)); 2155 memset(&subresourceRec, 0, sizeof(subresourceRec)); 2156 XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 2157 myName, myClass, 2158 font_resources, 2159 (Cardinal) XtNumber(font_resources), 2160 NULL, (Cardinal) 0); 2161 2162 /* 2163 * XtGetSubresources returns no status, so we compare the returned 2164 * data against a zero'd struct to see if any data is returned. 2165 */ 2166 if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 2167 && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 2168 2169 screen->mergedVTFonts = True; 2170 2171 /* 2172 * To make it simple, reallocate the strings returned by 2173 * XtGetSubresources. We can free our own strings, but not theirs. 2174 */ 2175 ALLOC_STRING(subresourceRec.default_font.f_n); 2176 ALLOC_STRING(subresourceRec.default_font.f_b); 2177#if OPT_WIDE_CHARS 2178 ALLOC_STRING(subresourceRec.default_font.f_w); 2179 ALLOC_STRING(subresourceRec.default_font.f_wb); 2180#endif 2181 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2182 ALLOC_STRING(subresourceRec.MenuFontName(n)); 2183 } 2184 2185 /* 2186 * Now, save the string to a font-list for consistency 2187 */ 2188#define ALLOC_SUBLIST(which,field) \ 2189 if (subresourceRec.default_font.field != NULL) { \ 2190 char *blob = x_strdup(subresourceRec.default_font.field); \ 2191 char *base; \ 2192 for (base = blob; ; base = NULL) { \ 2193 char *item = strtok(base, ","); \ 2194 if (item == NULL) \ 2195 break; \ 2196 save2FontList(xw, "cached", \ 2197 &(subresourceRec.fonts), \ 2198 which, \ 2199 item, False, False); \ 2200 } \ 2201 free(blob); \ 2202 } 2203 2204 ALLOC_SUBLIST(fNorm, f_n); 2205 ALLOC_SUBLIST(fBold, f_b); 2206#if OPT_WIDE_CHARS 2207 ALLOC_SUBLIST(fWide, f_w); 2208 ALLOC_SUBLIST(fWBold, f_wb); 2209#endif 2210 2211 /* 2212 * If a particular resource value was not found, use the original. 2213 */ 2214 MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n); 2215 INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b); 2216 MERGE_SUBLIST(subresourceRec, xw->work, list_n); 2217 MERGE_SUBLIST(subresourceRec, xw->work, list_b); 2218#if OPT_WIDE_CHARS 2219 INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w); 2220 INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb); 2221 MERGE_SUBLIST(subresourceRec, xw->work, list_w); 2222 MERGE_SUBLIST(subresourceRec, xw->work, list_wb); 2223#endif 2224 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2225 MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n)); 2226 } 2227 2228 /* 2229 * Finally, copy the subresource data to the widget. 2230 */ 2231 COPY_DEFAULT_FONTS(xw->misc, subresourceRec); 2232 COPY_X11_FONTLISTS(xw->work, subresourceRec); 2233 FREE_MENU_FONTS(xw->screen); 2234 COPY_MENU_FONTS(xw->screen, subresourceRec); 2235 2236 FREE_STRING(screen->MenuFontName(fontMenu_default)); 2237 FREE_STRING(screen->menu_font_names[0][fBold]); 2238 screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw)); 2239 screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw)); 2240#if OPT_WIDE_CHARS 2241 FREE_STRING(screen->menu_font_names[0][fWide]); 2242 FREE_STRING(screen->menu_font_names[0][fWBold]); 2243 screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw)); 2244 screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw)); 2245#endif 2246 /* 2247 * And remove our copies of strings. 2248 */ 2249 FREE_STRING(subresourceRec.default_font.f_n); 2250 FREE_STRING(subresourceRec.default_font.f_b); 2251#if OPT_WIDE_CHARS 2252 FREE_STRING(subresourceRec.default_font.f_w); 2253 FREE_STRING(subresourceRec.default_font.f_wb); 2254#endif 2255 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2256 FREE_STRING(subresourceRec.MenuFontName(n)); 2257 } 2258 } else { 2259 TRACE(("...no resources found\n")); 2260 status = False; 2261 } 2262 } 2263 TRACE((".. xtermLoadVTFonts: %d\n", status)); 2264 return status; 2265} 2266 2267#if OPT_WIDE_CHARS 2268static Bool 2269isWideFont(XFontStruct *fp, const char *tag, Bool nullOk) 2270{ 2271 Bool result = False; 2272 2273 (void) tag; 2274 if (okFont(fp)) { 2275 unsigned count = countGlyphs(fp); 2276 TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 2277 result = (count > 256) ? True : False; 2278 } else { 2279 result = nullOk; 2280 } 2281 return result; 2282} 2283 2284/* 2285 * If the current fonts are not wide, load the UTF8 fonts. 2286 * 2287 * Called during initialization (for wide-character mode), the fonts have not 2288 * been setup, so we pass nullOk=True to isWideFont(). 2289 * 2290 * Called after initialization, e.g., in response to the UTF-8 menu entry 2291 * (starting from narrow character mode), it checks if the fonts are not wide. 2292 */ 2293Bool 2294xtermLoadWideFonts(XtermWidget xw, Bool nullOk) 2295{ 2296 TScreen *screen = TScreenOf(xw); 2297 Bool result; 2298 2299 if (EmptyFont(GetNormalFont(screen, fWide)->fs)) { 2300 result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2301 && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk)); 2302 } else { 2303 result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk) 2304 && isWideFont(GetNormalFont(screen, fWBold)->fs, 2305 "wide-bold", nullOk)); 2306 if (result && !screen->utf8_latin1) { 2307 result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2308 && isWideFont(GetNormalFont(screen, fBold)->fs, 2309 "bold", nullOk)); 2310 } 2311 } 2312 if (!result) { 2313 TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 2314 result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 2315 } 2316 TRACE(("xtermLoadWideFonts:%d\n", result)); 2317 return result; 2318} 2319#endif /* OPT_WIDE_CHARS */ 2320 2321/* 2322 * Restore the default fonts, i.e., if we had switched to wide-fonts. 2323 */ 2324Bool 2325xtermLoadDefaultFonts(XtermWidget xw) 2326{ 2327 Bool result; 2328 result = xtermLoadVTFonts(xw, NULL, NULL); 2329 TRACE(("xtermLoadDefaultFonts:%d\n", result)); 2330 return result; 2331} 2332#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 2333 2334#if OPT_LOAD_VTFONTS 2335void 2336HandleLoadVTFonts(Widget w, 2337 XEvent *event GCC_UNUSED, 2338 String *params, 2339 Cardinal *param_count) 2340{ 2341 XtermWidget xw; 2342 2343 if ((xw = getXtermWidget(w)) != 0) { 2344 static char empty[] = ""; /* appease strict compilers */ 2345 2346 TScreen *screen = TScreenOf(xw); 2347 char name_buf[80]; 2348 String name = (String) ((*param_count > 0) ? params[0] : empty); 2349 char *myName = MyStackAlloc(strlen(name) + 1, name_buf); 2350 2351 TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 2352 if (myName != 0) { 2353 char class_buf[80]; 2354 String convert = (String) ((*param_count > 1) ? params[1] : myName); 2355 char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf); 2356 2357 strcpy(myName, name); 2358 if (myClass != 0) { 2359 strcpy(myClass, convert); 2360 if (*param_count == 1) 2361 myClass[0] = x_toupper(myClass[0]); 2362 2363 if (xtermLoadVTFonts(xw, myName, myClass)) { 2364 int n; 2365 /* 2366 * When switching fonts, try to preserve the font-menu 2367 * selection, since it is less surprising to do that (if 2368 * the font-switching can be undone) than to switch to 2369 * "Default". 2370 */ 2371 int font_number = screen->menu_font_number; 2372 if (font_number > fontMenu_lastBuiltin) 2373 font_number = fontMenu_lastBuiltin; 2374 for (n = 0; n < NMENUFONTS; ++n) { 2375 screen->menu_font_sizes[n] = 0; 2376 } 2377 if (font_number == fontMenu_default) { 2378 SetVTFont(xw, font_number, True, defaultVTFontNames(xw)); 2379 } else { 2380 SetVTFont(xw, font_number, True, NULL); 2381 } 2382 } 2383 MyStackFree(myClass, class_buf); 2384 } 2385 MyStackFree(myName, name_buf); 2386 } 2387 } 2388} 2389#endif /* OPT_LOAD_VTFONTS */ 2390 2391/* 2392 * Set the limits for the box that outlines the cursor. 2393 */ 2394void 2395xtermSetCursorBox(TScreen *screen) 2396{ 2397 static XPoint VTbox[NBOX]; 2398 XPoint *vp; 2399 int fw = FontWidth(screen) - 1; 2400 int fh = FontHeight(screen) - 1; 2401 int ww = isCursorBar(screen) ? fw / 8 : fw; 2402 int hh = isCursorUnderline(screen) ? fh / 8 : fh; 2403 if (ww < 2) 2404 ww = 2; 2405 if (hh < 2) 2406 hh = 2; 2407 2408 vp = &VTbox[1]; 2409 (vp++)->x = (short) ww; 2410 (vp++)->y = (short) hh; 2411 (vp++)->x = (short) -ww; 2412 vp->y = (short) -hh; 2413 2414 screen->box = VTbox; 2415} 2416 2417#if OPT_RENDERFONT 2418 2419#define CACHE_XFT(data) if (XftFp(data) != NULL) {\ 2420 int err = checkXftWidth(xw, data);\ 2421 TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\ 2422 #data,\ 2423 fontnum,\ 2424 XftFp(data)->height,\ 2425 XftFp(data)->ascent,\ 2426 XftFp(data)->descent,\ 2427 ((XftFp(data)->ascent + XftFp(data)->descent) > XftFp(data)->height ? "*" : ""),\ 2428 XftFp(data)->max_advance_width,\ 2429 data->font_info.min_width,\ 2430 data->font_info.mixed ? " mixed" : "",\ 2431 err ? " ERROR" : ""));\ 2432 if (err) {\ 2433 xtermCloseXft(screen, data);\ 2434 memset((data), 0, sizeof(*data));\ 2435 failed += err;\ 2436 }\ 2437 } 2438 2439#if OPT_REPORT_FONTS 2440static FcChar32 2441xtermXftFirstChar(XftFont *xft) 2442{ 2443 FcChar32 map[FC_CHARSET_MAP_SIZE]; 2444 FcChar32 next; 2445 FcChar32 first; 2446 int i; 2447 2448 first = FcCharSetFirstPage(xft->charset, map, &next); 2449 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { 2450 if (map[i]) { 2451 FcChar32 bits = map[i]; 2452 first += (FcChar32) i *32; 2453 while (!(bits & 0x1)) { 2454 bits >>= 1; 2455 first++; 2456 } 2457 break; 2458 } 2459 } 2460 return first; 2461} 2462 2463static FcChar32 2464xtermXftLastChar(XftFont *xft) 2465{ 2466 FcChar32 temp, last, next; 2467 FcChar32 map[FC_CHARSET_MAP_SIZE]; 2468 int i; 2469 last = FcCharSetFirstPage(xft->charset, map, &next); 2470 while ((temp = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 2471 last = temp; 2472 last &= (FcChar32) ~ 0xff; 2473 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) { 2474 if (map[i]) { 2475 FcChar32 bits = map[i]; 2476 last += (FcChar32) i *32 + 31; 2477 while (!(bits & 0x80000000)) { 2478 last--; 2479 bits <<= 1; 2480 } 2481 break; 2482 } 2483 } 2484 return (FcChar32) last; 2485} 2486#endif /* OPT_REPORT_FONTS */ 2487 2488#if OPT_TRACE 2489 2490#if !OPT_WIDE_CHARS 2491static Char * 2492convertToUTF8(Char *buffer, int c) 2493{ 2494 buffer[0] = (Char) c; 2495 buffer[1] = 0; 2496 return buffer; 2497} 2498#endif 2499 2500static void 2501dumpXft(XtermWidget xw, XTermXftFonts *data) 2502{ 2503 XftFont *xft = XftFp(data); 2504 TScreen *screen = TScreenOf(xw); 2505 VTwin *win = WhichVWin(screen); 2506 2507 FcChar32 c; 2508 FcChar32 first = xtermXftFirstChar(xft); 2509 FcChar32 last = xtermXftLastChar(xft); 2510 FcChar32 dump; 2511 unsigned count = 0; 2512 unsigned too_high = 0; 2513 unsigned too_wide = 0; 2514 Boolean skip = False; 2515 2516 TRACE(("dumpXft " TRACE_L "\n")); 2517 TRACE(("\tdata range U+%04X..U+%04X\n", first, last)); 2518 TRACE(("\tcode\tcells\tdimensions\n")); 2519#if OPT_TRACE < 2 2520 dump = 255; 2521#else 2522 dump = last; 2523#endif 2524 for (c = first; c <= last; ++c) { 2525 if (FcCharSetHasChar(xft->charset, c)) { 2526 int width = CharWidth(screen, c); 2527 XGlyphInfo extents; 2528 Boolean big_x; 2529 Boolean big_y; 2530 2531 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2532 big_x = (extents.width > win->f_width); 2533 big_y = (extents.height > win->f_height); 2534 2535 if (c <= dump) { 2536 Char buffer[80]; 2537 2538 *convertToUTF8(buffer, c) = '\0'; 2539 TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n", 2540 (big_y ? "y" : ""), 2541 (big_x ? "x" : ""), 2542 c, width, 2543 ((double) extents.height) / win->f_height, 2544 ((double) extents.width) / win->f_width, 2545 buffer)); 2546 } else if (!skip) { 2547 skip = True; 2548 TRACE(("\t...skipping\n")); 2549 } 2550 if (big_y) 2551 ++too_high; 2552 if (big_x) 2553 ++too_wide; 2554 ++count; 2555 } 2556 } 2557 TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide)); 2558} 2559#define DUMP_XFT(xw, data) dumpXft(xw, data) 2560#else 2561#define DUMP_XFT(xw, data) /* nothing */ 2562#endif 2563 2564/* 2565 * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a 2566 * problem with web browsers. As of 2018/12 (4 years later), Xft does not work 2567 * with that. Even with this workaround, fontconfig has at least one bug which 2568 * causes it to crash (Debian #917034). 2569 */ 2570#ifdef FC_COLOR 2571#define GetFcBool(pattern, what) \ 2572 FcOK(FcPatternGetBool(pattern, what, 0, &fcbogus)) 2573 2574static Boolean 2575isBogusXft(XftFont *font) 2576{ 2577 Boolean result = False; 2578 if (font != 0) { 2579 FcBool fcbogus; 2580 if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) { 2581 TRACE(("...matched color-bitmap font\n")); 2582#if !USE_FC_COLOR 2583 result = True; 2584#endif 2585 } else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) { 2586 TRACE(("...matched non-outline font\n")); 2587 /* This is legal for regular bitmap fonts - fontconfig attempts to 2588 * find a match - but problematic for misencoded color-bitmap fonts. 2589 */ 2590 } 2591 } 2592 return result; 2593} 2594#endif 2595 2596#if OPT_BOX_CHARS 2597static void 2598setBrokenBoxChars(XtermWidget xw, Bool state) 2599{ 2600 TRACE(("setBrokenBoxChars %s\n", BtoS(state))); 2601 term->work.broken_box_chars = (Boolean) state; 2602 TScreenOf(xw)->broken_box_chars = (Boolean) state; 2603 update_font_boxchars(); 2604} 2605 2606#else 2607#define setBrokenBoxChars(xw, state) /* nothing */ 2608#endif 2609 2610static Boolean 2611checkedXftWidth(Display *dpy, 2612 XTermXftFonts *source, 2613 unsigned limit, 2614 Dimension *width, 2615 FcChar32 c) 2616{ 2617 Boolean result = False; 2618 2619 if (FcCharSetHasChar(XftFp(source)->charset, c)) { 2620 XGlyphInfo extents; 2621 2622 result = True; 2623 XftTextExtents32(dpy, XftFp(source), &c, 1, &extents); 2624 if (*width < extents.width && extents.width <= limit) { 2625 *width = extents.width; 2626 } 2627 } 2628 return result; 2629} 2630 2631/* 2632 * Check if the given character has a glyph known to Xft. This is likely to be 2633 * slower than checking our cache. 2634 * 2635 * see xc/lib/Xft/xftglyphs.c 2636 */ 2637static Bool 2638slowXftMissing(XtermWidget xw, XftFont *font, unsigned wc) 2639{ 2640 TScreen *screen = TScreenOf(xw); 2641 Bool result = False; 2642 2643 if (font != NULL) { 2644 if (XftCharIndex(screen->display, font, wc) == 0) 2645 result = True; 2646 } 2647 return result; 2648} 2649 2650static int 2651checkXftWidth(XtermWidget xw, XTermXftFonts *data) 2652{ 2653 FcChar32 c; 2654 FcChar32 last = xtermXftLastChar(XftFp(data)); 2655 Dimension limit = (Dimension) XftFp(data)->max_advance_width; 2656 Dimension width = 0; 2657 Dimension width2 = 0; 2658 int failed = 0; 2659#if OPT_WIDE_CHARS 2660 Cardinal n; 2661#endif 2662 2663 data->font_info.min_width = 0; 2664 data->font_info.max_width = limit; 2665 2666#if OPT_WIDE_CHARS 2667 /* 2668 * Check if the line-drawing characters are all provided in the font. 2669 * If so, take that into account for the cell-widths. 2670 */ 2671 for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) { 2672 if (!checkedXftWidth(XtDisplay(xw), 2673 data, 2674 limit, 2675 &width2, unicode_boxes[n].code)) { 2676 width2 = 0; 2677 TRACE(("font omits U+%04X line-drawing symbol\n", 2678 unicode_boxes[n].code)); 2679 break; 2680 } 2681 } 2682#else 2683 (void) width2; 2684#endif 2685 2686 if (width2 > 0) { 2687 Dimension check = (Dimension) (limit + 1) / 2; 2688 TRACE(("font provides VT100-style line-drawing\n")); 2689 /* 2690 * The "VT100 line-drawing" characters happen to be all "ambiguous 2691 * width" in Unicode's scheme. That means that they could be twice as 2692 * wide as the Latin-1 characters. 2693 */ 2694#define FC_ERR(n) (1.2 * (n)) 2695 if (width2 > FC_ERR(check)) { 2696 TRACE(("line-drawing characters appear to be double-width (ignore)\n")); 2697 setBrokenBoxChars(xw, True); 2698 } else if (width2 > width) { 2699 width = width2; 2700 } 2701 } else { 2702 TRACE(("font does NOT provide VT100-style line-drawing\n")); 2703 setBrokenBoxChars(xw, True); 2704 } 2705 2706 /* 2707 * For each printable code, ask what its width is. Given the maximum width 2708 * for those, we have a reasonable estimate of the single-column width. 2709 * 2710 * Ignore control characters - their extent information is misleading. 2711 */ 2712 for (c = 32; c < 256; ++c) { 2713 if (CharWidth(TScreenOf(xw), c) <= 0) 2714 continue; 2715 if (FcCharSetHasChar(XftFp(data)->charset, c)) { 2716 (void) checkedXftWidth(XtDisplay(xw), 2717 data, 2718 data->font_info.max_width, 2719 &width, c); 2720 } 2721 } 2722 2723 /* 2724 * Sometimes someone uses a symbol font which has no useful ASCII or 2725 * Latin-1 characters. Allow that, in case they did it intentionally. 2726 */ 2727 if (width == 0) { 2728 failed = 1; 2729 if (last >= 256) { 2730 width = data->font_info.max_width; 2731 } 2732 } 2733 data->font_info.min_width = width; 2734 data->font_info.mixed = (data->font_info.max_width >= 2735 (data->font_info.min_width + 1)); 2736 return failed; 2737} 2738 2739#if OPT_TRACE 2740static const char * 2741nameOfXftFont(XftFont *fp) 2742{ 2743 static char *result; 2744 char buffer[1024]; 2745 FreeAndNull(result); 2746 if (XftNameUnparse(fp->pattern, buffer, (int) sizeof(buffer))) { 2747 char *target; 2748 char *source = buffer; 2749 if ((target = strtok(source, ":")) != 0) { 2750 result = x_strdup(target); 2751 } 2752 } 2753 return NonNull(result); 2754} 2755#endif 2756 2757#if OPT_REPORT_FONTS 2758static void 2759reportXftFonts(XtermWidget xw, 2760 XTermXftFonts *fontData, 2761 int fontNum, 2762 XftFont *fp, 2763 const char *name, 2764 const char *tag, 2765 XftPattern *match) 2766{ 2767 if (resource.reportFonts) { 2768 char buffer[1024]; 2769 FcChar32 first_char = xtermXftFirstChar(fp); 2770 FcChar32 last_char = xtermXftLastChar(fp); 2771 FcChar32 ch; 2772 unsigned missing = 0; 2773 2774 ReportFonts("Loaded XftFonts(%s[%s])\n", name, tag); 2775 2776 for (ch = first_char; ch <= last_char; ++ch) { 2777 if (xtermXftMissing(xw, fontData, fontNum, fp, ch)) { 2778 ++missing; 2779 } 2780 } 2781 ReportFonts("\t\tfirst char: %u\n", first_char); 2782 ReportFonts("\t\tlast char: %u\n", last_char); 2783 ReportFonts("\t\tmissing-chars: %u\n", missing); 2784 ReportFonts("\t\tpresent-chars: %u\n", ((last_char - first_char) 2785 + 1 - missing)); 2786 2787 if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 2788 char *target; 2789 char *source = buffer; 2790 while ((target = strtok(source, ":")) != 0) { 2791 ReportFonts("\t%s\n", target); 2792 source = 0; 2793 } 2794 } 2795 fflush(stdout); 2796 } 2797} 2798 2799static void 2800reportXftFallbackFont(XtermWidget xw, 2801 XTermXftFonts *fontData, 2802 int fontNum, 2803 XftFont *font, 2804 XftPattern *match) 2805{ 2806 if (resource.reportFonts) { 2807 char tag[80]; 2808 sprintf(tag, "%s#%d", 2809 whichXftFonts(xw, fontData), 2810 fontNum + 1); 2811 reportXftFonts(xw, fontData, fontNum, font, "fallback", tag, match); 2812 } 2813} 2814 2815#else 2816#define reportXftFonts(xw, fontData, fontNum, result, name, tag, match) /* empty */ 2817#define reportXftFallbackFont(xw, fontData, fontNum, font, match) /* empty */ 2818#endif /* OPT_REPORT_FONTS */ 2819 2820/* 2821 * Xft discards the pattern-match during open-pattern if the result happens to 2822 * match a currently-open file, but provides no clue to the caller when it does 2823 * this. That is, closing a font-file may leave the data in Xft's cache, while 2824 * opening a file may free the data used for the match. 2825 * 2826 * Because of this problem, we cannot reliably refer to the pattern-match data 2827 * if it may have been seen before. 2828 */ 2829Boolean 2830maybeXftCache(XtermWidget xw, XftFont *font) 2831{ 2832 Boolean result = False; 2833 if (font != NULL) { 2834 TScreen *screen = TScreenOf(xw); 2835 ListXftFonts *p; 2836 for (p = screen->list_xft_fonts; p != NULL; p = p->next) { 2837 if (p->font == font) { 2838 result = True; 2839 break; 2840 } 2841 } 2842 if (!result) { 2843 p = TypeXtMalloc(ListXftFonts); 2844 if (p != NULL) { 2845 p->font = font; 2846 p->next = screen->list_xft_fonts; 2847 screen->list_xft_fonts = p; 2848 } 2849 } 2850 } 2851 return result; 2852} 2853 2854/* 2855 * Drop an entry from the cache, and close the font. 2856 */ 2857void 2858closeCachedXft(TScreen *screen, XftFont *font) 2859{ 2860 if (font != 0) { 2861 ListXftFonts *p, *q; 2862 2863 for (p = screen->list_xft_fonts, q = 0; p != 0; q = p, p = p->next) { 2864 if (p->font == font) { 2865 XftFontClose(screen->display, font); 2866 if (q != 0) { 2867 q->next = p->next; 2868 } else { 2869 screen->list_xft_fonts = p->next; 2870 } 2871 free(p); 2872 break; 2873 } 2874 } 2875 } 2876} 2877 2878static void 2879xtermOpenXft(XtermWidget xw, 2880 XTermXftFonts *fontData, 2881 int fontNum, 2882 const char *name, 2883 XftPattern *pat, 2884 const char *tag) 2885{ 2886 TScreen *screen = TScreenOf(xw); 2887 Display *dpy = screen->display; 2888 XftResult status; 2889 XftFont *result = 0; 2890 2891 TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag)); 2892 if (pat != 0 && (fontNum <= MaxXftCache)) { 2893 XftPattern *match; 2894 2895 FcConfigSubstitute(NULL, pat, FcMatchPattern); 2896 XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat); 2897 2898 match = FcFontMatch(NULL, pat, &status); 2899 if (match != 0) { 2900 Boolean maybeReopened = False; 2901 result = XftFontOpenPattern(dpy, match); 2902#ifdef FC_COLOR 2903 if (result != NULL) { 2904 if (isBogusXft(result)) { 2905 XftFontClose(dpy, result); 2906 result = NULL; 2907 maybeReopened = True; 2908 } 2909 } 2910#endif 2911 if (result != NULL) { 2912 TRACE(("...matched %s font\n", tag)); 2913 if (fontData->fs_size < fontNum) 2914 fontData->fs_size = fontNum; 2915 XftFpN(fontData, fontNum) = result; 2916 XftIsN(fontData, fontNum) = xcOpened; 2917 if (!maybeXftCache(xw, result)) { 2918 reportXftFonts(xw, fontData, fontNum, result, name, tag, match); 2919 } 2920 } else { 2921 TRACE(("...could not open %s font\n", tag)); 2922 if (!maybeReopened) 2923 XftPatternDestroy(match); 2924 if (xw->misc.fontWarnings >= fwAlways) { 2925 cannotFont(xw, "open", tag, name); 2926 } 2927 } 2928 } else { 2929 TRACE(("...did not match %s font\n", tag)); 2930 if (xw->misc.fontWarnings >= fwResource) { 2931 cannotFont(xw, "match", tag, name); 2932 } 2933 } 2934 } 2935 if (result == NULL && (fontNum <= MaxXftCache)) { 2936 XftFpN(fontData, fontNum) = NULL; 2937 XftIsN(fontData, fontNum) = xcEmpty; 2938 } 2939} 2940 2941#if OPT_SHIFT_FONTS 2942/* 2943 * Don't make a dependency on the math library for a single function. 2944 * (Newton Raphson). 2945 */ 2946static double 2947dimSquareRoot(double value) 2948{ 2949 double result = 0.0; 2950 if (value > 0.0) { 2951 int n; 2952 double older = value; 2953 for (n = 0; n < 10; ++n) { 2954 double delta = (older * older - value) / (2.0 * older); 2955 double newer = older - delta; 2956 older = newer; 2957 result = newer; 2958 if (delta > -0.001 && delta < 0.001) 2959 break; 2960 } 2961 } 2962 return result; 2963} 2964#endif 2965 2966#ifdef DEBUG_XFT 2967static void 2968trace_xft_glyph(XtermWidget xw, XTermXftFonts *data, FT_Face face, int code, const char *name) 2969{ 2970 if (xtermXftMissing(xw, data, 0, XftFp(data), code)) { 2971 TRACE(("Xft glyph U+%04X missing :%s\n", code, name)); 2972 } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 2973 FT_GlyphSlot g = face->glyph; 2974 TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 2975 code, 2976 g->bitmap.rows, g->bitmap.width, 2977 g->bitmap_top, g->bitmap_left, 2978 name)); 2979 } 2980} 2981 2982#if OPT_WIDE_CHARS 2983static void 2984trace_xft_line_drawing(XtermWidget xw, XTermXftFonts *data, FT_Face face) 2985{ 2986 int n; 2987 for (n = 0; unicode_boxes[n].code != 0; ++n) { 2988 trace_xft_glyph(xw, data, face, unicode_boxes[n].code, 2989 unicode_boxes[n].name); 2990 } 2991} 2992#else 2993#define trace_xft_line_drawing(xw, data, face) /* nothing */ 2994#endif 2995#endif /* DEBUG_XFT */ 2996 2997/* 2998 * Check if the line-drawing characters do not fill the bounding box. If so, 2999 * they're not useful. 3000 */ 3001#if OPT_BOX_CHARS 3002static void 3003linedrawing_gaps(XtermWidget xw, XTermXftFonts *data) 3004{ 3005 Boolean broken; 3006 3007#if OPT_WIDE_CHARS 3008 TScreen *screen = TScreenOf(xw); 3009 int n; 3010 FT_Face face; 3011 face = XftLockFace(XftFp(data)); 3012 broken = False; 3013 for (n = 0; unicode_boxes[n].code; ++n) { 3014 unsigned code = unicode_boxes[n].code; 3015 3016 if (xtermXftMissing(xw, data, 0, XftFp(data), code)) { 3017 TRACE(("Xft glyph U+%04X is missing\n", code)); 3018 broken = True; 3019 break; 3020 } 3021 3022 if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 3023 FT_GlyphSlot g = face->glyph; 3024 TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 3025 code, 3026 g->bitmap.rows, g->bitmap.width, 3027 g->bitmap_top, g->bitmap_left, 3028 unicode_boxes[n].name)); 3029 /* 3030 * While it is possible for badly-designed fonts to have line 3031 * drawing characters which do not meet, FreeType aggravates the 3032 * situation with its rounding. Check for an obvious case where 3033 * the weights at the ends of a vertical line do not add up. That 3034 * shows up as two under-weight rows at the beginning/end of the 3035 * bitmap. 3036 */ 3037 if (code == 0x2502) { 3038 unsigned r, c; 3039 unsigned mids = 0, ends = 0; 3040 unsigned char *buffer = g->bitmap.buffer; 3041 3042 switch (g->bitmap.pixel_mode) { 3043 case FT_PIXEL_MODE_MONO: 3044 /* FALLTHRU */ 3045 case FT_PIXEL_MODE_GRAY: 3046 for (r = 0; r < (unsigned) g->bitmap.rows; ++r) { 3047 unsigned k = r * (unsigned) g->bitmap.pitch; 3048 unsigned sum = 0; 3049 for (c = 0; c < (unsigned) g->bitmap.width; ++c) { 3050 unsigned xx = 0; 3051 switch (g->bitmap.pixel_mode) { 3052 case FT_PIXEL_MODE_MONO: 3053 xx = (unsigned) ((buffer[k + (c / 8)] 3054 >> (c % 8)) & 1); 3055 break; 3056 case FT_PIXEL_MODE_GRAY: 3057 xx = buffer[k + c]; 3058 break; 3059 } 3060 sum += xx; 3061 TRACE2((" %2x", xx)); 3062 } 3063 TRACE2((" = %u\n", sum)); 3064 if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) { 3065 mids = sum; 3066 } else { 3067 ends += sum; 3068 } 3069 } 3070 TRACE(("...compare middle %u vs ends %u\n", mids, ends)); 3071 if ((mids > ends) && (g->bitmap.rows < 16)) 3072 broken = True; 3073 break; 3074 default: 3075 TRACE(("FIXME pixel_mode %d not handled\n", 3076 g->bitmap.pixel_mode)); 3077 break; 3078 } 3079 if (broken) 3080 break; 3081 } 3082 /* 3083 * The factor of two accounts for line-drawing that goes through 3084 * the middle of a cell, possibly leaving half of the cell unused. 3085 * A horizontal line has to extend the full width of the cell. 3086 */ 3087 switch (unicode_boxes[n].high) { 3088 case 1: 3089 if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) { 3090 TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n", 3091 (unsigned) g->bitmap.rows, 3092 (unsigned) FontHeight(screen))); 3093 broken = True; 3094 } 3095 break; 3096 case 2: 3097 if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) { 3098 TRACE(("...bitmap is too short for half-cell (%u vs %u)\n", 3099 (unsigned) (g->bitmap.rows * 2), 3100 (unsigned) FontHeight(screen))); 3101 broken = True; 3102 } 3103 break; 3104 } 3105 switch (unicode_boxes[n].wide) { 3106 case 1: 3107 if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) { 3108 TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n", 3109 (unsigned) g->bitmap.width, 3110 (unsigned) FontWidth(screen))); 3111 broken = True; 3112 } 3113 break; 3114 case 2: 3115 if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) { 3116 TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n", 3117 (unsigned) (g->bitmap.width * 2), 3118 (unsigned) FontWidth(screen))); 3119 broken = True; 3120 } 3121 break; 3122 } 3123 if (broken) 3124 break; 3125 } 3126 } 3127 XftUnlockFace(XftFp(data)); 3128#else 3129 (void) data; 3130 broken = True; 3131#endif 3132 3133 if (broken) { 3134 TRACE(("Xft line-drawing would not work\n")); 3135 setBrokenBoxChars(xw, True); 3136 } 3137} 3138#endif /* OPT_BOX_CHARS */ 3139 3140/* 3141 * Given the Xft font metrics, determine the actual font size. This is used 3142 * for each font to ensure that normal, bold and italic fonts follow the same 3143 * rule. 3144 */ 3145static void 3146setRenderFontsize(XtermWidget xw, VTwin *win, XTermXftFonts *data, const char *tag) 3147{ 3148 XftFont *font = XftFp(data); 3149 if (font != NULL) { 3150 TScreen *screen = TScreenOf(xw); 3151 int width, height, ascent, descent; 3152#ifdef DEBUG_XFT 3153 int n; 3154 FT_Face face; 3155 FT_Size size; 3156 FT_Size_Metrics metrics; 3157 Boolean scalable; 3158 Boolean is_fixed; 3159 Boolean debug_xft = False; 3160 3161 face = XftLockFace(font); 3162 size = face->size; 3163 metrics = size->metrics; 3164 is_fixed = FT_IS_FIXED_WIDTH(face); 3165 scalable = FT_IS_SCALABLE(face); 3166 trace_xft_line_drawing(xw, data, face); 3167 for (n = 32; n < 127; ++n) { 3168 char name[80]; 3169 sprintf(name, "letter \"%c\"", n); 3170 trace_xft_glyph(xw, data, face, n, name); 3171 } 3172 XftUnlockFace(font); 3173 3174 /* freetype's inconsistent for this sign */ 3175 metrics.descender = -metrics.descender; 3176 3177#define TR_XFT "Xft metrics: " 3178#define D_64(name) ((double)(metrics.name)/64.0) 3179#define M_64(a,b) ((font->a * 64) != metrics.b) 3180#define BOTH(a,b) D_64(b), M_64(a,b) ? "*" : "" 3181 3182 debug_xft = (M_64(ascent, ascender) 3183 || M_64(descent, descender) 3184 || M_64(height, height) 3185 || M_64(max_advance_width, max_advance)); 3186 3187 TRACE(("Xft font is %sscalable, %sfixed-width\n", 3188 is_fixed ? "" : "not ", 3189 scalable ? "" : "not ")); 3190 3191 if (debug_xft) { 3192 TRACE(("Xft font size %d+%d vs %d by %d\n", 3193 font->ascent, 3194 font->descent, 3195 font->height, 3196 font->max_advance_width)); 3197 TRACE((TR_XFT "ascender %6.2f%s\n", BOTH(ascent, ascender))); 3198 TRACE((TR_XFT "descender %6.2f%s\n", BOTH(descent, descender))); 3199 TRACE((TR_XFT "height %6.2f%s\n", BOTH(height, height))); 3200 TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance))); 3201 } else { 3202 TRACE((TR_XFT "matches font\n")); 3203 } 3204#endif 3205 3206 width = font->max_advance_width; 3207 height = font->height; 3208 ascent = font->ascent; 3209 descent = font->descent; 3210 if (screen->force_xft_height && height < ascent + descent) { 3211 TRACE(("...height is less than ascent + descent (%u vs %u)\n", 3212 height, ascent + descent)); 3213 if ((ascent + descent) > (height + 1)) { 3214 /* this happens less than 10% of the time */ 3215 --ascent; 3216 --descent; 3217 TRACE(("...decrement both ascent and descent before retry\n")); 3218 } else if (ascent > descent) { 3219 /* this is the usual case */ 3220 --ascent; 3221 TRACE(("...decrement ascent before retry\n")); 3222 } else { 3223 /* this could happen, though rare... */ 3224 --descent; 3225 TRACE(("...decrement descent before retry\n")); 3226 } 3227 height = ascent + descent; 3228 font->ascent = ascent; 3229 font->descent = descent; 3230 TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n", 3231 height, ascent + descent, ascent, descent)); 3232 } 3233 if (is_double_width_font_xft(screen->display, font)) { 3234 TRACE(("...reduce width from %d to %d\n", width, width >> 1)); 3235 width >>= 1; 3236 } 3237 if (tag == 0) { 3238 SetFontWidth(screen, win, width); 3239 SetFontHeight(screen, win, height); 3240 win->f_ascent = ascent; 3241 win->f_descent = descent; 3242 TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 3243 width, height, ascent, descent)); 3244 } else if (win->f_width < width || 3245 win->f_height < height || 3246 win->f_ascent < ascent || 3247 win->f_descent < descent) { 3248 TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 3249 tag, 3250 win->f_width, win->f_height, win->f_ascent, win->f_descent, 3251 width, height, ascent, descent)); 3252 3253 SetFontWidth(screen, win, width); 3254 SetFontHeight(screen, win, height); 3255 win->f_ascent = ascent; 3256 win->f_descent = descent; 3257 } else { 3258 TRACE(("setRenderFontsize %s unchanged\n", tag)); 3259 } 3260#if OPT_BOX_CHARS 3261 if (!screen->broken_box_chars && (tag == 0)) { 3262 linedrawing_gaps(xw, data); 3263 } 3264#endif 3265 } 3266} 3267#endif 3268 3269static void 3270checkFontInfo(int value, const char *tag, int failed) 3271{ 3272 if (value == 0 || failed) { 3273 if (value == 0) { 3274 xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 3275 exit(1); 3276 } else { 3277 xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag); 3278 } 3279 } 3280} 3281 3282#if OPT_RENDERFONT 3283void 3284xtermCloseXft(TScreen *screen, XTermXftFonts *pub) 3285{ 3286 if (XftFp(pub) != NULL) { 3287 int n; 3288 3289 if (pub->pattern) { 3290 XftPatternDestroy(pub->pattern); 3291 pub->pattern = NULL; 3292 } 3293 if (pub->fontset) { 3294 XftFontSetDestroy(pub->fontset); 3295 pub->fontset = NULL; 3296 } 3297 3298 for (n = 0; n <= pub->fs_size; ++n) { 3299 if (XftFpN(pub, n) != NULL) { 3300 closeCachedXft(screen, XftFpN(pub, n)); 3301 XftFpN(pub, n) = NULL; 3302 XftIsN(pub, n) = xcEmpty; 3303 } 3304 } 3305 FreeAndNull(pub->font_map.per_font); 3306 memset(pub, 0, sizeof(*pub)); 3307 } 3308} 3309 3310/* 3311 * Get the faceName/faceNameDoublesize resource setting. 3312 */ 3313String 3314getFaceName(XtermWidget xw, Bool wideName) 3315{ 3316#if OPT_RENDERWIDE 3317 String result = (wideName 3318 ? FirstItemOf(xw->work.fonts.xft.list_w) 3319 : CurrentXftFont(xw)); 3320#else 3321 String result = CurrentXftFont(xw); 3322 (void) wideName; 3323#endif 3324 return x_nonempty(result); 3325} 3326 3327/* 3328 * If we change the faceName, we'll have to re-acquire all of the fonts that 3329 * are derived from it. 3330 */ 3331void 3332setFaceName(XtermWidget xw, const char *value) 3333{ 3334 TScreen *screen = TScreenOf(xw); 3335 Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0) 3336 || strcmp(CurrentXftFont(xw), value)); 3337 3338 if (changed) { 3339 int n; 3340 3341 CurrentXftFont(xw) = x_strdup(value); 3342 for (n = 0; n < NMENUFONTS; ++n) { 3343 int e; 3344 xw->misc.face_size[n] = -1.0; 3345 for (e = 0; e < fMAX; ++e) { 3346 xtermCloseXft(screen, getMyXftFont(xw, e, n)); 3347 } 3348 } 3349 } 3350} 3351#endif 3352 3353/* 3354 * Compute useful values for the font/window sizes 3355 */ 3356void 3357xtermComputeFontInfo(XtermWidget xw, 3358 VTwin *win, 3359 XFontStruct *font, 3360 int sbwidth) 3361{ 3362 TScreen *screen = TScreenOf(xw); 3363 3364 int i, j, width, height; 3365#if OPT_RENDERFONT 3366 int fontnum = screen->menu_font_number; 3367#endif 3368 int failed = 0; 3369 3370#if OPT_RENDERFONT 3371 /* 3372 * xterm contains a lot of references to fonts, assuming they are fixed 3373 * size. This chunk of code overrides the actual font-selection (see 3374 * drawXtermText()), if the user has selected render-font. All of the 3375 * font-loading for fixed-fonts still goes on whether or not this chunk 3376 * overrides it. 3377 */ 3378 if (UsingRenderFont(xw) && fontnum >= 0) { 3379 String face_name = getFaceName(xw, False); 3380 XTermXftFonts *norm = &(screen->renderFontNorm[fontnum]); 3381 XTermXftFonts *bold = &(screen->renderFontBold[fontnum]); 3382 XTermXftFonts *ital = &(screen->renderFontItal[fontnum]); 3383 XTermXftFonts *btal = &(screen->renderFontBtal[fontnum]); 3384#if OPT_RENDERWIDE 3385 XTermXftFonts *wnorm = &(screen->renderWideNorm[fontnum]); 3386 XTermXftFonts *wbold = &(screen->renderWideBold[fontnum]); 3387 XTermXftFonts *wital = &(screen->renderWideItal[fontnum]); 3388 XTermXftFonts *wbtal = &(screen->renderWideBtal[fontnum]); 3389#endif 3390 3391 if (XftFp(norm) == 0 && !IsEmpty(face_name)) { 3392 Work *work = &(xw->work); 3393 XftPattern *pat; 3394 double face_size; 3395 3396 TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 3397 fontnum, face_name, 3398 xw->misc.face_size[fontnum])); 3399 3400 TRACE(("Using Xft %d\n", XftGetVersion())); 3401 TRACE(("Using FontConfig %d\n", FC_VERSION)); 3402 3403 if (work->xft_defaults == NULL) { 3404 FcInit(); 3405 work->xft_defaults = FcPatternCreate(); 3406 XftDefaultSubstitute(screen->display, 3407 XScreenNumberOfScreen(XtScreen(xw)), 3408 work->xft_defaults); 3409 if (screen->xft_max_glyph_memory > 0) { 3410 FcPatternAddInteger(work->xft_defaults, 3411 XFT_MAX_GLYPH_MEMORY, 3412 screen->xft_max_glyph_memory); 3413 } 3414 if (screen->xft_max_unref_fonts > 0) { 3415 FcPatternAddInteger(work->xft_defaults, 3416 XFT_MAX_UNREF_FONTS, 3417 screen->xft_max_unref_fonts); 3418 } 3419#ifdef XFT_TRACK_MEM_USAGE 3420 FcPatternAddBool(work->xft_defaults, 3421 XFT_TRACK_MEM_USAGE, 3422 screen->xft_track_mem_usage); 3423#endif 3424 XftDefaultSet(screen->display, work->xft_defaults); 3425 } 3426 3427 fillInFaceSize(xw, fontnum); 3428 face_size = (double) xw->misc.face_size[fontnum]; 3429 3430 /* 3431 * By observation (there is no documentation), XftPatternBuild is 3432 * cumulative. Build the bold- and italic-patterns on top of the 3433 * normal pattern. 3434 */ 3435#ifdef FC_COLOR 3436#if USE_FC_COLOR 3437#define NormXftPattern \ 3438 XFT_FAMILY, XftTypeString, "mono", \ 3439 FC_OUTLINE, XftTypeBool, FcTrue, \ 3440 XFT_SIZE, XftTypeDouble, face_size 3441#else 3442#define NormXftPattern \ 3443 XFT_FAMILY, XftTypeString, "mono", \ 3444 FC_COLOR, XftTypeBool, FcFalse, \ 3445 FC_OUTLINE, XftTypeBool, FcTrue, \ 3446 XFT_SIZE, XftTypeDouble, face_size 3447#endif 3448#else 3449#define NormXftPattern \ 3450 XFT_FAMILY, XftTypeString, "mono", \ 3451 XFT_SIZE, XftTypeDouble, face_size 3452#endif 3453 3454#define BoldXftPattern(norm) \ 3455 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3456 XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3457 3458#define ItalXftPattern(norm) \ 3459 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3460 XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3461 3462#define BtalXftPattern(norm) \ 3463 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3464 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3465 XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3466 3467#if OPT_WIDE_ATTRS 3468#define HAVE_ITALICS 1 3469#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0) 3470#elif OPT_ISO_COLORS 3471#define HAVE_ITALICS 1 3472#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0) 3473#else 3474#define HAVE_ITALICS 0 3475#endif 3476 3477#if OPT_DEC_CHRSET 3478 freeall_DoubleFT(xw); 3479#endif 3480 if ((pat = XftNameParse(face_name)) != 0) { 3481#define OPEN_XFT(data, tag) xtermOpenXft(xw, data, 0, face_name, data->pattern, tag) 3482 norm->pattern = XftPatternDuplicate(pat); 3483 XftPatternBuild(norm->pattern, 3484 NormXftPattern, 3485 (void *) 0); 3486 OPEN_XFT(norm, "normal"); 3487 3488 if (XftFp(norm) != 0) { 3489 bold->pattern = XftPatternDuplicate(pat); 3490 XftPatternBuild(bold->pattern, 3491 NormXftPattern, 3492 BoldXftPattern(norm), 3493 (void *) 0); 3494 OPEN_XFT(bold, "bold"); 3495 3496#if HAVE_ITALICS 3497 if (FIND_ITALICS) { 3498 ital->pattern = XftPatternDuplicate(pat); 3499 XftPatternBuild(ital->pattern, 3500 NormXftPattern, 3501 ItalXftPattern(norm), 3502 (void *) 0); 3503 OPEN_XFT(ital, "italic"); 3504 btal->pattern = XftPatternDuplicate(pat); 3505 XftPatternBuild(btal->pattern, 3506 NormXftPattern, 3507 BtalXftPattern(norm), 3508 (void *) 0); 3509 OPEN_XFT(btal, "bold-italic"); 3510 } 3511#endif 3512 3513 /* 3514 * FIXME: just assume that the corresponding font has no 3515 * graphics characters. 3516 */ 3517 if (screen->fnt_boxes) { 3518 screen->fnt_boxes = 0; 3519 TRACE(("Xft opened - will not use internal line-drawing characters\n")); 3520 } 3521 } 3522 3523 CACHE_XFT(norm); 3524 3525 CACHE_XFT(bold); 3526 if (XftFp(norm) != 0 && !XftFp(bold)) { 3527 noUsableXft(xw, "bold"); 3528 XftPatternDestroy(bold->pattern); 3529 bold->pattern = XftPatternDuplicate(pat); 3530 XftPatternBuild(bold->pattern, 3531 NormXftPattern, 3532 (void *) 0); 3533 OPEN_XFT(bold, "bold"); 3534 failed = 0; 3535 CACHE_XFT(bold); 3536 } 3537#if HAVE_ITALICS 3538 CACHE_XFT(ital); 3539 if (XftFp(norm) != 0 && !XftFp(ital)) { 3540 noUsableXft(xw, "italic"); 3541 XftPatternDestroy(ital->pattern); 3542 ital->pattern = XftPatternDuplicate(pat); 3543 XftPatternBuild(ital->pattern, 3544 NormXftPattern, 3545 (void *) 0); 3546 OPEN_XFT(ital, "italics"); 3547 failed = 0; 3548 CACHE_XFT(ital); 3549 } 3550 CACHE_XFT(btal); 3551 if (XftFp(norm) != 0 && !XftFp(btal)) { 3552 noUsableXft(xw, "bold italic"); 3553 XftPatternDestroy(btal->pattern); 3554 btal->pattern = XftPatternDuplicate(pat); 3555 XftPatternBuild(btal->pattern, 3556 NormXftPattern, 3557 (void *) 0); 3558 OPEN_XFT(btal, "bold-italics"); 3559 failed = 0; 3560 CACHE_XFT(btal); 3561 } 3562#endif 3563 XftPatternDestroy(pat); 3564 } else { 3565 failed = 1; 3566 } 3567 3568 /* 3569 * See xtermXftDrawString(). A separate double-width font is nice 3570 * to have, but not essential. 3571 */ 3572#if OPT_RENDERWIDE 3573 if (XftFp(norm) != 0 && screen->wide_chars) { 3574 int char_width = XftFp(norm)->max_advance_width * 2; 3575 double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w) 3576 || screen->renderFontNorm[fontnum].font_info.mixed) 3577 ? 1.0 3578 : 2.0); 3579 3580 face_name = getFaceName(xw, True); 3581 TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 3582 NonNull(face_name), 3583 char_width)); 3584 3585#define WideXftPattern \ 3586 XFT_FAMILY, XftTypeString, "mono", \ 3587 XFT_SIZE, XftTypeDouble, face_size, \ 3588 XFT_SPACING, XftTypeInteger, XFT_MONO, \ 3589 XFT_CHAR_WIDTH, XftTypeInteger, char_width, \ 3590 FC_ASPECT, XftTypeDouble, aspect 3591 3592 if (!IsEmpty(face_name) && (pat = XftNameParse(face_name)) 3593 != 0) { 3594 wnorm->pattern = XftPatternDuplicate(pat); 3595 XftPatternBuild(wnorm->pattern, 3596 WideXftPattern, 3597 (void *) 0); 3598 OPEN_XFT(wnorm, "wide"); 3599 3600 if (XftFp(wnorm) != 0) { 3601 wbold->pattern = XftPatternDuplicate(pat); 3602 XftPatternBuild(wbold->pattern, 3603 WideXftPattern, 3604 BoldXftPattern(wnorm), 3605 (void *) 0); 3606 OPEN_XFT(wbold, "wide-bold"); 3607 3608#if HAVE_ITALICS 3609 if (FIND_ITALICS) { 3610 wital->pattern = XftPatternDuplicate(pat); 3611 XftPatternBuild(wital->pattern, 3612 WideXftPattern, 3613 ItalXftPattern(wnorm), 3614 (void *) 0); 3615 OPEN_XFT(wital, "wide-italic"); 3616 } 3617 CACHE_XFT(wbtal); 3618 if (!XftFp(wbtal)) { 3619 noUsableXft(xw, "wide bold"); 3620 XftPatternDestroy(wbtal->pattern); 3621 wbtal->pattern = XftPatternDuplicate(pat); 3622 XftPatternBuild(wbtal->pattern, 3623 WideXftPattern, 3624 (void *) 0); 3625 OPEN_XFT(wbtal, "wide-bold-italics"); 3626 failed = 0; 3627 CACHE_XFT(wbtal); 3628 } 3629#endif 3630 } 3631 3632 CACHE_XFT(wnorm); 3633 3634 CACHE_XFT(wbold); 3635 if (XftFp(wnorm) != 0 && !XftFp(wbold)) { 3636 noUsableXft(xw, "wide-bold"); 3637 XftPatternDestroy(wbold->pattern); 3638 wbold->pattern = XftPatternDuplicate(pat); 3639 XftPatternBuild(bold->pattern, 3640 WideXftPattern, 3641 (void *) 0); 3642 OPEN_XFT(wbold, "wide-bold"); 3643 failed = 0; 3644 CACHE_XFT(bold); 3645 } 3646 3647 CACHE_XFT(wital); 3648 if (XftFp(wnorm) != 0 && !XftFp(wital)) { 3649 noUsableXft(xw, "wide-italic"); 3650 XftPatternDestroy(wital->pattern); 3651 wital->pattern = XftPatternDuplicate(pat); 3652 XftPatternBuild(wital->pattern, 3653 WideXftPattern, 3654 (void *) 0); 3655 OPEN_XFT(wital, "wide-italic"); 3656 failed = 0; 3657 CACHE_XFT(wital); 3658 } 3659 3660 XftPatternDestroy(pat); 3661 } 3662#undef OPEN_XFT 3663 } 3664#endif /* OPT_RENDERWIDE */ 3665 } 3666 if (XftFp(norm) == 0) { 3667 TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 3668 xw->work.render_font = False; 3669 update_font_renderfont(); 3670 /* now we will fall through into the bitmap fonts */ 3671 } else { 3672 setBrokenBoxChars(xw, False); 3673 setRenderFontsize(xw, win, norm, NULL); 3674 setRenderFontsize(xw, win, bold, "bold"); 3675 setRenderFontsize(xw, win, ital, "ital"); 3676 setRenderFontsize(xw, win, btal, "btal"); 3677#if OPT_BOX_CHARS 3678 setupPackedFonts(xw); 3679 3680 if (screen->force_packed) { 3681 XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 3682 SetFontHeight(screen, win, XftFp(use)->ascent + XftFp(use)->descent); 3683 SetFontWidth(screen, win, use->font_info.min_width); 3684 TRACE(("...packed TrueType font %dx%d vs %d\n", 3685 win->f_height, 3686 win->f_width, 3687 use->font_info.max_width)); 3688 } 3689#endif 3690 DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 3691 } 3692 } 3693 /* 3694 * Are we handling a bitmap font? 3695 */ 3696 else 3697#endif /* OPT_RENDERFONT */ 3698 { 3699 if (is_double_width_font(font) && !(screen->fnt_prop)) { 3700 SetFontWidth(screen, win, font->min_bounds.width); 3701 } else { 3702 SetFontWidth(screen, win, font->max_bounds.width); 3703 } 3704 SetFontHeight(screen, win, font->ascent + font->descent); 3705 win->f_ascent = font->ascent; 3706 win->f_descent = font->descent; 3707 } 3708 i = 2 * screen->border + sbwidth; 3709 j = 2 * screen->border; 3710 width = MaxCols(screen) * win->f_width + i; 3711 height = MaxRows(screen) * win->f_height + j; 3712 win->fullwidth = (Dimension) width; 3713 win->fullheight = (Dimension) height; 3714 win->width = width - i; 3715 win->height = height - j; 3716 3717 TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 3718 win->height, 3719 win->width, 3720 win->fullheight, 3721 win->fullwidth, 3722 win->f_height, 3723 win->f_width, 3724 win->f_ascent, 3725 win->f_descent)); 3726 3727 checkFontInfo(win->f_height, "height", failed); 3728 checkFontInfo(win->f_width, "width", failed); 3729} 3730 3731/* save this information as a side-effect for double-sized characters */ 3732static void 3733xtermSaveFontInfo(TScreen *screen, XFontStruct *font) 3734{ 3735 screen->fnt_wide = (Dimension) (font->max_bounds.width); 3736 screen->fnt_high = (Dimension) (font->ascent + font->descent); 3737 TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 3738} 3739 3740/* 3741 * After loading a new font, update the structures that use its size. 3742 */ 3743void 3744xtermUpdateFontInfo(XtermWidget xw, Bool doresize) 3745{ 3746 TScreen *screen = TScreenOf(xw); 3747 3748 int scrollbar_width; 3749 VTwin *win = &(screen->fullVwin); 3750 3751#if USE_DOUBLE_BUFFER 3752 discardRenderDraw(TScreenOf(xw)); 3753#endif /* USE_DOUBLE_BUFFER */ 3754 3755 scrollbar_width = (xw->misc.scrollbar 3756 ? (screen->scrollWidget->core.width + 3757 BorderWidth(screen->scrollWidget)) 3758 : 0); 3759 xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width); 3760 xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs); 3761 3762 if (doresize) { 3763 if (VWindow(screen)) { 3764 xtermClear(xw); 3765 } 3766 TRACE(("xtermUpdateFontInfo " TRACE_L "\n")); 3767 DoResizeScreen(xw); /* set to the new natural size */ 3768 ResizeScrollBar(xw); 3769 Redraw(); 3770 TRACE((TRACE_R " xtermUpdateFontInfo\n")); 3771#ifdef SCROLLBAR_RIGHT 3772 updateRightScrollbar(xw); 3773#endif 3774 } 3775 xtermSetCursorBox(screen); 3776} 3777 3778#if OPT_BOX_CHARS || OPT_REPORT_FONTS 3779 3780/* 3781 * Returns true if the given character is missing from the specified font. 3782 */ 3783Bool 3784xtermMissingChar(unsigned ch, XTermFonts * font) 3785{ 3786 Bool result = False; 3787 XFontStruct *fs = font->fs; 3788 XCharStruct *pc = 0; 3789 3790 if (fs == NULL) { 3791 result = True; 3792 } else if (fs->max_byte1 == 0) { 3793#if OPT_WIDE_CHARS 3794 if (ch < 256) 3795#endif 3796 { 3797 CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc); 3798 } 3799 } 3800#if OPT_WIDE_CHARS 3801 else { 3802 unsigned row = (ch >> 8); 3803 unsigned col = (ch & 0xff); 3804 CI_GET_CHAR_INFO_2D(fs, row, col, pc); 3805 } 3806#endif 3807 3808 if (pc == 0 || CI_NONEXISTCHAR(pc)) { 3809 TRACE2(("xtermMissingChar %#04x (!exists)\n", ch)); 3810 result = True; 3811 } 3812 if (ch < MaxUChar) { 3813 font->known_missing[ch] = (Char) (result ? 2 : 1); 3814 } 3815 return result; 3816} 3817#endif 3818 3819#if OPT_BOX_CHARS 3820/* 3821 * The grid is arbitrary, enough resolution that nothing's lost in 3822 * initialization. 3823 */ 3824#define BOX_HIGH 60 3825#define BOX_WIDE 60 3826 3827#define MID_HIGH (BOX_HIGH/2) 3828#define MID_WIDE (BOX_WIDE/2) 3829 3830#define CHR_WIDE ((9*BOX_WIDE)/10) 3831#define CHR_HIGH ((9*BOX_HIGH)/10) 3832 3833/* 3834 * ...since we'll scale the values anyway. 3835 */ 3836#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d) 3837#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width) 3838#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height) 3839#define SCALE_X(n) n = SCALED_X(n) 3840#define SCALE_Y(n) n = SCALED_Y(n) 3841 3842#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 3843 3844/* 3845 * Draw the given graphic character, if it is simple enough (i.e., a 3846 * line-drawing character). 3847 */ 3848void 3849xtermDrawBoxChar(XTermDraw * params, 3850 unsigned ch, 3851 GC gc, 3852 int x, 3853 int y, 3854 int cells, 3855 Bool xftords) 3856{ 3857 TScreen *screen = TScreenOf(params->xw); 3858 /* *INDENT-OFF* */ 3859 static const short glyph_ht[] = { 3860 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 3861 SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 3862 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 3863 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3864 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3865 -1 3866 }, glyph_ff[] = { 3867 SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 3868 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 3869 SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 3870 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3871 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3872 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3873 -1 3874 }, glyph_lf[] = { 3875 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 3876 SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 3877 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3878 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3879 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3880 -1 3881 }, glyph_nl[] = { 3882 SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 3883 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 3884 SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3885 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 3886 SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 3887 -1 3888 }, glyph_vt[] = { 3889 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 3890 SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3891 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3892 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3893 -1 3894 }, plus_or_minus[] = 3895 { 3896 SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 3897 SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 3898 SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 3899 -1 3900 }, lower_right_corner[] = 3901 { 3902 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3903 SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 3904 -1 3905 }, upper_right_corner[] = 3906 { 3907 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3908 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3909 -1 3910 }, upper_left_corner[] = 3911 { 3912 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3913 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3914 -1 3915 }, lower_left_corner[] = 3916 { 3917 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3918 SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 3919 -1 3920 }, cross[] = 3921 { 3922 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3923 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3924 -1 3925 }, scan_line_1[] = 3926 { 3927 SEG( 0, 0, BOX_WIDE, 0), 3928 -1 3929 }, scan_line_3[] = 3930 { 3931 SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 3932 -1 3933 }, scan_line_7[] = 3934 { 3935 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3936 -1 3937 }, scan_line_9[] = 3938 { 3939 SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 3940 -1 3941 }, horizontal_line[] = 3942 { 3943 SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 3944 -1 3945 }, left_tee[] = 3946 { 3947 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3948 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 3949 -1 3950 }, right_tee[] = 3951 { 3952 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3953 SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 3954 -1 3955 }, bottom_tee[] = 3956 { 3957 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3958 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 3959 -1 3960 }, top_tee[] = 3961 { 3962 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 3963 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3964 -1 3965 }, vertical_line[] = 3966 { 3967 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3968 -1 3969 }, less_than_or_equal[] = 3970 { 3971 SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 3972 SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 3973 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3974 -1 3975 }, greater_than_or_equal[] = 3976 { 3977 SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3978 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3979 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3980 -1 3981 }, greek_pi[] = 3982 { 3983 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3984 SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 3985 SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 3986 -1 3987 }, not_equal_to[] = 3988 { 3989 SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 3990 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 3991 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3992 -1 3993 }; 3994 3995 static const struct { 3996 const int mode; /* 1=y, 2=x, 3=both */ 3997 const short *const data; 3998 } lines[] = 3999 { 4000 { 0, 0 }, /* 00 (unused) */ 4001 { 0, 0 }, /* 01 diamond */ 4002 { 0, 0 }, /* 02 box */ 4003 { 0, glyph_ht }, /* 03 HT */ 4004 { 0, glyph_ff }, /* 04 FF */ 4005 { 0, 0 }, /* 05 CR */ 4006 { 0, glyph_lf }, /* 06 LF */ 4007 { 0, 0 }, /* 07 degrees (small circle) */ 4008 { 3, plus_or_minus }, /* 08 */ 4009 { 0, glyph_nl }, /* 09 */ 4010 { 0, glyph_vt }, /* 0A */ 4011 { 3, lower_right_corner }, /* 0B */ 4012 { 3, upper_right_corner }, /* 0C */ 4013 { 3, upper_left_corner }, /* 0D */ 4014 { 3, lower_left_corner }, /* 0E */ 4015 { 3, cross }, /* 0F */ 4016 { 2, scan_line_1 }, /* 10 */ 4017 { 2, scan_line_3 }, /* 11 */ 4018 { 2, scan_line_7 }, /* 12 */ 4019 { 2, scan_line_9 }, /* 13 */ 4020 { 2, horizontal_line }, /* 14 */ 4021 { 3, left_tee }, /* 15 */ 4022 { 3, right_tee }, /* 16 */ 4023 { 3, bottom_tee }, /* 17 */ 4024 { 3, top_tee }, /* 18 */ 4025 { 1, vertical_line }, /* 19 */ 4026 { 0, less_than_or_equal }, /* 1A */ 4027 { 0, greater_than_or_equal }, /* 1B */ 4028 { 0, greek_pi }, /* 1C */ 4029 { 0, not_equal_to }, /* 1D */ 4030 { 0, 0 }, /* 1E LB */ 4031 { 0, 0 }, /* 1F bullet */ 4032 }; 4033 /* *INDENT-ON* */ 4034 4035 GC gc2; 4036 CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 4037 VTwin *cgsWin = WhichVWin(screen); 4038 const short *p; 4039 unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U) 4040 * screen->fnt_wide); 4041 unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U) 4042 * screen->fnt_high); 4043 unsigned thick; 4044 4045 if (cells > 1) 4046 font_width *= (unsigned) cells; 4047 4048#if OPT_WIDE_CHARS 4049 /* 4050 * Try to show line-drawing characters if we happen to be in UTF-8 4051 * mode, but have gotten an old-style font. 4052 */ 4053 if (screen->utf8_mode 4054#if OPT_RENDERFONT 4055 && !UsingRenderFont(params->xw) 4056#endif 4057 && (ch > 127) 4058 && (ch != UCS_REPL)) { 4059 int which = (params->attr_flags & BOLD) ? fBold : fNorm; 4060 unsigned n; 4061 for (n = 1; n < 32; n++) { 4062 if (xtermMissingChar(n, getNormalFont(screen, which))) 4063 continue; 4064 if (dec2ucs(screen, n) != ch) 4065 continue; 4066 TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n)); 4067 ch = n; 4068 break; 4069 } 4070 } 4071#endif 4072 4073#if OPT_VT52_MODE 4074 if (!(screen->vtXX_level)) { 4075 switch (ch) { 4076 case 6: 4077 ch = 7; 4078 break; 4079 default: 4080 ch = 256; 4081 break; 4082 } 4083 } 4084#endif 4085 4086 /* 4087 * Line-drawing characters show use the full (scaled) cellsize, while 4088 * other characters should be shifted to center them vertically. 4089 */ 4090 if (!xftords) { 4091 if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) { 4092 font_height = (unsigned) ((float) font_height * screen->scale_height); 4093 } else { 4094 y += ScaleShift(screen); 4095 } 4096 } 4097 4098 TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n", 4099 ch, font_height, font_width, y, x, 4100 ((ch >= XtNumber(lines)) 4101 ? "-BAD" 4102 : ""))); 4103 4104 if (cgsId == gcDots) { 4105 setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4106 setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 4107 setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4108 } else { 4109 setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4110 setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4111 setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4112 } 4113 gc2 = getCgsGC(params->xw, cgsWin, cgsId); 4114 4115 if (!(params->draw_flags & NOBACKGROUND)) { 4116 XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 4117 font_width, 4118 font_height); 4119 } 4120 4121 setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4122 setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 4123 setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4124 gc2 = getCgsGC(params->xw, cgsWin, cgsId); 4125 4126 thick = ((params->attr_flags & BOLD) 4127 ? (Max((unsigned) screen->fnt_high / 12, 1)) 4128 : (Max((unsigned) screen->fnt_high / 16, 1))), 4129 XSetLineAttributes(screen->display, gc2, 4130 thick, 4131 ((ch < XtNumber(lines)) 4132 ? LineSolid 4133 : LineOnOffDash), /* like xtermDrawMissing */ 4134 CapProjecting, 4135 JoinMiter); 4136 4137 if (ch == 1) { /* diamond */ 4138 XPoint points[5]; 4139 int npoints = 5, n; 4140 4141 points[0].x = MID_WIDE; 4142 points[0].y = BOX_HIGH / 4; 4143 4144 points[1].x = 8 * BOX_WIDE / 8; 4145 points[1].y = MID_HIGH; 4146 4147 points[2].x = points[0].x; 4148 points[2].y = 3 * BOX_HIGH / 4; 4149 4150 points[3].x = 0 * BOX_WIDE / 8; 4151 points[3].y = points[1].y; 4152 4153 points[4].x = points[0].x; 4154 points[4].y = points[0].y; 4155 4156 for (n = 0; n < npoints; ++n) { 4157 points[n].x = (short) (SCALED_X(points[n].x)); 4158 points[n].y = (short) (SCALED_Y(points[n].y)); 4159 points[n].x = (short) (points[n].x + x); 4160 points[n].y = (short) (points[n].y + y); 4161 } 4162 4163 XFillPolygon(screen->display, 4164 VDrawable(screen), gc2, 4165 points, npoints, 4166 Convex, CoordModeOrigin); 4167 } else if (ch == 7) { /* degrees */ 4168 unsigned width = (BOX_WIDE / 3); 4169 int x_coord = MID_WIDE - (int) (width / 2); 4170 int y_coord = MID_HIGH - (int) width; 4171 4172 SCALE_X(x_coord); 4173 SCALE_Y(y_coord); 4174 width = (unsigned) SCALED_X(width); 4175 4176 XDrawArc(screen->display, 4177 VDrawable(screen), gc2, 4178 x + x_coord, y + y_coord, width, width, 4179 0, 4180 360 * 64); 4181 } else if (ch == 0x1f) { /* bullet */ 4182 unsigned width = 7 * BOX_WIDE / 10; 4183 int x_coord = MID_WIDE - (int) (width / 3); 4184 int y_coord = MID_HIGH - (int) (width / 3); 4185 4186 SCALE_X(x_coord); 4187 SCALE_Y(y_coord); 4188 width = (unsigned) SCALED_X(width); 4189 4190 XDrawArc(screen->display, 4191 VDrawable(screen), gc2, 4192 x + x_coord, y + y_coord, width, width, 4193 0, 4194 360 * 64); 4195 } else if (ch < XtNumber(lines) 4196 && (p = lines[ch].data) != 0) { 4197 int coord[4]; 4198 int n = 0; 4199 while (*p >= 0) { 4200 coord[n++] = *p++; 4201 if (n == 4) { 4202 SCALE_X(coord[0]); 4203 SCALE_Y(coord[1]); 4204 SCALE_X(coord[2]); 4205 SCALE_Y(coord[3]); 4206 XDrawLine(screen->display, 4207 VDrawable(screen), gc2, 4208 x + coord[0], y + coord[1], 4209 x + coord[2], y + coord[3]); 4210 n = 0; 4211 } 4212 } 4213 } else if (screen->force_all_chars) { 4214 /* bounding rectangle, for debugging */ 4215 if ((params->draw_flags & DOUBLEHFONT)) { 4216 XRectangle clip; 4217 4218 clip.x = 0; 4219 clip.y = 0; 4220 clip.width = (unsigned short) ((font_width - 1) + (unsigned) thick); 4221 clip.height = (unsigned short) ((unsigned) FontHeight(screen) + thick); 4222 4223 if ((params->draw_flags & DOUBLEFIRST)) { 4224 y -= (2 * FontDescent(screen)); 4225 clip.height = 4226 (unsigned short) (clip.height 4227 - ((unsigned short) FontDescent(screen))); 4228 } else { 4229 y -= FontHeight(screen); 4230 y += FontDescent(screen); 4231 clip.y = (short) FontHeight(screen); 4232 } 4233 XSetClipRectangles(screen->display, gc2, x, y, &clip, 1, Unsorted); 4234 } 4235 XDrawRectangle(screen->display, VDrawable(screen), gc2, 4236 x + (int) thick, y + (int) thick, 4237 font_width - (2 * thick), 4238 font_height - (2 * thick)); 4239 if ((params->draw_flags & DOUBLEHFONT)) { 4240 XSetClipMask(screen->display, gc2, None); 4241 } 4242 } 4243} 4244#endif /* OPT_BOX_CHARS */ 4245 4246#if OPT_RENDERFONT 4247static int 4248checkXftGlyph(XtermWidget xw, XftFont *font, unsigned wc) 4249{ 4250 TScreen *screen = TScreenOf(xw); 4251 int result = 0; 4252 int expect; 4253 4254 if ((expect = CharWidth(screen, wc)) > 0) { 4255 XGlyphInfo gi; 4256 int actual; 4257 int limit = (100 + xw->misc.limit_fontwidth); 4258 4259 XftTextExtents32(screen->display, font, &wc, 1, &gi); 4260 /* 4261 * Some (more than a few) fonts are sloppy; allow 10% outside 4262 * the bounding box to accommodate them. 4263 */ 4264 actual = ((gi.xOff * 100) >= (limit * FontWidth(screen))) ? 2 : 1; 4265 if (actual <= expect) { 4266 /* allow double-cell if wcwidth agrees */ 4267 result = 1; 4268 } else { 4269 /* 4270 * Do not use this font for this specific character, but 4271 * possibly other characters can be used. 4272 */ 4273 result = -1; 4274 TRACE(("SKIP U+%04X %d vs %d (%d vs %d) %s\n", 4275 wc, gi.xOff, FontWidth(screen), actual, expect, 4276 nameOfXftFont(font))); 4277 } 4278 } else { 4279 result = 1; 4280 } 4281 return result; 4282} 4283 4284/* 4285 * Check if the glyph is defined in the given font, and (try to) filter out 4286 * cases where double-width glyphs are stuffed into a single-width outline. 4287 */ 4288static int 4289foundXftGlyph(XtermWidget xw, XTermXftFonts *data, int fontNum, unsigned wc) 4290{ 4291 XftFont *font = XftFpN(data, fontNum); 4292 int result = 0; 4293 4294 if (font != 0) { 4295 if (!xtermXftMissing(xw, data, fontNum, font, wc)) { 4296 4297 if (XftIsN(data, fontNum) == xcBogus) { 4298 ; 4299 } else if (XftIsN(data, fontNum) == xcOpened) { 4300 result = 1; 4301 } else { 4302 result = checkXftGlyph(xw, font, wc); 4303 } 4304 } 4305 } 4306 return result; 4307} 4308 4309static void 4310markXftOpened(XtermWidget xw, XTermXftFonts *which, int n, unsigned wc) 4311{ 4312 if (XftIsN(which, n) != xcOpened) { 4313 which->opened++; 4314 XftIsN(which, n) = xcOpened; 4315 /* XFT_DEBUG=3 will show useful context for this */ 4316 if (getenv("XFT_DEBUG") != 0) { 4317 printf("%s: matched U+%04X in fontset #%d [%u:%u]\n", 4318 ProgramName, 4319 wc, n + 1, 4320 which->opened, 4321 xw->work.max_fontsets); 4322 } 4323 } 4324} 4325 4326static char ** 4327xftData2List(XtermWidget xw, XTermXftFonts *fontData) 4328{ 4329 TScreen *screen = TScreenOf(xw); 4330 VTFontList *lists = &xw->work.fonts.xft; 4331 char **result = NULL; 4332 int n = screen->menu_font_number; 4333 4334 if (fontData == &screen->renderFontNorm[n]) 4335 result = lists->list_n; 4336 else if (fontData == &screen->renderFontBold[n]) 4337 result = lists->list_b; 4338 else if (fontData == &screen->renderFontItal[n]) 4339 result = lists->list_i; 4340 else if (fontData == &screen->renderFontBtal[n]) 4341 result = lists->list_bi; 4342#if OPT_RENDERWIDE 4343 if (fontData == &screen->renderWideNorm[n]) 4344 result = lists->list_w; 4345 else if (fontData == &screen->renderWideBold[n]) 4346 result = lists->list_wb; 4347 else if (fontData == &screen->renderWideItal[n]) 4348 result = lists->list_wi; 4349 else if (fontData == &screen->renderWideBtal[n]) 4350 result = lists->list_wbi; 4351#endif 4352 return result; 4353} 4354 4355static FcPattern * 4356mergeXftStyle(XtermWidget xw, FcPattern * myPattern, XTermXftFonts *fontData) 4357{ 4358 TScreen *screen = TScreenOf(xw); 4359 Display *dpy = screen->display; 4360 XftFont *given = XftFp(fontData); 4361 XftResult mStatus; 4362 int iValue; 4363 double dValue; 4364 4365 if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_WEIGHT, 0, &iValue))) { 4366 FcPatternAddInteger(myPattern, XFT_WEIGHT, iValue); 4367 } 4368 if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_SLANT, 0, &iValue))) { 4369 FcPatternAddInteger(myPattern, XFT_SLANT, iValue); 4370 } 4371 if (FcOK(FcPatternGetDouble(fontData->pattern, FC_ASPECT, 0, &dValue))) { 4372 FcPatternAddDouble(myPattern, FC_ASPECT, dValue); 4373 } 4374 if (FcOK(FcPatternGetDouble(fontData->pattern, XFT_SIZE, 0, &dValue))) { 4375 FcPatternAddDouble(myPattern, XFT_SIZE, dValue); 4376 } 4377 FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4378 FcPatternAddInteger(myPattern, XFT_SPACING, XFT_MONO); 4379 FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4380#ifdef FC_COLOR 4381#if !USE_FC_COLOR 4382 FcPatternAddBool(myPattern, FC_COLOR, FcFalse); 4383#endif 4384 FcPatternAddBool(myPattern, FC_OUTLINE, FcTrue); 4385#endif 4386 4387 FcConfigSubstitute(NULL, myPattern, FcMatchPattern); 4388 XftDefaultSubstitute(dpy, DefaultScreen(dpy), myPattern); 4389 4390 return FcFontMatch(NULL, myPattern, &mStatus); 4391} 4392 4393/* 4394 * Check if the given character has a glyph known to Xft. If it is missing, 4395 * try first to replace the font with a fallback that provides the glyph. 4396 * 4397 * Return -1 if nothing is found. Otherwise, return the index in the cache. 4398 */ 4399int 4400findXftGlyph(XtermWidget xw, XTermXftFonts *fontData, unsigned wc) 4401{ 4402 TScreen *screen = TScreenOf(xw); 4403 XftFont *given; 4404 XftFont *actual = NULL; 4405 FcResult status; 4406 int n; 4407 int result = -1; 4408 4409 /* sanity-check */ 4410 if (fontData == NULL) 4411 return result; 4412 given = XftFp(fontData); 4413 4414 /* if fontsets are not wanted, just leave */ 4415 if (xw->work.max_fontsets == 0) { 4416 return result; 4417 } 4418 4419 /* ignore codes in private use areas */ 4420 if ((wc >= 0xe000 && wc <= 0xf8ff) 4421 || (wc >= 0xf0000 && wc <= 0xffffd) 4422 || (wc >= 0x100000 && wc <= 0x10fffd)) { 4423 return result; 4424 } 4425 /* the end of the BMP is reserved for non-characters */ 4426 if (wc >= 0xfff0 && wc <= 0xffff) { 4427 return result; 4428 } 4429 4430 /* initialize on the first call */ 4431 if (fontData->fontset == NULL && fontData->pattern != NULL) { 4432 FcFontSet *sortedFonts; 4433 FcPattern *myPattern; 4434 int j; 4435 char **my_list; 4436 4437 myPattern = FcPatternDuplicate(fontData->pattern); 4438 4439 FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4440 FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4441 4442 FcConfigSubstitute(FcConfigGetCurrent(), 4443 myPattern, 4444 FcMatchPattern); 4445 FcDefaultSubstitute(myPattern); 4446 4447 sortedFonts = FcFontSort(NULL, myPattern, FcTrue, NULL, &status); 4448 4449 fontData->fontset = FcFontSetCreate(); 4450 4451 if (fontData->fontset == 0 || !sortedFonts || sortedFonts->nfont <= 0) { 4452 xtermWarning("did not find any usable TrueType font\n"); 4453 return 0; 4454 } 4455 4456 /* 4457 * Check if there are additional fonts in the XtermFontNames.xft for 4458 * this font-data. 4459 */ 4460 if ((my_list = xftData2List(xw, fontData)) != NULL 4461 && *++my_list != NULL) { 4462 for (j = 0; my_list[j] != NULL; ++j) { 4463 FcPattern *extraPattern; 4464 if ((extraPattern = XftNameParse(my_list[j])) != 0) { 4465 FcPattern *match; 4466 4467 match = mergeXftStyle(xw, extraPattern, fontData); 4468 4469 if (match != NULL) { 4470 FcFontSetAdd(fontData->fontset, match); 4471 } 4472 FcPatternDestroy(extraPattern); 4473 } 4474 } 4475 } 4476 4477 for (j = 0; j < sortedFonts->nfont; j++) { 4478 FcPattern *font_pattern; 4479 4480 font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(), 4481 myPattern, 4482 sortedFonts->fonts[j]); 4483 if (font_pattern) { 4484 FcFontSetAdd(fontData->fontset, font_pattern); 4485 } 4486 } 4487 4488 FcFontSetSortDestroy(sortedFonts); 4489 FcPatternDestroy(myPattern); 4490 4491 fontData->fs_size = Min(MaxXftCache, fontData->fontset->nfont); 4492 } 4493 if (fontData->fontset != NULL && fontData->fs_size > 0) { 4494 XftFont *check; 4495 int empty = fontData->fs_size; 4496 4497 for (n = 1; n <= fontData->fs_size; ++n) { 4498 XTermXftState usage = XftIsN(fontData, n); 4499 if (usage == xcEmpty) { 4500 if (empty > n) 4501 empty = n; 4502 } else if (usage == xcOpened 4503 || (usage == xcUnused 4504 && (fontData->opened < xw->work.max_fontsets))) { 4505 check = XftFpN(fontData, n); 4506 if (foundXftGlyph(xw, fontData, (int) n, wc)) { 4507 markXftOpened(xw, fontData, n, wc); 4508 actual = check; 4509 result = (int) n; 4510 TRACE_FALLBACK(xw, "old", wc, result, actual); 4511 break; 4512 } 4513 } 4514 } 4515 4516 if ((actual == NULL) 4517 && (empty <= fontData->fs_size) 4518 && (fontData->opened < xw->work.max_fontsets)) { 4519 FcPattern *myPattern = NULL; 4520 FcPattern *myReport = NULL; 4521 int defer = -1; 4522 4523 if (empty == 0) /* should not happen */ 4524 empty++; 4525 4526 for (n = empty; n <= fontData->fs_size; ++n) { 4527 int found; 4528 int nn = n - 1; 4529 4530 if (XftIsN(fontData, n) != xcEmpty) { 4531 continue; 4532 } 4533 if (resource.reportFonts) { 4534 if (myReport != NULL) 4535 FcPatternDestroy(myReport); 4536 myReport = FcPatternDuplicate(fontData->fontset->fonts[nn]); 4537 } 4538 myPattern = FcPatternDuplicate(fontData->fontset->fonts[nn]); 4539 check = XftFontOpenPattern(screen->display, myPattern); 4540 (void) maybeXftCache(xw, check); 4541 XftFpN(fontData, n) = check; 4542 if (check == NULL) { 4543 ; /* shouldn't happen... */ 4544 } else 4545#ifdef FC_COLOR 4546 if (isBogusXft(check)) { 4547 XftIsN(fontData, n) = xcBogus; 4548 } else 4549#endif 4550 if ((found = foundXftGlyph(xw, fontData, (int) n, wc)) 4551 != 0) { 4552 markXftOpened(xw, fontData, n, wc); 4553 reportXftFallbackFont(xw, fontData, (int) n, check, myReport); 4554 if (found < 0) { 4555 if (defer < 0) { 4556 defer = (int) n; 4557 TRACE(("Deferring font choice #%d\n", n + 1)); 4558 continue; 4559 } else if (slowXftMissing(xw, check, wc)) { 4560 TRACE(("Deferred, continuing #%d\n", n + 1)); 4561 continue; 4562 } 4563 } else if (defer >= 0) { 4564 defer = -1; 4565 TRACE(("Deferred, replacing %d with %d\n", 4566 defer + 1, n + 1)); 4567 } 4568 actual = check; 4569 result = (int) n; 4570 TRACE_FALLBACK(xw, "new", wc, result, actual); 4571 break; 4572 } else { 4573 Bool ok; 4574 if (defer >= 0 4575 && (ok = !slowXftMissing(xw, check, wc)) 4576 && checkXftGlyph(xw, check, wc)) { 4577 XTermFontMap *font_map = &(fontData->font_map); 4578 TRACE(("checkrecover2 %d\n", n)); 4579 markXftOpened(xw, fontData, n, wc); 4580 reportXftFallbackFont(xw, fontData, (int) n, check, myReport); 4581 actual = check; 4582 result = (int) n; 4583 TRACE_FALLBACK(xw, "fix", wc, result, actual); 4584 font_map->per_font[wc] = (XTfontNum) (result + 1); 4585 break; 4586 } else { 4587 /* 4588 * The slot is opened, but we are not using it yet. 4589 */ 4590 XftIsN(fontData, n) = xcUnused; 4591 } 4592 } 4593 } 4594 if (myReport != NULL) 4595 FcPatternDestroy(myReport); 4596 } 4597 } 4598 return result; 4599} 4600 4601/* 4602 * Check if the given character has a glyph known to Xft. If it is missing, 4603 * return true. 4604 * 4605 * see xc/lib/Xft/xftglyphs.c 4606 */ 4607Bool 4608xtermXftMissing(XtermWidget xw, 4609 XTermXftFonts *data, 4610 int fontNum, /* 0=primary, 1+ is fallback */ 4611 XftFont *font, /* actual font if no data */ 4612 unsigned wc) 4613{ 4614 Bool result = True; 4615 4616 (void) xw; 4617 if (data != NULL && font != NULL) { 4618 XTermFontMap *font_map = &(data->font_map); 4619 /* 4620 * Each fallback font has one chance to be scanned/cached. 4621 * We record in per_font[] the index of the first font containing a 4622 * given glyph. 4623 */ 4624 if (font_map->depth <= fontNum) { 4625 FcChar32 last = (xtermXftLastChar(font) | 255) + 1; 4626 FcChar32 base; 4627 FcChar32 nextPage; 4628 FcChar32 map[FC_CHARSET_MAP_SIZE]; 4629 unsigned added = 0; 4630 unsigned actual = 0; 4631 4632 font_map->depth = (fontNum + 1); 4633 /* allocate space */ 4634 if (last > font_map->last_char) { 4635 size_t need = (last * sizeof(XTfontNum)); 4636 size_t c1st = (font_map->last_char * sizeof(XTfontNum)); 4637 font_map->per_font = realloc(font_map->per_font, need); 4638 memset(font_map->per_font + font_map->last_char, 0, (need - c1st)); 4639 font_map->last_char = last; 4640 } 4641 4642 /* scan new font */ 4643 base = FcCharSetFirstPage(font->charset, map, &nextPage); 4644 do { 4645 unsigned row; 4646 unsigned col; 4647 FcChar32 bits; 4648 for (row = 0; row < FC_CHARSET_MAP_SIZE; ++row) { 4649 bits = map[row]; 4650 for (col = 0; col < 32; ++col) { 4651 if ((bits & 1) != 0) { 4652 actual++; 4653 if (!font_map->per_font[base]) { 4654 font_map->per_font[base] = (Char) font_map->depth; 4655 ++added; 4656 } 4657 } 4658 bits >>= 1; 4659 ++base; 4660 } 4661 } 4662 } while ((base = FcCharSetNextPage(font->charset, map, 4663 &nextPage)) != FC_CHARSET_DONE); 4664 (void) added; 4665 (void) actual; 4666 TRACE(("xtermXftMissing U+%04X #%-3d %6u added vs %6u of %6ld %s: %s\n", 4667 wc, 4668 font_map->depth, 4669 added, actual, 4670 font_map->last_char + 1, 4671 whichXftFonts(xw, data), 4672 nameOfXftFont(font))); 4673 } 4674 if (wc < font_map->last_char) { 4675 result = (font_map->per_font[wc] != (fontNum + 1)); 4676 } 4677 } 4678 return result; 4679} 4680#endif /* OPT_RENDERFONT */ 4681 4682#if OPT_WIDE_CHARS 4683#define MY_UCS(ucs,dec) case ucs: result = dec; break 4684unsigned 4685ucs2dec(TScreen *screen, unsigned ch) 4686{ 4687 unsigned result = ch; 4688 4689 (void) screen; 4690 if ((ch > 127) 4691 && (ch != UCS_REPL)) { 4692#if OPT_VT52_MODE 4693 if (screen != 0 && !(screen->vtXX_level)) { 4694 /* 4695 * Intentionally empty: it would be possible to use the built-in 4696 * line-drawing fallback in xtermDrawBoxChar(), but for testing 4697 * ncurses, this is good enough. 4698 */ 4699 ; 4700 } else 4701#endif 4702 switch (ch) { 4703 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4704 MY_UCS(0x25c6, 1); /* black diamond */ 4705 MY_UCS(0x2592, 2); /* medium shade */ 4706 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4707 MY_UCS(0x240c, 4); /* symbol for form feed */ 4708 MY_UCS(0x240d, 5); /* symbol for carriage return */ 4709 MY_UCS(0x240a, 6); /* symbol for line feed */ 4710 MY_UCS(0x00b0, 7); /* degree sign */ 4711 MY_UCS(0x00b1, 8); /* plus-minus sign */ 4712 MY_UCS(0x2424, 9); /* symbol for newline */ 4713 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4714 MY_UCS(0x2518, 11); /* box drawings light up and left */ 4715 MY_UCS(0x2510, 12); /* box drawings light down and left */ 4716 MY_UCS(0x250c, 13); /* box drawings light down and right */ 4717 MY_UCS(0x2514, 14); /* box drawings light up and right */ 4718 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4719 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4720 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4721 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4722 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4723 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4724 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4725 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4726 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4727 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4728 MY_UCS(0x2502, 25); /* box drawings light vertical */ 4729 MY_UCS(0x2264, 26); /* less-than or equal to */ 4730 MY_UCS(0x2265, 27); /* greater-than or equal to */ 4731 MY_UCS(0x03c0, 28); /* greek small letter pi */ 4732 MY_UCS(0x2260, 29); /* not equal to */ 4733 MY_UCS(0x00a3, 30); /* pound sign */ 4734 MY_UCS(0x00b7, 31); /* middle dot */ 4735 } 4736 } 4737 return result; 4738} 4739 4740#undef MY_UCS 4741#define MY_UCS(ucs,dec) case dec: result = ucs; break 4742 4743unsigned 4744dec2ucs(TScreen *screen, unsigned ch) 4745{ 4746 unsigned result = ch; 4747 4748 (void) screen; 4749 if (xtermIsDecGraphic(ch)) { 4750#if OPT_VT52_MODE 4751 if (screen != 0 && !(screen->vtXX_level)) { 4752 switch (ch) { 4753 MY_UCS(0x0020, 0); /* nbsp, treat as blank */ 4754 MY_UCS(0x0020, 1); /* reserved, treat as blank */ 4755 MY_UCS(0x25ae, 2); /* black vertical rectangle */ 4756 MY_UCS(0x215f, 3); /* "1/" */ 4757 MY_UCS(0x0020, 4); /* "3/", not in Unicode, ignore */ 4758 MY_UCS(0x0020, 5); /* "5/", not in Unicode, ignore */ 4759 MY_UCS(0x0020, 6); /* "7/", not in Unicode, ignore */ 4760 MY_UCS(0x00b0, 7); /* degree sign */ 4761 MY_UCS(0x00b1, 8); /* plus-minus sign */ 4762 MY_UCS(0x2192, 9); /* right-arrow */ 4763 MY_UCS(0x2026, 10); /* ellipsis */ 4764 MY_UCS(0x00f7, 11); /* divide by */ 4765 MY_UCS(0x2193, 12); /* down arrow */ 4766 MY_UCS(0x23ba, 13); /* bar at scan 0 */ 4767 MY_UCS(0x23ba, 14); /* bar at scan 1 */ 4768 MY_UCS(0x23bb, 15); /* bar at scan 2 */ 4769 MY_UCS(0x23bb, 16); /* bar at scan 3 */ 4770 MY_UCS(0x23bc, 17); /* bar at scan 4 */ 4771 MY_UCS(0x23bc, 18); /* bar at scan 5 */ 4772 MY_UCS(0x23bd, 19); /* bar at scan 6 */ 4773 MY_UCS(0x23bd, 20); /* bar at scan 7 */ 4774 MY_UCS(0x2080, 21); /* subscript 0 */ 4775 MY_UCS(0x2081, 22); /* subscript 1 */ 4776 MY_UCS(0x2082, 23); /* subscript 2 */ 4777 MY_UCS(0x2083, 24); /* subscript 3 */ 4778 MY_UCS(0x2084, 25); /* subscript 4 */ 4779 MY_UCS(0x2085, 26); /* subscript 5 */ 4780 MY_UCS(0x2086, 27); /* subscript 6 */ 4781 MY_UCS(0x2087, 28); /* subscript 7 */ 4782 MY_UCS(0x2088, 29); /* subscript 8 */ 4783 MY_UCS(0x2089, 30); /* subscript 9 */ 4784 MY_UCS(0x00b6, 31); /* paragraph */ 4785 } 4786 } else 4787#endif 4788 switch (ch) { 4789 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4790 MY_UCS(0x25c6, 1); /* black diamond */ 4791 MY_UCS(0x2592, 2); /* medium shade */ 4792 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4793 MY_UCS(0x240c, 4); /* symbol for form feed */ 4794 MY_UCS(0x240d, 5); /* symbol for carriage return */ 4795 MY_UCS(0x240a, 6); /* symbol for line feed */ 4796 MY_UCS(0x00b0, 7); /* degree sign */ 4797 MY_UCS(0x00b1, 8); /* plus-minus sign */ 4798 MY_UCS(0x2424, 9); /* symbol for newline */ 4799 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4800 MY_UCS(0x2518, 11); /* box drawings light up and left */ 4801 MY_UCS(0x2510, 12); /* box drawings light down and left */ 4802 MY_UCS(0x250c, 13); /* box drawings light down and right */ 4803 MY_UCS(0x2514, 14); /* box drawings light up and right */ 4804 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4805 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4806 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4807 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4808 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4809 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4810 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4811 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4812 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4813 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4814 MY_UCS(0x2502, 25); /* box drawings light vertical */ 4815 MY_UCS(0x2264, 26); /* less-than or equal to */ 4816 MY_UCS(0x2265, 27); /* greater-than or equal to */ 4817 MY_UCS(0x03c0, 28); /* greek small letter pi */ 4818 MY_UCS(0x2260, 29); /* not equal to */ 4819 MY_UCS(0x00a3, 30); /* pound sign */ 4820 MY_UCS(0x00b7, 31); /* middle dot */ 4821 } 4822 } 4823 return result; 4824} 4825 4826#endif /* OPT_WIDE_CHARS */ 4827 4828#if OPT_RENDERFONT || OPT_SHIFT_FONTS 4829static int 4830lookupOneFontSize(XtermWidget xw, int fontnum) 4831{ 4832 TScreen *screen = TScreenOf(xw); 4833 4834 if (screen->menu_font_sizes[fontnum] == 0) { 4835 XTermFonts fnt; 4836 4837 memset(&fnt, 0, sizeof(fnt)); 4838 screen->menu_font_sizes[fontnum] = -1; 4839 if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, NULL, True)) { 4840 if (fontnum <= fontMenu_lastBuiltin 4841 || strcmp(fnt.fn, DEFFONT)) { 4842 screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 4843 if (screen->menu_font_sizes[fontnum] <= 0) 4844 screen->menu_font_sizes[fontnum] = -1; 4845 } 4846 xtermCloseFont(xw, &fnt); 4847 } 4848 } 4849 return (screen->menu_font_sizes[fontnum] > 0); 4850} 4851 4852/* 4853 * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 4854 */ 4855static void 4856lookupFontSizes(XtermWidget xw) 4857{ 4858 int n; 4859 4860 for (n = 0; n < NMENUFONTS; n++) { 4861 (void) lookupOneFontSize(xw, n); 4862 } 4863} 4864#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 4865 4866#if OPT_RENDERFONT 4867static double 4868defaultFaceSize(void) 4869{ 4870 double result; 4871 float value; 4872 4873 if (sscanf(DEFFACESIZE, "%f", &value) == 1) 4874 result = (double) value; 4875 else 4876 result = 14.0; 4877 return result; 4878} 4879 4880static void 4881fillInFaceSize(XtermWidget xw, int fontnum) 4882{ 4883 TScreen *screen = TScreenOf(xw); 4884 double face_size = (double) xw->misc.face_size[fontnum]; 4885 4886 if (face_size <= 0.0) { 4887#if OPT_SHIFT_FONTS 4888 /* 4889 * If the user is switching font-sizes, make it follow by 4890 * default the same ratios to the default as the fixed fonts 4891 * would, for easy comparison. There will be some differences 4892 * since the fixed fonts have a variety of height/width ratios, 4893 * but this is simpler than adding another resource value - and 4894 * as noted above, the data for the fixed fonts are available. 4895 */ 4896 (void) lookupOneFontSize(xw, 0); 4897 if (fontnum == fontMenu_default) { 4898 face_size = defaultFaceSize(); 4899 } else if (lookupOneFontSize(xw, fontnum) 4900 && (screen->menu_font_sizes[0] 4901 != screen->menu_font_sizes[fontnum])) { 4902 double ratio; 4903 long num = screen->menu_font_sizes[fontnum]; 4904 long den = screen->menu_font_sizes[0]; 4905 4906 if (den <= 0) 4907 den = 1; 4908 ratio = dimSquareRoot((double) num / (double) den); 4909 4910 face_size = (ratio * (double) xw->misc.face_size[0]); 4911 TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 4912 fontnum, num, den, ratio, face_size)); 4913 } else 4914#endif 4915 { 4916#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default]) 4917 switch (fontnum) { 4918 case fontMenu_font1: 4919 face_size = LikeBitmap(2.0); 4920 break; 4921 case fontMenu_font2: 4922 face_size = LikeBitmap(35.0); 4923 break; 4924 case fontMenu_font3: 4925 face_size = LikeBitmap(60.0); 4926 break; 4927 default: 4928 face_size = defaultFaceSize(); 4929 break; 4930 case fontMenu_font4: 4931 face_size = LikeBitmap(90.0); 4932 break; 4933 case fontMenu_font5: 4934 face_size = LikeBitmap(135.0); 4935 break; 4936 case fontMenu_font6: 4937 face_size = LikeBitmap(200.0); 4938 break; 4939 case fontMenu_font7: 4940 face_size = LikeBitmap(240.0); 4941 break; 4942 } 4943 TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 4944 } 4945 xw->misc.face_size[fontnum] = (float) face_size; 4946 } 4947} 4948 4949/* no selection or escape */ 4950#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 4951 4952/* 4953 * Workaround for breakage in font-packages - check if all of the bitmap font 4954 * sizes are the same, and if we're using TrueType fonts. 4955 */ 4956static Boolean 4957useFaceSizes(XtermWidget xw) 4958{ 4959 Boolean result = False; 4960 4961 TRACE(("useFaceSizes " TRACE_L "\n")); 4962 if (UsingRenderFont(xw)) { 4963 Boolean nonzero = True; 4964 int n; 4965 4966 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 4967 if (xw->misc.face_size[n] <= 0.0f) { 4968 nonzero = False; 4969 break; 4970 } 4971 } 4972 if (!nonzero) { 4973 Boolean broken_fonts = True; 4974 TScreen *screen = TScreenOf(xw); 4975 long first; 4976 4977 lookupFontSizes(xw); 4978 first = screen->menu_font_sizes[0]; 4979 for (n = 0; n < NMENUFONTS; n++) { 4980 if (screen->menu_font_sizes[n] > 0 4981 && screen->menu_font_sizes[n] != first) { 4982 broken_fonts = False; 4983 break; 4984 } 4985 } 4986 4987 if (broken_fonts) { 4988 4989 TRACE(("bitmap fonts are broken - set faceSize resources\n")); 4990 for (n = 0; n < NMENUFONTS; n++) { 4991 fillInFaceSize(xw, n); 4992 } 4993 4994 } 4995 } 4996 result = True; 4997 } 4998 TRACE((TRACE_R " useFaceSizes %d\n", result)); 4999 return result; 5000} 5001#endif /* OPT_RENDERFONT */ 5002 5003#if OPT_SHIFT_FONTS 5004/* 5005 * Find the index of a larger/smaller font (according to the sign of 'relative' 5006 * and its magnitude), starting from the 'old' index. 5007 */ 5008int 5009lookupRelativeFontSize(XtermWidget xw, int old, int relative) 5010{ 5011 TScreen *screen = TScreenOf(xw); 5012 int m = -1; 5013 5014 TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 5015 if (!IsIcon(screen)) { 5016#if OPT_RENDERFONT 5017 if (useFaceSizes(xw)) { 5018 TRACE(("...using FaceSize\n")); 5019 if (relative != 0) { 5020 int n; 5021 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 5022 fillInFaceSize(xw, n); 5023 if (xw->misc.face_size[n] > 0 && 5024 xw->misc.face_size[n] != xw->misc.face_size[old]) { 5025 int cmp_0 = ((xw->misc.face_size[n] > 5026 xw->misc.face_size[old]) 5027 ? relative 5028 : -relative); 5029 int cmp_m = ((m < 0) 5030 ? 1 5031 : ((xw->misc.face_size[n] < 5032 xw->misc.face_size[m]) 5033 ? relative 5034 : -relative)); 5035 if (cmp_0 > 0 && cmp_m > 0) { 5036 m = n; 5037 } 5038 } 5039 } 5040 } 5041 } else 5042#endif 5043 { 5044 TRACE(("...using bitmap areas\n")); 5045 lookupFontSizes(xw); 5046 if (relative != 0) { 5047 int n; 5048 for (n = 0; n < NMENUFONTS; ++n) { 5049 if (screen->menu_font_sizes[n] > 0 && 5050 screen->menu_font_sizes[n] != 5051 screen->menu_font_sizes[old]) { 5052 int cmp_0 = ((screen->menu_font_sizes[n] > 5053 screen->menu_font_sizes[old]) 5054 ? relative 5055 : -relative); 5056 int cmp_m = ((m < 0) 5057 ? 1 5058 : ((screen->menu_font_sizes[n] < 5059 screen->menu_font_sizes[m]) 5060 ? relative 5061 : -relative)); 5062 if (cmp_0 > 0 && cmp_m > 0) { 5063 m = n; 5064 } 5065 } 5066 } 5067 } 5068 } 5069 TRACE(("...new index %d\n", m)); 5070 if (m >= 0) { 5071 if (relative > 1) 5072 m = lookupRelativeFontSize(xw, m, relative - 1); 5073 else if (relative < -1) 5074 m = lookupRelativeFontSize(xw, m, relative + 1); 5075 } 5076 } 5077 return m; 5078} 5079 5080/* ARGSUSED */ 5081void 5082HandleLargerFont(Widget w, 5083 XEvent *event GCC_UNUSED, 5084 String *params GCC_UNUSED, 5085 Cardinal *param_count GCC_UNUSED) 5086{ 5087 XtermWidget xw; 5088 5089 TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 5090 if ((xw = getXtermWidget(w)) != 0) { 5091 if (xw->misc.shift_fonts) { 5092 TScreen *screen = TScreenOf(xw); 5093 int m; 5094 5095 m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 5096 if (m >= 0) { 5097 SetVTFont(xw, m, True, NULL); 5098 } else { 5099 Bell(xw, XkbBI_MinorError, 0); 5100 } 5101 } 5102 } 5103} 5104 5105/* ARGSUSED */ 5106void 5107HandleSmallerFont(Widget w, 5108 XEvent *event GCC_UNUSED, 5109 String *params GCC_UNUSED, 5110 Cardinal *param_count GCC_UNUSED) 5111{ 5112 XtermWidget xw; 5113 5114 TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 5115 if ((xw = getXtermWidget(w)) != 0) { 5116 if (xw->misc.shift_fonts) { 5117 TScreen *screen = TScreenOf(xw); 5118 int m; 5119 5120 m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 5121 if (m >= 0) { 5122 SetVTFont(xw, m, True, NULL); 5123 } else { 5124 Bell(xw, XkbBI_MinorError, 0); 5125 } 5126 } 5127 } 5128} 5129#endif /* OPT_SHIFT_FONTS */ 5130 5131int 5132xtermGetFont(const char *param) 5133{ 5134 int fontnum; 5135 5136 if (param == NULL) 5137 param = ""; 5138 5139 switch (param[0]) { 5140 case 'd': 5141 case 'D': 5142 case '0': 5143 fontnum = fontMenu_default; 5144 break; 5145 case '1': 5146 fontnum = fontMenu_font1; 5147 break; 5148 case '2': 5149 fontnum = fontMenu_font2; 5150 break; 5151 case '3': 5152 fontnum = fontMenu_font3; 5153 break; 5154 case '4': 5155 fontnum = fontMenu_font4; 5156 break; 5157 case '5': 5158 fontnum = fontMenu_font5; 5159 break; 5160 case '6': 5161 fontnum = fontMenu_font6; 5162 break; 5163 case '7': 5164 fontnum = fontMenu_font7; 5165 break; 5166 case 'e': 5167 case 'E': 5168 fontnum = fontMenu_fontescape; 5169 break; 5170 case 's': 5171 case 'S': 5172 fontnum = fontMenu_fontsel; 5173 break; 5174 default: 5175 fontnum = -1; 5176 break; 5177 } 5178 TRACE(("xtermGetFont(%s) ->%d\n", param, fontnum)); 5179 return fontnum; 5180} 5181 5182/* ARGSUSED */ 5183void 5184HandleSetFont(Widget w, 5185 XEvent *event GCC_UNUSED, 5186 String *params, 5187 Cardinal *param_count) 5188{ 5189 XtermWidget xw; 5190 5191 if ((xw = getXtermWidget(w)) != 0) { 5192 int fontnum; 5193 VTFontNames fonts; 5194 5195 memset(&fonts, 0, sizeof(fonts)); 5196 5197 if (*param_count == 0) { 5198 fontnum = fontMenu_default; 5199 } else { 5200 Cardinal maxparams = 1; /* total number of params allowed */ 5201 int result = xtermGetFont(params[0]); 5202 5203 switch (result) { 5204 case fontMenu_default: /* FALLTHRU */ 5205 case fontMenu_font1: /* FALLTHRU */ 5206 case fontMenu_font2: /* FALLTHRU */ 5207 case fontMenu_font3: /* FALLTHRU */ 5208 case fontMenu_font4: /* FALLTHRU */ 5209 case fontMenu_font5: /* FALLTHRU */ 5210 case fontMenu_font6: /* FALLTHRU */ 5211 case fontMenu_font7: /* FALLTHRU */ 5212 break; 5213 case fontMenu_fontescape: 5214#if OPT_WIDE_CHARS 5215 maxparams = 5; 5216#else 5217 maxparams = 3; 5218#endif 5219 break; 5220 case fontMenu_fontsel: 5221 maxparams = 2; 5222 break; 5223 default: 5224 Bell(xw, XkbBI_MinorError, 0); 5225 return; 5226 } 5227 fontnum = result; 5228 5229 if (*param_count > maxparams) { /* see if extra args given */ 5230 Bell(xw, XkbBI_MinorError, 0); 5231 return; 5232 } 5233 switch (*param_count) { /* assign 'em */ 5234#if OPT_WIDE_CHARS 5235 case 5: 5236 fonts.f_wb = x_strdup(params[4]); 5237 /* FALLTHRU */ 5238 case 4: 5239 fonts.f_w = x_strdup(params[3]); 5240#endif 5241 /* FALLTHRU */ 5242 case 3: 5243 fonts.f_b = x_strdup(params[2]); 5244 /* FALLTHRU */ 5245 case 2: 5246 fonts.f_n = x_strdup(params[1]); 5247 break; 5248 } 5249 } 5250 5251 SetVTFont(xw, fontnum, True, &fonts); 5252 } 5253} 5254 5255Bool 5256SetVTFont(XtermWidget xw, 5257 int which, 5258 Bool doresize, 5259 const VTFontNames * fonts) 5260{ 5261 TScreen *screen = TScreenOf(xw); 5262 Bool result = False; 5263 5264 TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 5265 (fonts && fonts->f_n) ? fonts->f_n : "<null>", 5266 (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 5267 5268 if (IsIcon(screen)) { 5269 Bell(xw, XkbBI_MinorError, 0); 5270 } else if (which >= 0 && which < NMENUFONTS) { 5271 VTFontNames new_fnames; 5272 5273 memset(&new_fnames, 0, sizeof(new_fnames)); 5274 if (fonts != 0) 5275 new_fnames = *fonts; 5276 5277 if (which == fontMenu_fontsel) { /* go get the selection */ 5278 result = FindFontSelection(xw, new_fnames.f_n, False); 5279 } else { 5280#define USE_CACHED(field, name) \ 5281 if (new_fnames.field == NULL) { \ 5282 new_fnames.field = x_strdup(screen->menu_font_names[which][name]); \ 5283 TRACE(("set new_fnames." #field " from menu_font_names[%d][" #name "] %s\n", \ 5284 which, NonNull(new_fnames.field))); \ 5285 } else { \ 5286 TRACE(("set new_fnames." #field " reused\n")); \ 5287 } 5288#define SAVE_FNAME(field, name) \ 5289 if (new_fnames.field != NULL \ 5290 && (screen->menu_font_names[which][name] == NULL \ 5291 || strcmp(screen->menu_font_names[which][name], new_fnames.field))) { \ 5292 TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \ 5293 which, new_fnames.field)); \ 5294 FREE_STRING(screen->menu_font_names[which][name]); \ 5295 screen->menu_font_names[which][name] = x_strdup(new_fnames.field); \ 5296 } 5297 5298 USE_CACHED(f_n, fNorm); 5299 USE_CACHED(f_b, fBold); 5300#if OPT_WIDE_CHARS 5301 USE_CACHED(f_w, fWide); 5302 USE_CACHED(f_wb, fWBold); 5303#endif 5304 if (xtermLoadFont(xw, 5305 &new_fnames, 5306 doresize, which)) { 5307 /* 5308 * If successful, save the data so that a subsequent query via 5309 * OSC-50 will return the expected values. 5310 */ 5311 SAVE_FNAME(f_n, fNorm); 5312 SAVE_FNAME(f_b, fBold); 5313#if OPT_WIDE_CHARS 5314 SAVE_FNAME(f_w, fWide); 5315 SAVE_FNAME(f_wb, fWBold); 5316#endif 5317 result = True; 5318 } else { 5319 Bell(xw, XkbBI_MinorError, 0); 5320 } 5321 FREE_FNAME(f_n); 5322 FREE_FNAME(f_b); 5323#if OPT_WIDE_CHARS 5324 FREE_FNAME(f_w); 5325 FREE_FNAME(f_wb); 5326#endif 5327 } 5328 } else { 5329 Bell(xw, XkbBI_MinorError, 0); 5330 } 5331 TRACE(("...SetVTFont: %d\n", result)); 5332 return result; 5333} 5334 5335#if OPT_RENDERFONT 5336static void 5337trimSizeFromFace(char *face_name, float *face_size) 5338{ 5339 char *first = strstr(face_name, ":size="); 5340 if (first == 0) { 5341 first = face_name; 5342 } else { 5343 first++; 5344 } 5345 if (!strncmp(first, "size=", (size_t) 5)) { 5346 char *last = strchr(first, ':'); 5347 char mark; 5348 float value; 5349 char extra; 5350 TRACE(("...before trimming, font = \"%s\"\n", face_name)); 5351 if (last == 0) 5352 last = first + strlen(first); 5353 mark = *last; 5354 *last = '\0'; 5355 if (sscanf(first, "size=%g%c", &value, &extra) == 1) { 5356 TRACE(("...trimmed size from font: %g\n", value)); 5357 if (face_size != 0) 5358 *face_size = value; 5359 } 5360 if (mark) { 5361 while ((*first++ = *++last) != '\0') { 5362 ; 5363 } 5364 } else { 5365 if (first != face_name) 5366 --first; 5367 *first = '\0'; 5368 } 5369 TRACE(("...after trimming, font = \"%s\"\n", face_name)); 5370 } 5371} 5372#endif 5373 5374/* 5375 * Save a font specification to the proper list. 5376 */ 5377static void 5378save2FontList(XtermWidget xw, 5379 const char *name, 5380 XtermFontNames * fontnames, 5381 VTFontEnum which, 5382 const char *source, 5383 Bool check, 5384 Bool ttf) 5385{ 5386 char *value; 5387 size_t plen; 5388 Bool marked = False; 5389 Bool use_ttf = ttf; 5390 5391 (void) xw; 5392 5393 if (source == 0) 5394 source = ""; 5395 while (isspace(CharOf(*source))) 5396 ++source; 5397 5398 /* fontconfig patterns can contain ':' separators, but we'll treat 5399 * a leading prefix specially to denote whether the pattern might be 5400 * XLFD ("x" or "xlfd") versus Xft ("xft"). 5401 */ 5402 for (plen = 0; source[plen] != '\0'; ++plen) { 5403 if (source[plen] == ':') { 5404 marked = True; 5405 switch (plen) { 5406 case 0: 5407 ++plen; /* trim leading ':' */ 5408 break; 5409 case 1: 5410 if (!strncmp(source, "x", plen)) { 5411 ++plen; 5412 use_ttf = False; 5413 } else { 5414 marked = False; 5415 } 5416 break; 5417 case 3: 5418 if (!strncmp(source, "xft", plen)) { 5419 ++plen; 5420 use_ttf = True; 5421 } else { 5422 marked = False; 5423 } 5424 break; 5425 case 4: 5426 if (!strncmp(source, "xlfd", plen)) { 5427 ++plen; 5428 use_ttf = False; 5429 } else { 5430 marked = False; 5431 } 5432 break; 5433 default: 5434 marked = False; 5435 plen = 0; 5436 break; 5437 } 5438 break; 5439 } 5440 } 5441 if (!marked) 5442 plen = 0; 5443 value = x_strtrim(source + plen); 5444 if (value != 0) { 5445 Bool success = False; 5446#if OPT_RENDERFONT 5447 VTFontList *target = (use_ttf 5448 ? &(fontnames->xft) 5449 : &(fontnames->x11)); 5450#else 5451 VTFontList *target = &(fontnames->x11); 5452#endif 5453 char ***list = 0; 5454 char **next = 0; 5455 size_t count = 0; 5456 5457 (void) use_ttf; 5458 switch (which) { 5459 case fNorm: 5460 list = &(target->list_n); 5461 break; 5462 case fBold: 5463 list = &(target->list_b); 5464 break; 5465#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5466 case fItal: 5467 list = &(target->list_i); 5468 break; 5469 case fBtal: 5470 list = &(target->list_bi); 5471 break; 5472#endif 5473#if OPT_WIDE_CHARS 5474 case fWide: 5475 list = &(target->list_w); 5476 break; 5477 case fWBold: 5478 list = &(target->list_wb); 5479 break; 5480 case fWItal: 5481 list = &(target->list_wi); 5482 break; 5483 case fWBtal: 5484 list = &(target->list_wbi); 5485 break; 5486#endif 5487 case fMAX: 5488 list = 0; 5489 break; 5490 } 5491 5492 if (list != 0) { 5493 success = True; 5494 if (*list != 0) { 5495 while ((*list)[count] != 0) { 5496 if (IsEmpty((*list)[count])) { 5497 TRACE(("... initial %s\n", value)); 5498 free((*list)[count]); 5499 break; 5500 } else if (!strcmp(value, (*list)[count])) { 5501 TRACE(("... duplicate %s\n", value)); 5502 success = False; 5503 break; 5504 } 5505 ++count; 5506 } 5507 } 5508 if (success) { 5509 next = (char **) realloc(*list, sizeof(char *) * (count + 2)); 5510 if (next != 0) { 5511#if OPT_RENDERFONT 5512 if (use_ttf) { 5513 trimSizeFromFace(value, 5514 (count == 0 && which == fNorm) 5515 ? &(xw->misc.face_size[0]) 5516 : (float *) 0); 5517 } 5518#endif 5519 next[count++] = value; 5520 next[count] = 0; 5521 *list = next; 5522 TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n", 5523 whichFontList(xw, target), 5524 whichFontList2(xw, *list), 5525 (unsigned long) count, 5526 value)); 5527 } else { 5528 xtermWarning("realloc failure in save2FontList(%s)\n", name); 5529 freeFontList(list); 5530 success = False; 5531 } 5532 } 5533 } 5534 if (success) { 5535#if (MAX_XFT_FONTS == MAX_XLFD_FONTS) 5536 size_t limit = MAX_XFT_FONTS; 5537#else 5538 size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS; 5539#endif 5540 if (count > limit && *x_skip_blanks(value)) { 5541 if (check) { 5542 xtermWarning("too many fonts for %s, ignoring %s\n", 5543 whichFontEnum(which), 5544 value); 5545 } 5546 if (list && *list) { 5547 free((*list)[limit]); 5548 (*list)[limit] = 0; 5549 } 5550 } 5551 } else { 5552 free(value); 5553 } 5554 } 5555} 5556 5557/* 5558 * In principle, any of the font-name resources could be extended to be a list 5559 * of font-names. That would be bad for performance, but as a basis for an 5560 * extension, parse the font-name as a comma-separated list, creating/updating 5561 * an array of font-names. 5562 */ 5563void 5564allocFontList(XtermWidget xw, 5565 const char *name, 5566 XtermFontNames * target, 5567 VTFontEnum which, 5568 const char *source, 5569 Bool ttf) 5570{ 5571 char *blob; 5572 5573 blob = x_strdup(source); 5574 if (blob != 0) { 5575 int n; 5576 int pass; 5577 char **list = 0; 5578 5579 TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n", 5580 whichFontEnum(which), name, blob)); 5581 5582 for (pass = 0; pass < 2; ++pass) { 5583 unsigned count = 0; 5584 if (pass) 5585 list[0] = blob; 5586 for (n = 0; blob[n] != '\0'; ++n) { 5587 if (blob[n] == ',') { 5588 ++count; 5589 if (pass != 0) { 5590 blob[n] = '\0'; 5591 list[count] = blob + n + 1; 5592 } 5593 } 5594 } 5595 if (!pass) { 5596 if (count == 0 && *blob == '\0') 5597 break; 5598 list = TypeCallocN(char *, count + 2); 5599 if (list == 0) 5600 break; 5601 } 5602 } 5603 if (list) { 5604 for (n = 0; list[n] != 0; ++n) { 5605 if (*list[n]) { 5606 save2FontList(xw, name, target, which, list[n], True, ttf); 5607 } 5608 } 5609 free(list); 5610 } 5611 } 5612 free(blob); 5613} 5614 5615static void 5616initFontList(XtermWidget xw, 5617 const char *name, 5618 XtermFontNames * target, 5619 Bool ttf) 5620{ 5621 int which; 5622 5623 TRACE(("initFontList(%s)\n", name)); 5624 for (which = 0; which < fMAX; ++which) { 5625 save2FontList(xw, name, target, (VTFontEnum) which, "", False, ttf); 5626 } 5627} 5628 5629void 5630initFontLists(XtermWidget xw) 5631{ 5632 TRACE(("initFontLists\n")); 5633 initFontList(xw, "x11 font", &(xw->work.fonts), False); 5634#if OPT_RENDERFONT 5635 initFontList(xw, "xft font", &(xw->work.fonts), True); 5636#endif 5637#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5638 initFontList(xw, "cached font", 5639 &(xw->screen.cacheVTFonts.fonts), False); 5640#endif 5641} 5642 5643void 5644copyFontList(char ***targetp, char **source) 5645{ 5646 freeFontList(targetp); 5647 5648 if (source != 0) { 5649 int pass; 5650 size_t count; 5651 5652 for (pass = 0; pass < 2; ++pass) { 5653 for (count = 0; source[count] != 0; ++count) { 5654 if (pass) 5655 (*targetp)[count] = x_strdup(source[count]); 5656 } 5657 if (!pass) { 5658 ++count; 5659 *targetp = TypeCallocN(char *, count); 5660 } 5661 } 5662 } else { 5663 *targetp = TypeCallocN(char *, 2); 5664 (*targetp)[0] = x_strdup(""); 5665 } 5666} 5667 5668#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5669static Boolean 5670merge_sublist(char ***targetp, char **source) 5671{ 5672 Boolean result = False; 5673 if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) { 5674 copyFontList(targetp, source); 5675 result = True; 5676 } 5677 return result; 5678} 5679#endif 5680 5681void 5682freeFontList(char ***targetp) 5683{ 5684 if (targetp != 0) { 5685 char **target = *targetp; 5686 if (target != 0) { 5687 int n; 5688 for (n = 0; target[n] != 0; ++n) { 5689 free(target[n]); 5690 } 5691 free(target); 5692 *targetp = 0; 5693 } 5694 } 5695} 5696 5697void 5698freeFontLists(VTFontList * lists) 5699{ 5700 int which; 5701 5702 TRACE(("freeFontLists\n")); 5703 for (which = 0; which < fMAX; ++which) { 5704 char ***target = 0; 5705 switch (which) { 5706 case fNorm: 5707 target = &(lists->list_n); 5708 break; 5709 case fBold: 5710 target = &(lists->list_b); 5711 break; 5712#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5713 case fItal: 5714 target = &(lists->list_i); 5715 break; 5716 case fBtal: 5717 target = &(lists->list_bi); 5718 break; 5719#endif 5720#if OPT_WIDE_CHARS 5721 case fWide: 5722 target = &(lists->list_w); 5723 break; 5724 case fWBold: 5725 target = &(lists->list_wb); 5726 break; 5727 case fWItal: 5728 target = &(lists->list_wi); 5729 break; 5730 case fWBtal: 5731 target = &(lists->list_wbi); 5732 break; 5733#endif 5734 default: 5735 target = 0; 5736 break; 5737 } 5738 freeFontList(target); 5739 } 5740} 5741 5742/* 5743 * Return a pointer to the XLFD font information for a given font class. 5744 * XXX make this allocate the font on demand. 5745 */ 5746XTermFonts * 5747getNormalFont(TScreen *screen, int which) 5748{ 5749 XTermFonts *result = 0; 5750 if (which >= 0 && which < fMAX) 5751 result = GetNormalFont(screen, which); 5752 return result; 5753} 5754 5755#if OPT_DEC_CHRSET 5756XTermFonts * 5757getDoubleFont(TScreen *screen, int which) 5758{ 5759 XTermFonts *result = 0; 5760 if ((int) which >= 0 && which < NUM_CHRSET) 5761 result = GetDoubleFont(screen, which); 5762 return result; 5763} 5764 5765#if OPT_RENDERFONT 5766void 5767getDoubleXftFont(XTermDraw * params, XTermXftFonts *data, unsigned chrset, unsigned attr_flags) 5768{ 5769 XtermWidget xw = params->xw; 5770 TScreen *screen = TScreenOf(xw); 5771 XftPattern *top_pattern; 5772 int fontnum = screen->menu_font_number; 5773 const char *face_name = getFaceName(xw, False); 5774 5775 if (chrset != CSET_SWL 5776 && (top_pattern = XftNameParse(face_name)) != 0) { 5777 double face_size = (double) xw->misc.face_size[fontnum]; 5778 XftPattern *sub_pattern = XftPatternDuplicate(top_pattern); 5779 const char *category = "doublesize"; 5780 5781 switch (chrset) { 5782 case CSET_DHL_TOP: 5783 category = "DHL_TOP"; 5784 goto double_high; 5785 case CSET_DHL_BOT: 5786 category = "DHL_BOT"; 5787 double_high: 5788 face_size *= 2; 5789 XftPatternBuild(sub_pattern, 5790 NormXftPattern, 5791 (void *) 0); 5792 break; 5793 case CSET_DWL: 5794 category = "DWL"; 5795 XftPatternBuild(sub_pattern, 5796 NormXftPattern, 5797 FC_ASPECT, XftTypeDouble, 2.0, 5798 (void *) 0); 5799 break; 5800 } 5801 if (attr_flags & BOLD) { 5802 XftPatternBuild(sub_pattern, 5803 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, 5804 (void *) 0); 5805 } 5806 xtermOpenXft(xw, data, 0, face_name, sub_pattern, category); 5807 data->pattern = sub_pattern; 5808 } 5809} 5810#endif 5811#endif /* OPT_DEC_CHRSET */ 5812 5813#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5814XTermFonts * 5815getItalicFont(TScreen *screen, int which) 5816{ 5817 XTermFonts *result = 0; 5818#if OPT_WIDE_ATTRS 5819 if (which >= 0 && which < fMAX) 5820 result = GetItalicFont(screen, which); 5821#else 5822 (void) screen; 5823 (void) which; 5824#endif 5825 return result; 5826} 5827#endif 5828 5829#if OPT_RENDERFONT 5830/* 5831 * This returns a pointer to everything known about a given Xft font. 5832 * XXX make this allocate the font on demand. 5833 */ 5834XTermXftFonts * 5835getMyXftFont(XtermWidget xw, int which, int fontnum) 5836{ 5837 TScreen *screen = TScreenOf(xw); 5838 XTermXftFonts *result = 0; 5839 if (fontnum >= 0 && fontnum < NMENUFONTS) { 5840 switch ((VTFontEnum) which) { 5841 case fNorm: 5842 result = &(screen->renderFontNorm[fontnum]); 5843 break; 5844 case fBold: 5845 result = &(screen->renderFontBold[fontnum]); 5846 break; 5847#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5848 case fItal: 5849 result = &(screen->renderFontItal[fontnum]); 5850 break; 5851 case fBtal: 5852 result = &(screen->renderFontBtal[fontnum]); 5853 break; 5854#endif 5855#if OPT_WIDE_CHARS 5856 case fWide: 5857 result = &(screen->renderWideNorm[fontnum]); 5858 break; 5859 case fWBold: 5860 result = &(screen->renderWideBold[fontnum]); 5861 break; 5862 case fWItal: 5863 result = &(screen->renderWideItal[fontnum]); 5864 break; 5865 case fWBtal: 5866 result = &(screen->renderWideBtal[fontnum]); 5867 break; 5868#endif 5869 case fMAX: 5870 break; 5871 } 5872 } 5873 return result; 5874} 5875 5876const char * 5877whichXftFonts(XtermWidget xw, XTermXftFonts *data) 5878{ 5879 TScreen *screen = TScreenOf(xw); 5880 const char *result = "?"; 5881#define CHECK(name) ((data >= &(screen->name[0])) && (data < &(screen->name[NMENUFONTS]))) result = #name 5882 if CHECK 5883 (renderFontNorm); 5884 else if CHECK 5885 (renderFontBold); 5886#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5887 else if CHECK 5888 (renderFontItal); 5889 else if CHECK 5890 (renderFontBtal); 5891#endif 5892#if OPT_WIDE_CHARS 5893 else if CHECK 5894 (renderWideNorm); 5895 else if CHECK 5896 (renderWideBold); 5897 else if CHECK 5898 (renderWideItal); 5899 else if CHECK 5900 (renderWideBtal); 5901#endif 5902#if OPT_DEC_CHRSET 5903#if OPT_RENDERFONT 5904 else { 5905 int n; 5906 for (n = 0; n < NUM_CHRSET; ++n) { 5907 if (data == &screen->double_xft_fonts[n]) { 5908 result = "double_xft_fonts"; 5909 break; 5910 } 5911 } 5912 } 5913#endif 5914#endif /* OPT_DEC_CHRSET */ 5915 return result; 5916} 5917 5918XftFont * 5919getXftFont(XtermWidget xw, VTFontEnum which, int fontnum) 5920{ 5921 XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum); 5922 XftFont *result = 0; 5923 if (data != 0) 5924 result = XftFp(data); 5925 return result; 5926} 5927#endif 5928 5929const char * 5930whichFontEnum(VTFontEnum value) 5931{ 5932 const char *result = "?"; 5933#define DATA(name) case name: result = #name; break 5934 switch (value) { 5935 DATA(fNorm); 5936 DATA(fBold); 5937#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5938 DATA(fItal); 5939 DATA(fBtal); 5940#endif 5941#if OPT_WIDE_CHARS 5942 DATA(fWide); 5943 DATA(fWBold); 5944 DATA(fWItal); 5945 DATA(fWBtal); 5946#endif 5947 DATA(fMAX); 5948 } 5949#undef DATA 5950 return result; 5951} 5952 5953const char * 5954whichFontList(XtermWidget xw, VTFontList * value) 5955{ 5956 const char *result = "?"; 5957 if (value == &(xw->work.fonts.x11)) 5958 result = "x11_fontnames"; 5959#if OPT_RENDERFONT 5960 else if (value == &(xw->work.fonts.xft)) 5961 result = "xft_fontnames"; 5962#endif 5963#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5964 else if (value == &(xw->screen.cacheVTFonts.fonts.x11)) 5965 result = "cached_fontnames"; 5966#endif 5967 return result; 5968} 5969 5970static const char * 5971whichFontList2s(VTFontList * list, char **value) 5972{ 5973 const char *result = 0; 5974#define DATA(name) if (value == (list->name)) result = #name 5975 DATA(list_n); 5976 DATA(list_b); 5977#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5978 DATA(list_i); 5979 DATA(list_bi); 5980#endif 5981#if OPT_WIDE_CHARS 5982 DATA(list_w); 5983 DATA(list_wb); 5984 DATA(list_wi); 5985 DATA(list_wbi); 5986#endif 5987#undef DATA 5988 return result; 5989} 5990 5991const char * 5992whichFontList2(XtermWidget xw, char **value) 5993{ 5994 const char *result = 0; 5995#define DATA(name) (result = whichFontList2s(&(xw->name), value)) 5996 if (DATA(work.fonts.x11) == 0) { 5997#if OPT_RENDERFONT 5998 if (DATA(work.fonts.xft) == 0) 5999#endif 6000#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 6001 if (DATA(screen.cacheVTFonts.fonts.x11) == 0) 6002#endif 6003 result = "?"; 6004 } 6005#undef DATA 6006 return result; 6007} 6008