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