fontutils.c revision dfb07bc7
1/* $XTermId: fontutils.c,v 1.531 2017/06/20 09:10:19 tom Exp $ */ 2 3/* 4 * Copyright 1998-2016,2017 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33/* 34 * A portion of this module (for FontNameProperties) was adapted from EMU 1.3; 35 * it constructs font names with specific properties changed, e.g., for bold 36 * and double-size characters. 37 */ 38 39#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field) 40 41#include <fontutils.h> 42#include <X11/Xmu/Drawing.h> 43#include <X11/Xmu/CharSet.h> 44 45#include <main.h> 46#include <data.h> 47#include <menu.h> 48#include <xstrings.h> 49#include <xterm.h> 50 51#include <stdio.h> 52#include <ctype.h> 53 54#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 55#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((screen)->scale_height * (float) (src)) 56 57/* from X11/Xlibint.h - not all vendors install this file */ 58#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 59 (((cs)->rbearing|(cs)->lbearing| \ 60 (cs)->ascent|(cs)->descent) == 0)) 61 62#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 63{ \ 64 cs = 0; \ 65 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 66 if (fs->per_char == NULL) { \ 67 cs = &fs->min_bounds; \ 68 } else { \ 69 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 70 } \ 71 if (CI_NONEXISTCHAR(cs)) cs = 0; \ 72 } \ 73} 74 75#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 76{ \ 77 cs = 0; \ 78 if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 79 col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 80 if (fs->per_char == NULL) { \ 81 cs = &fs->min_bounds; \ 82 } else { \ 83 cs = &fs->per_char[((row - fs->min_byte1) * \ 84 (fs->max_char_or_byte2 - \ 85 fs->min_char_or_byte2 + 1)) + \ 86 (col - fs->min_char_or_byte2)]; \ 87 } \ 88 if (CI_NONEXISTCHAR(cs)) cs = 0; \ 89 } \ 90} 91 92#define FREE_FNAME(field) \ 93 if (fonts == 0 || myfonts.field != fonts->field) { \ 94 FREE_STRING(myfonts.field); \ 95 myfonts.field = 0; \ 96 } 97 98/* 99 * A structure to hold the relevant properties from a font 100 * we need to make a well formed font name for it. 101 */ 102typedef struct { 103 /* registry, foundry, family */ 104 const char *beginning; 105 /* weight */ 106 const char *weight; 107 /* slant */ 108 const char *slant; 109 /* wideness */ 110 const char *wideness; 111 /* add style */ 112 const char *add_style; 113 int pixel_size; 114 const char *point_size; 115 int res_x; 116 int res_y; 117 const char *spacing; 118 int average_width; 119 /* charset registry, charset encoding */ 120 char *end; 121} FontNameProperties; 122 123#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 124static Boolean merge_sublist(char ***, char **); 125#endif 126 127static void save2FontList(XtermWidget, const char *, XtermFontNames *, 128 VTFontEnum, const char *, Bool); 129 130#if OPT_RENDERFONT 131static void fillInFaceSize(XtermWidget, int); 132#endif 133 134#if OPT_SHIFT_FONTS 135static int lookupOneFontSize(XtermWidget, int); 136#endif 137 138#if OPT_REPORT_FONTS || OPT_WIDE_CHARS 139static unsigned 140countGlyphs(XFontStruct *fp) 141{ 142 unsigned count = 0; 143 144 if (fp != 0) { 145 if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 146 count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1; 147 } else if (fp->min_char_or_byte2 < 256 148 && fp->max_char_or_byte2 < 256) { 149 unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 150 unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 151 count = last + 1 - first; 152 } 153 } 154 return count; 155} 156#endif 157 158#if OPT_WIDE_CHARS 159/* 160 * Verify that the wide-bold font is at least a bold font with roughly as many 161 * glyphs as the wide font. The counts should be the same, but settle for 162 * filtering out the worst of the font mismatches. 163 */ 164static Bool 165compatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs) 166{ 167 unsigned count_w = countGlyphs(wfs); 168 unsigned count_wb = countGlyphs(wbfs); 169 if (count_w <= 256 || 170 count_wb <= 256 || 171 ((count_w / 4) * 3) > count_wb) { 172 TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 173 count_w, count_wb)); 174 return False; 175 } 176 return True; 177} 178#endif /* OPT_WIDE_CHARS */ 179 180#if OPT_BOX_CHARS 181static void 182setupPackedFonts(XtermWidget xw) 183{ 184 TScreen *screen = TScreenOf(xw); 185 Bool value = False; 186 187#if OPT_RENDERFONT 188 if (xw->work.render_font == True) { 189 int e; 190 191 for (e = 0; e < fMAX; ++e) { 192 XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number); 193 if (data != 0) { 194 if (data->map.mixed) { 195 screen->allow_packing = True; 196 break; 197 } 198 } 199 } 200 } 201#endif /* OPT_RENDERFONT */ 202 203 value = screen->allow_packing; 204 205 SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 206} 207#endif 208 209/* 210 * Returns the fields from start to stop in a dash- separated string. This 211 * function will modify the source, putting '\0's in the appropriate place and 212 * moving the beginning forward to after the '\0' 213 * 214 * This will NOT work for the last field (but we won't need it). 215 */ 216static char * 217n_fields(char **source, int start, int stop) 218{ 219 int i; 220 char *str, *str1; 221 222 /* 223 * find the start-1th dash 224 */ 225 for (i = start - 1, str = *source; i; i--, str++) { 226 if ((str = strchr(str, '-')) == 0) 227 return 0; 228 } 229 230 /* 231 * find the stopth dash 232 */ 233 for (i = stop - start + 1, str1 = str; i; i--, str1++) { 234 if ((str1 = strchr(str1, '-')) == 0) 235 return 0; 236 } 237 238 /* 239 * put a \0 at the end of the fields 240 */ 241 *(str1 - 1) = '\0'; 242 243 /* 244 * move source forward 245 */ 246 *source = str1; 247 248 return str; 249} 250 251static Boolean 252check_fontname(const char *name) 253{ 254 Boolean result = True; 255 256 if (IsEmpty(name)) { 257 TRACE(("fontname missing\n")); 258 result = False; 259 } 260 return result; 261} 262 263/* 264 * Gets the font properties from a given font structure. We use the FONT name 265 * to find them out, since that seems easier. 266 * 267 * Returns a pointer to a static FontNameProperties structure 268 * or NULL on error. 269 */ 270static FontNameProperties * 271get_font_name_props(Display *dpy, XFontStruct *fs, char **result) 272{ 273 static FontNameProperties props; 274 static char *last_name; 275 276 Atom fontatom = XInternAtom(dpy, "FONT", False); 277 char *name = 0; 278 char *str; 279 280 /* 281 * first get the full font name 282 */ 283 if (fontatom != 0) { 284 XFontProp *fp; 285 int i; 286 287 for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 288 if (fp->name == fontatom) { 289 name = XGetAtomName(dpy, fp->card32); 290 break; 291 } 292 } 293 } 294 295 if (name == 0) 296 return 0; 297 298 /* 299 * XGetAtomName allocates memory - don't leak 300 */ 301 if (last_name != 0) 302 XFree(last_name); 303 last_name = name; 304 305 if (result != 0) { 306 if (!check_fontname(name)) 307 return 0; 308 if (*result != 0) 309 free(*result); 310 *result = x_strdup(name); 311 } 312 313 /* 314 * Now split it up into parts and put them in 315 * their places. Since we are using parts of 316 * the original string, we must not free the Atom Name 317 */ 318 319 /* registry, foundry, family */ 320 if ((props.beginning = n_fields(&name, 1, 3)) == 0) 321 return 0; 322 323 /* weight is the next */ 324 if ((props.weight = n_fields(&name, 1, 1)) == 0) 325 return 0; 326 327 /* slant */ 328 if ((props.slant = n_fields(&name, 1, 1)) == 0) 329 return 0; 330 331 /* width */ 332 if ((props.wideness = n_fields(&name, 1, 1)) == 0) 333 return 0; 334 335 /* add style */ 336 if ((props.add_style = n_fields(&name, 1, 1)) == 0) 337 return 0; 338 339 /* pixel size */ 340 if ((str = n_fields(&name, 1, 1)) == 0) 341 return 0; 342 if ((props.pixel_size = atoi(str)) == 0) 343 return 0; 344 345 /* point size */ 346 if ((props.point_size = n_fields(&name, 1, 1)) == 0) 347 return 0; 348 349 /* res_x */ 350 if ((str = n_fields(&name, 1, 1)) == 0) 351 return 0; 352 if ((props.res_x = atoi(str)) == 0) 353 return 0; 354 355 /* res_y */ 356 if ((str = n_fields(&name, 1, 1)) == 0) 357 return 0; 358 if ((props.res_y = atoi(str)) == 0) 359 return 0; 360 361 /* spacing */ 362 if ((props.spacing = n_fields(&name, 1, 1)) == 0) 363 return 0; 364 365 /* average width */ 366 if ((str = n_fields(&name, 1, 1)) == 0) 367 return 0; 368 if ((props.average_width = atoi(str)) == 0) 369 return 0; 370 371 /* the rest: charset registry and charset encoding */ 372 props.end = name; 373 374 return &props; 375} 376 377#define ALLOCHUNK(n) ((n | 127) + 1) 378 379static void 380alloca_fontname(char **result, size_t next) 381{ 382 size_t last = (*result != 0) ? strlen(*result) : 0; 383 size_t have = (*result != 0) ? ALLOCHUNK(last) : 0; 384 size_t want = last + next + 2; 385 386 if (want >= have) { 387 want = ALLOCHUNK(want); 388 if (last != 0) { 389 char *save = *result; 390 *result = TypeRealloc(char, want, *result); 391 if (*result == 0) 392 free(save); 393 } else { 394 if ((*result = TypeMallocN(char, want)) != 0) 395 **result = '\0'; 396 } 397 } 398} 399 400static void 401append_fontname_str(char **result, const char *value) 402{ 403 if (value == 0) 404 value = "*"; 405 alloca_fontname(result, strlen(value)); 406 if (*result != 0) { 407 if (**result != '\0') 408 strcat(*result, "-"); 409 strcat(*result, value); 410 } 411} 412 413static void 414append_fontname_num(char **result, int value) 415{ 416 if (value < 0) { 417 append_fontname_str(result, "*"); 418 } else { 419 char temp[100]; 420 sprintf(temp, "%d", value); 421 append_fontname_str(result, temp); 422 } 423} 424 425/* 426 * Take the given font props and try to make a well formed font name specifying 427 * the same base font and size and everything, but with different weight/width 428 * according to the parameters. The return value is allocated, should be freed 429 * by the caller. 430 */ 431static char * 432derive_font_name(FontNameProperties *props, 433 const char *use_weight, 434 int use_average_width, 435 const char *use_encoding) 436{ 437 char *result = 0; 438 439 append_fontname_str(&result, props->beginning); 440 append_fontname_str(&result, use_weight); 441 append_fontname_str(&result, props->slant); 442 append_fontname_str(&result, 0); 443 append_fontname_str(&result, 0); 444 append_fontname_num(&result, props->pixel_size); 445 append_fontname_str(&result, props->point_size); 446 append_fontname_num(&result, props->res_x); 447 append_fontname_num(&result, props->res_y); 448 append_fontname_str(&result, props->spacing); 449 append_fontname_num(&result, use_average_width); 450 append_fontname_str(&result, use_encoding); 451 452 return result; 453} 454 455static char * 456bold_font_name(FontNameProperties *props, int use_average_width) 457{ 458 return derive_font_name(props, "bold", use_average_width, props->end); 459} 460 461#if OPT_WIDE_ATTRS 462static char * 463italic_font_name(FontNameProperties *props, const char *slant) 464{ 465 FontNameProperties myprops = *props; 466 myprops.slant = slant; 467 return derive_font_name(&myprops, props->weight, myprops.average_width, props->end); 468} 469 470static Boolean 471open_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data) 472{ 473 static const char *slant[] = 474 { 475 "o", 476 "i" 477 }; 478 char *name; 479 Cardinal pass; 480 Boolean result = False; 481 482 for (pass = 0; pass < XtNumber(slant); ++pass) { 483 if ((name = italic_font_name(fp, slant[pass])) != 0) { 484 TRACE(("open_italic_font %s %s\n", 485 whichFontEnum((VTFontEnum) n), name)); 486 if (xtermOpenFont(xw, name, data, False)) { 487 result = (data->fs != 0); 488#if OPT_REPORT_FONTS 489 if (resource.reportFonts) { 490 printf("opened italic version of %s:\n\t%s\n", 491 whichFontEnum(n), 492 name); 493 } 494#endif 495 } 496 free(name); 497 if (result) 498 break; 499 } 500 } 501#if OPT_TRACE 502 if (result) { 503 XFontStruct *fs = data->fs; 504 if (fs != 0) { 505 TRACE(("...actual size %dx%d (ascent %d, descent %d)\n", 506 fs->ascent + 507 fs->descent, 508 fs->max_bounds.width, 509 fs->ascent, 510 fs->descent)); 511 } 512 } 513#endif 514 return result; 515} 516#endif 517 518#if OPT_WIDE_CHARS 519#define derive_wide_font(props, weight) \ 520 derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 521 522static char * 523wide_font_name(FontNameProperties *props) 524{ 525 return derive_wide_font(props, "medium"); 526} 527 528static char * 529widebold_font_name(FontNameProperties *props) 530{ 531 return derive_wide_font(props, "bold"); 532} 533#endif /* OPT_WIDE_CHARS */ 534 535#if OPT_DEC_CHRSET 536/* 537 * Take the given font props and try to make a well formed font name specifying 538 * the same base font but changed depending on the given attributes and chrset. 539 * 540 * For double width fonts, we just double the X-resolution, for double height 541 * fonts we double the pixel-size and Y-resolution 542 */ 543char * 544xtermSpecialFont(XtermWidget xw, unsigned attr_flags, unsigned draw_flags, unsigned chrset) 545{ 546 TScreen *screen = TScreenOf(xw); 547#if OPT_TRACE 548 static char old_spacing[80]; 549 static FontNameProperties old_props; 550#endif 551 FontNameProperties *props; 552 char *result = 0; 553 const char *weight; 554 int pixel_size; 555 int res_x; 556 int res_y; 557 558 props = get_font_name_props(screen->display, 559 getNormalFont(screen, fNorm)->fs, 0); 560 if (props == 0) 561 return result; 562 563 pixel_size = props->pixel_size; 564 res_x = props->res_x; 565 res_y = props->res_y; 566 if (attr_flags & BOLD) 567 weight = "bold"; 568 else 569 weight = props->weight; 570 571 if (CSET_DOUBLE(chrset)) 572 res_x *= 2; 573 574 if (chrset == CSET_DHL_TOP 575 || chrset == CSET_DHL_BOT) { 576 res_y *= 2; 577 pixel_size *= 2; 578 } 579#if OPT_TRACE 580 if (old_props.res_x != res_x 581 || old_props.res_x != res_y 582 || old_props.pixel_size != pixel_size 583 || strcmp(old_props.spacing, props->spacing)) { 584 TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n", 585 attr_flags, draw_flags, chrset)); 586 TRACE(("res_x = %d\n", res_x)); 587 TRACE(("res_y = %d\n", res_y)); 588 TRACE(("point_size = %s\n", props->point_size)); 589 TRACE(("pixel_size = %d\n", pixel_size)); 590 TRACE(("spacing = %s\n", props->spacing)); 591 old_props.res_x = res_x; 592 old_props.res_y = res_y; 593 old_props.pixel_size = pixel_size; 594 old_props.spacing = old_spacing; 595 sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 596 } 597#endif 598 599 append_fontname_str(&result, props->beginning); 600 append_fontname_str(&result, weight); 601 append_fontname_str(&result, props->slant); 602 append_fontname_str(&result, props->wideness); 603 append_fontname_str(&result, props->add_style); 604 append_fontname_num(&result, pixel_size); 605 append_fontname_str(&result, props->point_size); 606 append_fontname_num(&result, (draw_flags & NORESOLUTION) ? -1 : res_x); 607 append_fontname_num(&result, (draw_flags & NORESOLUTION) ? -1 : res_y); 608 append_fontname_str(&result, props->spacing); 609 append_fontname_str(&result, 0); 610 append_fontname_str(&result, props->end); 611 612 return result; 613} 614#endif /* OPT_DEC_CHRSET */ 615 616/* 617 * Case-independent comparison for font-names, including wildcards. 618 * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 619 * to use it). 620 */ 621static Bool 622same_font_name(const char *pattern, const char *match) 623{ 624 Bool result = False; 625 626 if (pattern && match) { 627 while (*pattern && *match) { 628 if (*pattern == *match) { 629 pattern++; 630 match++; 631 } else if (*pattern == '*' || *match == '*') { 632 if (same_font_name(pattern + 1, match)) { 633 return True; 634 } else if (same_font_name(pattern, match + 1)) { 635 return True; 636 } else { 637 return False; 638 } 639 } else { 640 int p = x_toupper(*pattern++); 641 int m = x_toupper(*match++); 642 if (p != m) 643 return False; 644 } 645 } 646 result = (*pattern == *match); /* both should be NUL */ 647 } 648 return result; 649} 650 651/* 652 * Double-check the fontname that we asked for versus what the font server 653 * actually gave us. The larger fixed fonts do not always have a matching bold 654 * font, and the font server may try to scale another font or otherwise 655 * substitute a mismatched font. 656 * 657 * If we cannot get what we requested, we will fallback to the original 658 * behavior, which simulates bold by overstriking each character at one pixel 659 * offset. 660 */ 661static int 662got_bold_font(Display *dpy, XFontStruct *fs, String requested) 663{ 664 char *actual = 0; 665 int got; 666 667 if (get_font_name_props(dpy, fs, &actual) == 0) 668 got = 0; 669 else 670 got = same_font_name(requested, actual); 671 free(actual); 672 return got; 673} 674 675/* 676 * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able 677 * to check for missing glyphs in a comparable manner. 678 */ 679static int 680comparable_metrics(XFontStruct *normal, XFontStruct *bold) 681{ 682#define DATA "comparable_metrics: " 683 int result = 0; 684 685 if (normal == 0 || bold == 0) { 686 ; 687 } else if (normal->all_chars_exist) { 688 if (bold->all_chars_exist) { 689 result = 1; 690 } else { 691 TRACE((DATA "all chars exist in normal font, but not in bold\n")); 692 } 693 } else if (normal->per_char != 0) { 694 if (bold->per_char != 0) { 695 result = 1; 696 } else { 697 TRACE((DATA "normal font has per-char metrics, but not bold\n")); 698 } 699 } else { 700 TRACE((DATA "normal font is not very good!\n")); 701 result = 1; /* give in (we're not going in reverse) */ 702 } 703 return result; 704#undef DATA 705} 706 707/* 708 * If the font server tries to adjust another font, it may not adjust it 709 * properly. Check that the bounding boxes are compatible. Otherwise we'll 710 * leave trash on the display when we mix normal and bold fonts. 711 */ 712static int 713same_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs) 714{ 715 TScreen *screen = TScreenOf(xw); 716 int result = 0; 717 718 if (nfs != 0 && bfs != 0) { 719 TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 720 nfs->ascent + nfs->descent, 721 bfs->ascent + bfs->descent, 722 nfs->min_bounds.width, bfs->min_bounds.width, 723 nfs->max_bounds.width, bfs->max_bounds.width)); 724 result = screen->free_bold_box 725 || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 726 && (nfs->min_bounds.width == bfs->min_bounds.width 727 || nfs->min_bounds.width == bfs->min_bounds.width + 1) 728 && (nfs->max_bounds.width == bfs->max_bounds.width 729 || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 730 } 731 return result; 732} 733 734/* 735 * Check if the font looks like it has fixed width 736 */ 737static int 738is_fixed_font(XFontStruct *fs) 739{ 740 if (fs) 741 return (fs->min_bounds.width == fs->max_bounds.width); 742 return 1; 743} 744 745/* 746 * Check if the font looks like a double width font (i.e. contains 747 * characters of width X and 2X 748 */ 749#if OPT_WIDE_CHARS 750static int 751is_double_width_font(XFontStruct *fs) 752{ 753 return ((2 * fs->min_bounds.width) == fs->max_bounds.width); 754} 755#else 756#define is_double_width_font(fs) 0 757#endif 758 759#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 760#define HALF_WIDTH_TEST_STRING "1234567890" 761 762/* '1234567890' in Chinese characters in UTF-8 */ 763#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 764 "\xe5\x9b\x9b\xe4\xba\x94" \ 765 "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 766 "\xe4\xb9\x9d\xef\xa6\xb2" 767 768/* '1234567890' in Korean script in UTF-8 */ 769#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 770 "\xec\x82\xac\xec\x98\xa4" \ 771 "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 772 "\xea\xb5\xac\xec\x98\x81" 773 774#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 775#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 776#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 777#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 778 779static Bool 780is_double_width_font_xft(Display *dpy, XftFont *font) 781{ 782 XGlyphInfo gi1, gi2; 783 FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 784 String fwstr = FULL_WIDTH_TEST_STRING; 785 String hwstr = HALF_WIDTH_TEST_STRING; 786 787 /* Some Korean fonts don't have Chinese characters at all. */ 788 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 789 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 790 return False; /* Not a CJK font */ 791 else /* a Korean font without CJK Ideographs */ 792 fwstr = FULL_WIDTH_TEST_STRING2; 793 } 794 795 XftTextExtents32(dpy, font, &c1, 1, &gi1); 796 XftTextExtents32(dpy, font, &c2, 1, &gi2); 797 if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 798 return False; 799 800 XftTextExtentsUtf8(dpy, 801 font, 802 (_Xconst FcChar8 *) hwstr, 803 (int) strlen(hwstr), 804 &gi1); 805 XftTextExtentsUtf8(dpy, 806 font, 807 (_Xconst FcChar8 *) fwstr, 808 (int) strlen(fwstr), 809 &gi2); 810 811 /* 812 * fontconfig and Xft prior to 2.2(?) set the width of half-width 813 * characters identical to that of full-width character in CJK double-width 814 * (bi-width / monospace) font even though the former is half as wide as 815 * the latter. This was fixed sometime before the release of fontconfig 816 * 2.2 in early 2003. See 817 * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 818 * In the meantime, we have to check both possibilities. 819 */ 820 return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 821} 822#else 823#define is_double_width_font_xft(dpy, xftfont) 0 824#endif 825 826#define EmptyFont(fs) (fs != 0 \ 827 && ((fs)->ascent + (fs)->descent == 0 \ 828 || (fs)->max_bounds.width == 0)) 829 830#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 831 * (fs)->max_bounds.width) 832 833const VTFontNames * 834xtermFontName(const char *normal) 835{ 836 static VTFontNames data; 837 FREE_STRING(data.f_n); 838 memset(&data, 0, sizeof(data)); 839 if (normal) 840 data.f_n = x_strdup(normal); 841 return &data; 842} 843 844const VTFontNames * 845defaultVTFontNames(XtermWidget xw) 846{ 847 static VTFontNames data; 848 memset(&data, 0, sizeof(data)); 849 data.f_n = DefaultFontN(xw); 850 data.f_b = DefaultFontB(xw); 851#if OPT_WIDE_CHARS 852 data.f_w = DefaultFontW(xw); 853 data.f_wb = DefaultFontWB(xw); 854#endif 855 return &data; 856} 857 858static void 859cache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 860{ 861 if (name != 0) { 862 String last = screen->menu_font_names[fontnum][which]; 863 if (last != 0) { 864 if (strcmp(last, name)) { 865 FREE_STRING(last); 866 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 867 screen->menu_font_names[fontnum][which] = x_strdup(name); 868 } 869 } else { 870 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 871 screen->menu_font_names[fontnum][which] = x_strdup(name); 872 } 873 } 874} 875 876typedef struct _cannotFont { 877 struct _cannotFont *next; 878 char *where; 879} CannotFont; 880 881static void 882cannotFont(XtermWidget xw, const char *who, const char *what, const char *where) 883{ 884 static CannotFont *ignored; 885 CannotFont *list; 886 887 switch (xw->misc.fontWarnings) { 888 case fwNever: 889 return; 890 case fwResource: 891 for (list = ignored; list != 0; list = list->next) { 892 if (!strcmp(where, list->where)) { 893 return; 894 } 895 } 896 if ((list = TypeMalloc(CannotFont)) != 0) { 897 list->where = x_strdup(where); 898 list->next = ignored; 899 ignored = list; 900 } 901 break; 902 case fwAlways: 903 break; 904 } 905 TRACE(("OOPS: cannot %s%s%s font \"%s\"\n", who, *what ? " " : "", what, where)); 906 xtermWarning("cannot %s%s%s font \"%s\"\n", who, *what ? " " : "", what, where); 907} 908 909/* 910 * Open the given font and verify that it is non-empty. Return a null on 911 * failure. 912 */ 913Bool 914xtermOpenFont(XtermWidget xw, 915 const char *name, 916 XTermFonts * result, 917 Bool force) 918{ 919 Bool code = False; 920 TScreen *screen = TScreenOf(xw); 921 922 if (!IsEmpty(name)) { 923 if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) { 924 code = True; 925 if (EmptyFont(result->fs)) { 926 xtermCloseFont(xw, result); 927 code = False; 928 } else { 929 result->fn = x_strdup(name); 930 } 931 } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 932 if (result->warn <= xw->misc.fontWarnings 933#if OPT_RENDERFONT 934 && !UsingRenderFont(xw) 935#endif 936 ) { 937 TRACE(("OOPS: cannot load font %s\n", name)); 938 cannotFont(xw, "load", "", name); 939 } else { 940 TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 941 } 942 if (force) { 943 result->warn = fwAlways; 944 code = xtermOpenFont(xw, DEFFONT, result, True); 945 } 946 } 947 } 948 result->warn = fwAlways; 949 return code; 950} 951 952/* 953 * Close the font and free the font info. 954 */ 955void 956xtermCloseFont(XtermWidget xw, XTermFonts * fnt) 957{ 958 if (fnt != 0 && fnt->fs != 0) { 959 TScreen *screen = TScreenOf(xw); 960 961 clrCgsFonts(xw, WhichVWin(screen), fnt); 962 XFreeFont(screen->display, fnt->fs); 963 xtermFreeFontInfo(fnt); 964 } 965} 966 967/* 968 * Close and free the font (as well as any aliases). 969 */ 970static void 971xtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which) 972{ 973 XFontStruct *thisFont = fnts[which].fs; 974 975 if (thisFont != 0) { 976 int k; 977 978 xtermCloseFont(xw, &fnts[which]); 979 for (k = 0; k < fMAX; ++k) { 980 if (k != which) { 981 if (thisFont == fnts[k].fs) { 982 xtermFreeFontInfo(&fnts[k]); 983 } 984 } 985 } 986 } 987} 988 989/* 990 * Close the listed fonts, noting that some may use copies of the pointer. 991 */ 992void 993xtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 994{ 995 int j; 996 997 for (j = 0; j < fMAX; ++j) { 998 xtermCloseFont2(xw, fnts, j); 999 } 1000} 1001 1002/* 1003 * Make a copy of the source, assuming the XFontStruct's to be unique, but 1004 * ensuring that the names are reallocated to simplify freeing. 1005 */ 1006void 1007xtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 1008{ 1009 xtermFreeFontInfo(target); 1010 target->chrset = source->chrset; 1011 target->flags = source->flags; 1012 target->fn = x_strdup(source->fn); 1013 target->fs = source->fs; 1014 target->warn = source->warn; 1015} 1016 1017void 1018xtermFreeFontInfo(XTermFonts * target) 1019{ 1020 target->chrset = 0; 1021 target->flags = 0; 1022 if (target->fn != 0) { 1023 free(target->fn); 1024 target->fn = 0; 1025 } 1026 target->fs = 0; 1027} 1028 1029#if OPT_REPORT_FONTS 1030static void 1031reportXCharStruct(const char *tag, XCharStruct * cs) 1032{ 1033 printf("\t\t%s:\n", tag); 1034 printf("\t\t\tlbearing: %d\n", cs->lbearing); 1035 printf("\t\t\trbearing: %d\n", cs->rbearing); 1036 printf("\t\t\twidth: %d\n", cs->width); 1037 printf("\t\t\tascent: %d\n", cs->ascent); 1038 printf("\t\t\tdescent: %d\n", cs->descent); 1039} 1040 1041static void 1042reportOneVTFont(const char *tag, 1043 XTermFonts * fnt) 1044{ 1045 if (!IsEmpty(fnt->fn) && fnt->fs != 0) { 1046 XFontStruct *fs = fnt->fs; 1047 unsigned first_char = 0; 1048 unsigned last_char = 0; 1049 1050 if (fs->max_byte1 == 0) { 1051 first_char = fs->min_char_or_byte2; 1052 last_char = fs->max_char_or_byte2; 1053 } else { 1054 first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1055 last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1056 } 1057 1058 printf("\t%s: %s\n", tag, NonNull(fnt->fn)); 1059 printf("\t\tall chars: %s\n", fs->all_chars_exist ? "yes" : "no"); 1060 printf("\t\tdefault char: %d\n", fs->default_char); 1061 printf("\t\tdirection: %d\n", fs->direction); 1062 printf("\t\tascent: %d\n", fs->ascent); 1063 printf("\t\tdescent: %d\n", fs->descent); 1064 printf("\t\tfirst char: %u\n", first_char); 1065 printf("\t\tlast char: %u\n", last_char); 1066 printf("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 1067 if (FontLacksMetrics(fnt)) { 1068 printf("\t\tmissing-chars: ?\n"); 1069 printf("\t\tpresent-chars: ?\n"); 1070 } else { 1071 unsigned missing = 0; 1072 unsigned ch; 1073 for (ch = first_char; ch <= last_char; ++ch) { 1074 if (xtermMissingChar(ch, fnt)) { 1075 ++missing; 1076 } 1077 } 1078 printf("\t\tmissing-chars: %u\n", missing); 1079 printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 1080 } 1081 printf("\t\tmin_byte1: %d\n", fs->min_byte1); 1082 printf("\t\tmax_byte1: %d\n", fs->max_byte1); 1083 printf("\t\tproperties: %d\n", fs->n_properties); 1084 reportXCharStruct("min_bounds", &(fs->min_bounds)); 1085 reportXCharStruct("max_bounds", &(fs->max_bounds)); 1086 /* TODO: report fs->properties and fs->per_char */ 1087 } 1088} 1089 1090static void 1091reportVTFontInfo(XtermWidget xw, int fontnum) 1092{ 1093 if (resource.reportFonts) { 1094 TScreen *screen = TScreenOf(xw); 1095 1096 if (fontnum) { 1097 printf("Loaded VTFonts(font%d)\n", fontnum); 1098 } else { 1099 printf("Loaded VTFonts(default)\n"); 1100 } 1101 1102 reportOneVTFont("fNorm", getNormalFont(screen, fNorm)); 1103 reportOneVTFont("fBold", getNormalFont(screen, fBold)); 1104#if OPT_WIDE_CHARS 1105 reportOneVTFont("fWide", getNormalFont(screen, fWide)); 1106 reportOneVTFont("fWBold", getNormalFont(screen, fWBold)); 1107#endif 1108 } 1109} 1110#endif 1111 1112typedef XTermFonts *(*MyGetFont) (TScreen *, int); 1113 1114void 1115xtermUpdateFontGCs(XtermWidget xw, Bool italic) 1116{ 1117 TScreen *screen = TScreenOf(xw); 1118#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 1119 MyGetFont myfunc = italic ? getItalicFont : getNormalFont; 1120#else 1121 MyGetFont myfunc = getNormalFont; 1122#endif 1123 VTwin *win = WhichVWin(screen); 1124 Pixel new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground); 1125 Pixel new_revers = getXtermBackground(xw, xw->flags, xw->cur_background); 1126 1127 (void) italic; 1128 1129 setCgsFore(xw, win, gcNorm, new_normal); 1130 setCgsBack(xw, win, gcNorm, new_revers); 1131 setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm)); 1132 1133 copyCgs(xw, win, gcBold, gcNorm); 1134 setCgsFont(xw, win, gcBold, myfunc(screen, fBold)); 1135 1136 setCgsFore(xw, win, gcNormReverse, new_revers); 1137 setCgsBack(xw, win, gcNormReverse, new_normal); 1138 setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm)); 1139 1140 copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1141 setCgsFont(xw, win, gcBoldReverse, myfunc(screen, fBold)); 1142 1143 if_OPT_WIDE_CHARS(screen, { 1144 XTermFonts *wide_xx = myfunc(screen, fWide); 1145 XTermFonts *bold_xx = myfunc(screen, fWBold); 1146 if (wide_xx->fs != 0 1147 && bold_xx->fs != 0) { 1148 setCgsFore(xw, win, gcWide, new_normal); 1149 setCgsBack(xw, win, gcWide, new_revers); 1150 setCgsFont(xw, win, gcWide, wide_xx); 1151 1152 copyCgs(xw, win, gcWBold, gcWide); 1153 setCgsFont(xw, win, gcWBold, bold_xx); 1154 1155 setCgsFore(xw, win, gcWideReverse, new_revers); 1156 setCgsBack(xw, win, gcWideReverse, new_normal); 1157 setCgsFont(xw, win, gcWideReverse, wide_xx); 1158 1159 copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1160 setCgsFont(xw, win, gcWBoldReverse, bold_xx); 1161 } 1162 }); 1163} 1164 1165#if OPT_TRACE 1166static void 1167show_font_misses(const char *name, XTermFonts * fp) 1168{ 1169 if (fp->fs != 0) { 1170 if (FontLacksMetrics(fp)) { 1171 TRACE(("%s font lacks metrics\n", name)); 1172 } else if (FontIsIncomplete(fp)) { 1173 TRACE(("%s font is incomplete\n", name)); 1174 } else { 1175 TRACE(("%s font is complete\n", name)); 1176 } 1177 } else { 1178 TRACE(("%s font is missing\n", name)); 1179 } 1180} 1181#endif 1182 1183static Bool 1184loadNormFP(XtermWidget xw, 1185 char **nameOutP, 1186 XTermFonts * infoOut, 1187 int fontnum) 1188{ 1189 Bool status = True; 1190 1191 TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP))); 1192 1193 if (!xtermOpenFont(xw, 1194 *nameOutP, 1195 infoOut, 1196 (fontnum == fontMenu_default))) { 1197 /* 1198 * If we are opening the default font, and it happens to be missing, 1199 * force that to the compiled-in default font, e.g., "fixed". If we 1200 * cannot open the font, disable it from the menu. 1201 */ 1202 if (fontnum != fontMenu_fontsel) { 1203 SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1204 } 1205 status = False; 1206 } 1207 return status; 1208} 1209 1210static Bool 1211loadBoldFP(XtermWidget xw, 1212 char **nameOutP, 1213 XTermFonts * infoOut, 1214 const char *nameRef, 1215 XTermFonts * infoRef, 1216 int fontnum) 1217{ 1218 TScreen *screen = TScreenOf(xw); 1219 Bool status = True; 1220 1221 TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP))); 1222 1223 if (!check_fontname(*nameOutP)) { 1224 FontNameProperties *fp; 1225 char *normal = x_strdup(nameRef); 1226 1227 fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1228 if (fp != 0) { 1229 *nameOutP = bold_font_name(fp, fp->average_width); 1230 if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1231 free(*nameOutP); 1232 *nameOutP = bold_font_name(fp, -1); 1233 xtermOpenFont(xw, *nameOutP, infoOut, False); 1234 } 1235 TRACE(("...derived bold '%s'\n", NonNull(*nameOutP))); 1236 } 1237 if (fp == 0 || infoOut->fs == 0) { 1238 xtermCopyFontInfo(infoOut, infoRef); 1239 TRACE(("...cannot load a matching bold font\n")); 1240 } else if (comparable_metrics(infoRef->fs, infoOut->fs) 1241 && same_font_size(xw, infoRef->fs, infoOut->fs) 1242 && got_bold_font(screen->display, infoOut->fs, *nameOutP)) { 1243 TRACE(("...got a matching bold font\n")); 1244 cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1245 } else { 1246 xtermCloseFont2(xw, infoOut - fBold, fBold); 1247 *infoOut = *infoRef; 1248 TRACE(("...did not get a matching bold font\n")); 1249 } 1250 free(normal); 1251 } else if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1252 xtermCopyFontInfo(infoOut, infoRef); 1253 TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP))); 1254 } else { 1255 cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1256 } 1257 1258 /* 1259 * Most of the time this call to load the font will succeed, even if 1260 * there is no wide font : the X server doubles the width of the 1261 * normal font, or similar. 1262 * 1263 * But if it did fail for some reason, then nevermind. 1264 */ 1265 if (EmptyFont(infoOut->fs)) 1266 status = False; /* can't use a 0-sized font */ 1267 1268 if (!same_font_size(xw, infoRef->fs, infoOut->fs) 1269 && (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) { 1270 TRACE(("...ignoring mismatched normal/bold fonts\n")); 1271 xtermCloseFont2(xw, infoOut - fBold, fBold); 1272 xtermCopyFontInfo(infoOut, infoRef); 1273 } 1274 1275 return status; 1276} 1277 1278#if OPT_WIDE_CHARS 1279static Bool 1280loadWideFP(XtermWidget xw, 1281 char **nameOutP, 1282 XTermFonts * infoOut, 1283 const char *nameRef, 1284 XTermFonts * infoRef, 1285 int fontnum) 1286{ 1287 TScreen *screen = TScreenOf(xw); 1288 FontNameProperties *fp; 1289 Bool status = True; 1290 1291 TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP))); 1292 1293 if (check_fontname(*nameOutP)) { 1294 cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1295 } else if (screen->utf8_fonts && !is_double_width_font(infoRef->fs)) { 1296 char *normal = x_strdup(nameRef); 1297 fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1298 if (fp != 0) { 1299 *nameOutP = wide_font_name(fp); 1300 TRACE(("...derived wide %s\n", NonNull(*nameOutP))); 1301 cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1302 } 1303 free(normal); 1304 } 1305 1306 if (check_fontname(*nameOutP)) { 1307 if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) { 1308 xtermCopyFontInfo(infoOut, infoRef); 1309 } 1310 } else { 1311 xtermCopyFontInfo(infoOut, infoRef); 1312 } 1313 return status; 1314} 1315 1316static Bool 1317loadWBoldFP(XtermWidget xw, 1318 char **nameOutP, 1319 XTermFonts * infoOut, 1320 const char *wideNameRef, XTermFonts * wideInfoRef, 1321 const char *boldNameRef, XTermFonts * boldInfoRef, 1322 int fontnum) 1323{ 1324 TScreen *screen = TScreenOf(xw); 1325 Bool status = True; 1326 Boolean derived; 1327 char *bold = NULL; 1328 1329 TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP))); 1330 1331 derived = False; 1332 if (!check_fontname(*nameOutP)) { 1333 FontNameProperties *fp; 1334 fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold); 1335 if (fp != 0) { 1336 *nameOutP = widebold_font_name(fp); 1337 derived = True; 1338 } 1339 } 1340 1341 if (check_fontname(*nameOutP)) { 1342 1343 if (xtermOpenFont(xw, *nameOutP, infoOut, False) 1344 && derived 1345 && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) { 1346 xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1347 } 1348 1349 if (infoOut->fs == 0) { 1350 if (derived) 1351 free(*nameOutP); 1352 if (IsEmpty(wideNameRef)) { 1353 *nameOutP = x_strdup(boldNameRef); 1354 xtermCopyFontInfo(infoOut, boldInfoRef); 1355 TRACE(("...cannot load wide-bold, use bold %s\n", 1356 NonNull(boldNameRef))); 1357 } else { 1358 *nameOutP = x_strdup(wideNameRef); 1359 xtermCopyFontInfo(infoOut, wideInfoRef); 1360 TRACE(("...cannot load wide-bold, use wide %s\n", 1361 NonNull(wideNameRef))); 1362 } 1363 } else { 1364 TRACE(("...%s wide/bold %s\n", 1365 derived ? "derived" : "given", 1366 NonNull(*nameOutP))); 1367 cache_menu_font_name(screen, fontnum, fWBold, *nameOutP); 1368 } 1369 } else if (is_double_width_font(boldInfoRef->fs)) { 1370 xtermCopyFontInfo(infoOut, boldInfoRef); 1371 TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef))); 1372 } else { 1373 xtermCopyFontInfo(infoOut, wideInfoRef); 1374 TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef))); 1375 } 1376 1377 free(bold); 1378 1379 if (EmptyFont(infoOut->fs)) { 1380 status = False; /* can't use a 0-sized font */ 1381 } else { 1382 if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs) 1383 || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs) 1384 && is_fixed_font(wideInfoRef->fs) 1385 && is_fixed_font(infoOut->fs)))) { 1386 TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1387 xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1388 xtermCopyFontInfo(infoOut, wideInfoRef); 1389 } 1390 } 1391 1392 return status; 1393} 1394#endif 1395 1396int 1397xtermLoadFont(XtermWidget xw, 1398 const VTFontNames * fonts, 1399 Bool doresize, 1400 int fontnum) 1401{ 1402 TScreen *screen = TScreenOf(xw); 1403 VTwin *win = WhichVWin(screen); 1404 1405 VTFontNames myfonts; 1406 XTermFonts fnts[fMAX]; 1407 char *tmpname = NULL; 1408 Boolean proportional = False; 1409 1410 memset(&myfonts, 0, sizeof(myfonts)); 1411 memset(fnts, 0, sizeof(fnts)); 1412 1413 if (fonts != 0) 1414 myfonts = *fonts; 1415 if (!check_fontname(myfonts.f_n)) 1416 return 0; 1417 1418 if (fontnum == fontMenu_fontescape 1419 && myfonts.f_n != screen->MenuFontName(fontnum)) { 1420 if ((tmpname = x_strdup(myfonts.f_n)) == 0) 1421 return 0; 1422 } 1423 1424 TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n)); 1425 releaseWindowGCs(xw, win); 1426 1427#define DbgResource(name, field, index) \ 1428 TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1429 fontnum, \ 1430 (fnts[index].warn == fwResource) ? "*" : " ", \ 1431 NonNull(myfonts.field))) 1432 DbgResource("normal", f_n, fNorm); 1433 DbgResource("bold ", f_b, fBold); 1434#if OPT_WIDE_CHARS 1435 DbgResource("wide ", f_w, fWide); 1436 DbgResource("w/bold", f_wb, fWBold); 1437#endif 1438 1439 if (!loadNormFP(xw, 1440 &myfonts.f_n, 1441 &fnts[fNorm], 1442 fontnum)) 1443 goto bad; 1444 1445 if (!loadBoldFP(xw, 1446 &myfonts.f_b, 1447 &fnts[fBold], 1448 myfonts.f_n, 1449 &fnts[fNorm], 1450 fontnum)) 1451 goto bad; 1452 1453 /* 1454 * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1455 * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1456 * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1457 */ 1458 if_OPT_WIDE_CHARS(screen, { 1459 1460 if (!loadWideFP(xw, 1461 &myfonts.f_w, 1462 &fnts[fWide], 1463 myfonts.f_n, 1464 &fnts[fNorm], 1465 fontnum)) 1466 goto bad; 1467 1468 if (!loadWBoldFP(xw, 1469 &myfonts.f_wb, 1470 &fnts[fWBold], 1471 myfonts.f_w, 1472 &fnts[fWide], 1473 myfonts.f_b, 1474 &fnts[fBold], 1475 fontnum)) 1476 goto bad; 1477 1478 }); 1479 1480 /* 1481 * Normal/bold fonts should be the same width. Also, the min/max 1482 * values should be the same. 1483 */ 1484 if (!is_fixed_font(fnts[fNorm].fs) 1485 || !is_fixed_font(fnts[fBold].fs) 1486 || fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) { 1487 TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1488 fnts[fNorm].fs->min_bounds.width, 1489 fnts[fNorm].fs->max_bounds.width, 1490 fnts[fBold].fs->min_bounds.width, 1491 fnts[fBold].fs->max_bounds.width)); 1492 proportional = True; 1493 } 1494 1495 if_OPT_WIDE_CHARS(screen, { 1496 if (fnts[fWide].fs != 0 1497 && fnts[fWBold].fs != 0 1498 && (!is_fixed_font(fnts[fWide].fs) 1499 || !is_fixed_font(fnts[fWBold].fs) 1500 || fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) { 1501 TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1502 fnts[fWide].fs->min_bounds.width, 1503 fnts[fWide].fs->max_bounds.width, 1504 fnts[fWBold].fs->min_bounds.width, 1505 fnts[fWBold].fs->max_bounds.width)); 1506 proportional = True; 1507 } 1508 }); 1509 1510 /* TODO : enforce that the width of the wide font is 2* the width 1511 of the narrow font */ 1512 1513 /* 1514 * If we're switching fonts, free the old ones. Otherwise we'll leak 1515 * the memory that is associated with the old fonts. The 1516 * XLoadQueryFont call allocates a new XFontStruct. 1517 */ 1518 xtermCloseFonts(xw, screen->fnts); 1519#if OPT_WIDE_ATTRS 1520 xtermCloseFonts(xw, screen->ifnts); 1521 screen->ifnts_ok = False; 1522#endif 1523 1524 xtermCopyFontInfo(getNormalFont(screen, fNorm), &fnts[fNorm]); 1525 xtermCopyFontInfo(getNormalFont(screen, fBold), &fnts[fBold]); 1526#if OPT_WIDE_CHARS 1527 xtermCopyFontInfo(getNormalFont(screen, fWide), &fnts[fWide]); 1528 if (fnts[fWBold].fs == NULL) 1529 xtermCopyFontInfo(getNormalFont(screen, fWide), &fnts[fWide]); 1530 xtermCopyFontInfo(getNormalFont(screen, fWBold), &fnts[fWBold]); 1531#endif 1532 1533 xtermUpdateFontGCs(xw, False); 1534 1535#if OPT_BOX_CHARS 1536 screen->allow_packing = proportional; 1537 setupPackedFonts(xw); 1538#endif 1539 screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1540 screen->fnt_boxes = True; 1541 1542#if OPT_BOX_CHARS 1543 /* 1544 * xterm uses character positions 1-31 of a font for the line-drawing 1545 * characters. Check that they are all present. The null character 1546 * (0) is special, and is not used. 1547 */ 1548#if OPT_RENDERFONT 1549 if (UsingRenderFont(xw)) { 1550 /* 1551 * FIXME: we shouldn't even be here if we're using Xft. 1552 */ 1553 screen->fnt_boxes = False; 1554 TRACE(("assume Xft missing line-drawing chars\n")); 1555 } else 1556#endif 1557 { 1558 unsigned ch; 1559 1560#if OPT_TRACE 1561#define TRACE_MISS(index) show_font_misses(#index, &fnts[index]) 1562 TRACE_MISS(fNorm); 1563 TRACE_MISS(fBold); 1564#if OPT_WIDE_CHARS 1565 TRACE_MISS(fWide); 1566 TRACE_MISS(fWBold); 1567#endif 1568#endif 1569 1570 for (ch = 1; ch < 32; ch++) { 1571 unsigned n = ch; 1572#if OPT_WIDE_CHARS 1573 if (screen->utf8_mode || screen->unicode_font) { 1574 n = dec2ucs(ch); 1575 if (n == UCS_REPL) 1576 continue; 1577 } 1578#endif 1579 if (IsXtermMissingChar(screen, n, &fnts[fNorm])) { 1580 TRACE(("missing normal char #%d\n", n)); 1581 screen->fnt_boxes = False; 1582 break; 1583 } 1584 if (IsXtermMissingChar(screen, n, &fnts[fBold])) { 1585 TRACE(("missing bold char #%d\n", n)); 1586 screen->fnt_boxes = False; 1587 break; 1588 } 1589 } 1590 } 1591 TRACE(("Will %suse internal line-drawing characters\n", 1592 screen->fnt_boxes ? "not " : "")); 1593#endif 1594 1595 if (screen->always_bold_mode) { 1596 screen->enbolden = screen->bold_mode; 1597 } else { 1598 screen->enbolden = screen->bold_mode 1599 && ((fnts[fNorm].fs == fnts[fBold].fs) 1600 || same_font_name(myfonts.f_n, myfonts.f_b)); 1601 } 1602 TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1603 screen->enbolden ? "" : "not ")); 1604 1605 set_menu_font(False); 1606 screen->menu_font_number = fontnum; 1607 set_menu_font(True); 1608 if (tmpname) { /* if setting escape or sel */ 1609 if (screen->MenuFontName(fontnum)) 1610 FREE_STRING(screen->MenuFontName(fontnum)); 1611 screen->MenuFontName(fontnum) = tmpname; 1612 if (fontnum == fontMenu_fontescape) { 1613 update_font_escape(); 1614 } 1615#if OPT_SHIFT_FONTS 1616 screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs); 1617#endif 1618 } 1619 set_cursor_gcs(xw); 1620 xtermUpdateFontInfo(xw, doresize); 1621 TRACE(("Success Cgs - xtermLoadFont\n")); 1622#if OPT_REPORT_FONTS 1623 reportVTFontInfo(xw, fontnum); 1624#endif 1625 FREE_FNAME(f_n); 1626 FREE_FNAME(f_b); 1627#if OPT_WIDE_CHARS 1628 FREE_FNAME(f_w); 1629 FREE_FNAME(f_wb); 1630#endif 1631 if (fnts[fNorm].fn == fnts[fBold].fn) { 1632 free(fnts[fNorm].fn); 1633 } else { 1634 free(fnts[fNorm].fn); 1635 free(fnts[fBold].fn); 1636 } 1637#if OPT_WIDE_CHARS 1638 free(fnts[fWide].fn); 1639 free(fnts[fWBold].fn); 1640#endif 1641 xtermSetWinSize(xw); 1642 return 1; 1643 1644 bad: 1645 if (tmpname) 1646 free(tmpname); 1647 1648#if OPT_RENDERFONT 1649 if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) { 1650 int old_fontnum = screen->menu_font_number; 1651#if OPT_TOOLBAR 1652 SetItemSensitivity(fontMenuEntries[fontnum].widget, True); 1653#endif 1654 Bell(xw, XkbBI_MinorError, 0); 1655 myfonts.f_n = screen->MenuFontName(old_fontnum); 1656 return xtermLoadFont(xw, &myfonts, doresize, old_fontnum); 1657 } else if (x_strcasecmp(myfonts.f_n, DEFFONT)) { 1658 int code; 1659 1660 myfonts.f_n = x_strdup(DEFFONT); 1661 TRACE(("...recovering for TrueType fonts\n")); 1662 code = xtermLoadFont(xw, &myfonts, doresize, fontnum); 1663 if (code) { 1664 if (fontnum != fontMenu_fontsel) { 1665 SetItemSensitivity(fontMenuEntries[fontnum].widget, 1666 UsingRenderFont(xw)); 1667 } 1668 TRACE(("...recovered size %dx%d\n", 1669 FontHeight(screen), 1670 FontWidth(screen))); 1671 } 1672 return code; 1673 } 1674#endif 1675 1676 releaseWindowGCs(xw, win); 1677 1678 xtermCloseFonts(xw, fnts); 1679 TRACE(("Fail Cgs - xtermLoadFont\n")); 1680 return 0; 1681} 1682 1683#if OPT_WIDE_ATTRS 1684/* 1685 * (Attempt to) load matching italics for the current normal/bold/etc fonts. 1686 * If the attempt fails for a given style, use the non-italic font. 1687 */ 1688void 1689xtermLoadItalics(XtermWidget xw) 1690{ 1691 TScreen *screen = TScreenOf(xw); 1692 1693 if (!screen->ifnts_ok) { 1694 int n; 1695 FontNameProperties *fp; 1696 XTermFonts *data; 1697 1698 screen->ifnts_ok = True; 1699 for (n = 0; n < fMAX; ++n) { 1700 switch (n) { 1701 case fNorm: 1702 /* FALLTHRU */ 1703 case fBold: 1704 /* FALLTHRU */ 1705#if OPT_WIDE_CHARS 1706 case fWide: 1707 /* FALLTHRU */ 1708 case fWBold: 1709#endif 1710 /* FALLTHRU */ 1711 data = getItalicFont(screen, n); 1712 1713 /* 1714 * FIXME - need to handle font-leaks 1715 */ 1716 data->fs = 0; 1717 if (getNormalFont(screen, n)->fs != 0 && 1718 (fp = get_font_name_props(screen->display, 1719 getNormalFont(screen, n)->fs, 1720 0)) != 0) { 1721 if (!open_italic_font(xw, n, fp, data)) { 1722 if (n > 0) { 1723 xtermCopyFontInfo(data, 1724 getItalicFont(screen, n - 1)); 1725 } else { 1726 xtermOpenFont(xw, 1727 getNormalFont(screen, n)->fn, 1728 data, False); 1729 } 1730 } 1731 } 1732 break; 1733 } 1734 } 1735 } 1736} 1737#endif 1738 1739#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1740/* 1741 * Collect font-names that we can modify with the load-vt-fonts() action. 1742 */ 1743#define MERGE_SUBFONT(dst,src,name) \ 1744 if (IsEmpty(dst.name)) { \ 1745 TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \ 1746 dst.name = x_strdup(src.name); \ 1747 } else { \ 1748 TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1749 } 1750#define MERGE_SUBLIST(dst,src,name) \ 1751 if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \ 1752 TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \ 1753 } else { \ 1754 TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \ 1755 } 1756 1757#define INFER_SUBFONT(dst,src,name) \ 1758 if (IsEmpty(dst.name)) { \ 1759 TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1760 dst.name = x_strdup(""); \ 1761 } else { \ 1762 TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 1763 } 1764 1765#define FREE_MENU_FONTS(dst) \ 1766 TRACE(("FREE_MENU_FONTS " #dst "\n")); \ 1767 for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1768 for (m = 0; m < fMAX; ++m) { \ 1769 FREE_STRING(dst.menu_font_names[n][m]); \ 1770 dst.menu_font_names[n][m] = 0; \ 1771 } \ 1772 } 1773 1774#define COPY_MENU_FONTS(dst,src) \ 1775 TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1776 for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1777 for (m = 0; m < fMAX; ++m) { \ 1778 FREE_STRING(dst.menu_font_names[n][m]); \ 1779 dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1780 } \ 1781 TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \ 1782 } 1783 1784#define COPY_DEFAULT_FONTS(target, source) \ 1785 TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \ 1786 xtermCopyVTFontNames(&target.default_font, &source.default_font) 1787 1788#define COPY_X11_FONTLISTS(target, source) \ 1789 TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \ 1790 xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11) 1791 1792static void 1793xtermCopyVTFontNames(VTFontNames * target, VTFontNames * source) 1794{ 1795#define COPY_IT(name,field) \ 1796 TRACE((".. "#name" = %s\n", NonNull(source->field))); \ 1797 free(target->field); \ 1798 target->field = x_strdup(source->field) 1799 1800 TRACE(("xtermCopyVTFontNames\n")); 1801 1802 COPY_IT(font, f_n); 1803 COPY_IT(boldFont, f_b); 1804 1805#if OPT_WIDE_CHARS 1806 COPY_IT(wideFont, f_w); 1807 COPY_IT(wideBoldFont, f_wb); 1808#endif 1809#undef COPY_IT 1810} 1811 1812static void 1813xtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source) 1814{ 1815#define COPY_IT(name,field) \ 1816 copyFontList(&(target->field), source->field); \ 1817 TRACE_ARGV(".. " #name, source->field) 1818 1819 (void) xw; 1820 TRACE(("xtermCopyFontLists %s ->%s\n", 1821 whichFontList(xw, source), 1822 whichFontList(xw, target))); 1823 1824 COPY_IT(font, list_n); 1825 COPY_IT(fontBold, list_b); 1826#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 1827 COPY_IT(fontItal, list_i); 1828#endif 1829#if OPT_WIDE_CHARS 1830 COPY_IT(wideFont, list_w); 1831 COPY_IT(wideBoldFont, list_wb); 1832 COPY_IT(wideItalFont, list_wi); 1833#endif 1834#undef COPY_IT 1835} 1836 1837void 1838xtermSaveVTFonts(XtermWidget xw) 1839{ 1840 TScreen *screen = TScreenOf(xw); 1841 Cardinal n, m; 1842 1843 if (!screen->savedVTFonts) { 1844 1845 screen->savedVTFonts = True; 1846 TRACE(("xtermSaveVTFonts saving original\n")); 1847 COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc); 1848 COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work); 1849 COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 1850 } 1851} 1852 1853#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 1854#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 1855 1856static Boolean 1857sameSubResources(SubResourceRec * a, SubResourceRec * b) 1858{ 1859 Boolean result = True; 1860 1861 if (!SAME_MEMBER(default_font.f_n) 1862 || !SAME_MEMBER(default_font.f_b) 1863#if OPT_WIDE_CHARS 1864 || !SAME_MEMBER(default_font.f_w) 1865 || !SAME_MEMBER(default_font.f_wb) 1866#endif 1867 ) { 1868 TRACE(("sameSubResources: default_font differs\n")); 1869 result = False; 1870 } else { 1871 int n; 1872 1873 for (n = 0; n < NMENUFONTS; ++n) { 1874 if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 1875 TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 1876 result = False; 1877 break; 1878 } 1879 } 1880 } 1881 1882 return result; 1883} 1884 1885/* 1886 * Load the "VT" font names from the given subresource name/class. These 1887 * correspond to the VT100 resources. 1888 */ 1889static Bool 1890xtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 1891{ 1892 SubResourceRec subresourceRec; 1893 SubResourceRec referenceRec; 1894 1895 /* 1896 * These are duplicates of the VT100 font resources, but with a special 1897 * application/classname passed in to distinguish them. 1898 */ 1899 static XtResource font_resources[] = 1900 { 1901 Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 1902 Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 1903#if OPT_WIDE_CHARS 1904 Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 1905 Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 1906#endif 1907 Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 1908 Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 1909 Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 1910 Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 1911 Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 1912 Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 1913 }; 1914 Cardinal n, m; 1915 Bool status = True; 1916 TScreen *screen = TScreenOf(xw); 1917 1918 TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 1919 NonNull(myName), NonNull(myClass))); 1920 1921 xtermSaveVTFonts(xw); 1922 1923 if (IsEmpty(myName)) { 1924 TRACE(("xtermLoadVTFonts restoring original\n")); 1925 COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts); 1926 COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts); 1927 FREE_MENU_FONTS(xw->screen); 1928 COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 1929 } else { 1930 TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 1931 1932 memset(&referenceRec, 0, sizeof(referenceRec)); 1933 memset(&subresourceRec, 0, sizeof(subresourceRec)); 1934 XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 1935 myName, myClass, 1936 font_resources, 1937 (Cardinal) XtNumber(font_resources), 1938 NULL, (Cardinal) 0); 1939 1940 /* 1941 * XtGetSubresources returns no status, so we compare the returned 1942 * data against a zero'd struct to see if any data is returned. 1943 */ 1944 if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 1945 && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 1946 1947 screen->mergedVTFonts = True; 1948 1949 /* 1950 * To make it simple, reallocate the strings returned by 1951 * XtGetSubresources. We can free our own strings, but not theirs. 1952 */ 1953 ALLOC_STRING(subresourceRec.default_font.f_n); 1954 ALLOC_STRING(subresourceRec.default_font.f_b); 1955#if OPT_WIDE_CHARS 1956 ALLOC_STRING(subresourceRec.default_font.f_w); 1957 ALLOC_STRING(subresourceRec.default_font.f_wb); 1958#endif 1959 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 1960 ALLOC_STRING(subresourceRec.MenuFontName(n)); 1961 } 1962 1963 /* 1964 * Now, save the string to a font-list for consistency 1965 */ 1966#define ALLOC_SUBLIST(which,field) \ 1967 save2FontList(xw, "cached", \ 1968 &(subresourceRec.fonts), \ 1969 which, \ 1970 subresourceRec.default_font.field, False) 1971 1972 ALLOC_SUBLIST(fNorm, f_n); 1973 ALLOC_SUBLIST(fBold, f_b); 1974#if OPT_WIDE_CHARS 1975 ALLOC_SUBLIST(fWide, f_w); 1976 ALLOC_SUBLIST(fWBold, f_wb); 1977#endif 1978 1979 /* 1980 * If a particular resource value was not found, use the original. 1981 */ 1982 MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n); 1983 INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b); 1984 MERGE_SUBLIST(subresourceRec, xw->work, list_n); 1985 MERGE_SUBLIST(subresourceRec, xw->work, list_b); 1986#if OPT_WIDE_CHARS 1987 INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w); 1988 INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb); 1989 MERGE_SUBLIST(subresourceRec, xw->work, list_w); 1990 MERGE_SUBLIST(subresourceRec, xw->work, list_wb); 1991#endif 1992 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 1993 MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n)); 1994 } 1995 1996 /* 1997 * Finally, copy the subresource data to the widget. 1998 */ 1999 COPY_DEFAULT_FONTS(xw->misc, subresourceRec); 2000 COPY_X11_FONTLISTS(xw->work, subresourceRec); 2001 FREE_MENU_FONTS(xw->screen); 2002 COPY_MENU_FONTS(xw->screen, subresourceRec); 2003 2004 FREE_STRING(screen->MenuFontName(fontMenu_default)); 2005 FREE_STRING(screen->menu_font_names[0][fBold]); 2006 screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw)); 2007 screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw)); 2008#if OPT_WIDE_CHARS 2009 FREE_STRING(screen->menu_font_names[0][fWide]); 2010 FREE_STRING(screen->menu_font_names[0][fWBold]); 2011 screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw)); 2012 screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw)); 2013#endif 2014 /* 2015 * And remove our copies of strings. 2016 */ 2017 FREE_STRING(subresourceRec.default_font.f_n); 2018 FREE_STRING(subresourceRec.default_font.f_b); 2019#if OPT_WIDE_CHARS 2020 FREE_STRING(subresourceRec.default_font.f_w); 2021 FREE_STRING(subresourceRec.default_font.f_wb); 2022#endif 2023 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2024 FREE_STRING(subresourceRec.MenuFontName(n)); 2025 } 2026 } else { 2027 TRACE(("...no resources found\n")); 2028 status = False; 2029 } 2030 } 2031 TRACE((".. xtermLoadVTFonts: %d\n", status)); 2032 return status; 2033} 2034 2035#if OPT_WIDE_CHARS 2036static Bool 2037isWideFont(XFontStruct *fp, const char *tag, Bool nullOk) 2038{ 2039 Bool result = False; 2040 2041 (void) tag; 2042 if (okFont(fp)) { 2043 unsigned count = countGlyphs(fp); 2044 TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 2045 result = (count > 256) ? True : False; 2046 } else { 2047 result = nullOk; 2048 } 2049 return result; 2050} 2051 2052/* 2053 * If the current fonts are not wide, load the UTF8 fonts. 2054 * 2055 * Called during initialization (for wide-character mode), the fonts have not 2056 * been setup, so we pass nullOk=True to isWideFont(). 2057 * 2058 * Called after initialization, e.g., in response to the UTF-8 menu entry 2059 * (starting from narrow character mode), it checks if the fonts are not wide. 2060 */ 2061Bool 2062xtermLoadWideFonts(XtermWidget xw, Bool nullOk) 2063{ 2064 TScreen *screen = TScreenOf(xw); 2065 Bool result; 2066 2067 if (EmptyFont(getNormalFont(screen, fWide)->fs)) { 2068 result = (isWideFont(getNormalFont(screen, fNorm)->fs, "normal", nullOk) 2069 && isWideFont(getNormalFont(screen, fBold)->fs, "bold", nullOk)); 2070 } else { 2071 result = (isWideFont(getNormalFont(screen, fWide)->fs, "wide", nullOk) 2072 && isWideFont(getNormalFont(screen, fWBold)->fs, 2073 "wide-bold", nullOk)); 2074 if (result && !screen->utf8_latin1) { 2075 result = (isWideFont(getNormalFont(screen, fNorm)->fs, "normal", nullOk) 2076 && isWideFont(getNormalFont(screen, fBold)->fs, 2077 "bold", nullOk)); 2078 } 2079 } 2080 if (!result) { 2081 TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 2082 result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 2083 } 2084 TRACE(("xtermLoadWideFonts:%d\n", result)); 2085 return result; 2086} 2087#endif /* OPT_WIDE_CHARS */ 2088 2089/* 2090 * Restore the default fonts, i.e., if we had switched to wide-fonts. 2091 */ 2092Bool 2093xtermLoadDefaultFonts(XtermWidget xw) 2094{ 2095 Bool result; 2096 result = xtermLoadVTFonts(xw, NULL, NULL); 2097 TRACE(("xtermLoadDefaultFonts:%d\n", result)); 2098 return result; 2099} 2100#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 2101 2102#if OPT_LOAD_VTFONTS 2103void 2104HandleLoadVTFonts(Widget w, 2105 XEvent *event GCC_UNUSED, 2106 String *params GCC_UNUSED, 2107 Cardinal *param_count GCC_UNUSED) 2108{ 2109 XtermWidget xw; 2110 2111 if ((xw = getXtermWidget(w)) != 0) { 2112 static char empty[] = ""; /* appease strict compilers */ 2113 2114 TScreen *screen = TScreenOf(xw); 2115 char name_buf[80]; 2116 String name = (String) ((*param_count > 0) ? params[0] : empty); 2117 char *myName = MyStackAlloc(strlen(name) + 1, name_buf); 2118 2119 TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 2120 if (myName != 0) { 2121 char class_buf[80]; 2122 String convert = (String) ((*param_count > 1) ? params[1] : myName); 2123 char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf); 2124 2125 strcpy(myName, name); 2126 if (myClass != 0) { 2127 strcpy(myClass, convert); 2128 if (*param_count == 1) 2129 myClass[0] = x_toupper(myClass[0]); 2130 2131 if (xtermLoadVTFonts(xw, myName, myClass)) { 2132 int n; 2133 /* 2134 * When switching fonts, try to preserve the font-menu 2135 * selection, since it is less surprising to do that (if 2136 * the font-switching can be undone) than to switch to 2137 * "Default". 2138 */ 2139 int font_number = screen->menu_font_number; 2140 if (font_number > fontMenu_lastBuiltin) 2141 font_number = fontMenu_lastBuiltin; 2142 for (n = 0; n < NMENUFONTS; ++n) { 2143 screen->menu_font_sizes[n] = 0; 2144 } 2145 if (font_number == fontMenu_default) { 2146 SetVTFont(xw, font_number, True, defaultVTFontNames(xw)); 2147 } else { 2148 SetVTFont(xw, font_number, True, NULL); 2149 } 2150 } 2151 MyStackFree(myClass, class_buf); 2152 } 2153 MyStackFree(myName, name_buf); 2154 } 2155 } 2156} 2157#endif /* OPT_LOAD_VTFONTS */ 2158 2159/* 2160 * Set the limits for the box that outlines the cursor. 2161 */ 2162void 2163xtermSetCursorBox(TScreen *screen) 2164{ 2165 static XPoint VTbox[NBOX]; 2166 XPoint *vp; 2167 int fw = FontWidth(screen) - 1; 2168 int fh = FontHeight(screen) - 1; 2169 int ww = isCursorBar(screen) ? 1 : fw; 2170 int hh = isCursorUnderline(screen) ? 1 : fh; 2171 2172 vp = &VTbox[1]; 2173 (vp++)->x = (short) ww; 2174 (vp++)->y = (short) hh; 2175 (vp++)->x = (short) -ww; 2176 vp->y = (short) -hh; 2177 2178 screen->box = VTbox; 2179} 2180 2181#define CACHE_XFT(dst,src) if (src != 0) {\ 2182 checkXft(xw, &(dst[fontnum]), src);\ 2183 TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s\n",\ 2184 #dst,\ 2185 fontnum,\ 2186 src->height,\ 2187 src->ascent,\ 2188 src->descent,\ 2189 ((src->ascent + src->descent) > src->height ? "*" : ""),\ 2190 src->max_advance_width,\ 2191 dst[fontnum].map.min_width,\ 2192 dst[fontnum].map.mixed ? " mixed" : ""));\ 2193 } 2194 2195#if OPT_RENDERFONT 2196 2197#if OPT_REPORT_FONTS 2198static FcChar32 2199xtermXftFirstChar(XftFont *xft) 2200{ 2201 FcChar32 map[FC_CHARSET_MAP_SIZE]; 2202 FcChar32 next; 2203 FcChar32 first; 2204 int i; 2205 2206 first = FcCharSetFirstPage(xft->charset, map, &next); 2207 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { 2208 if (map[i]) { 2209 FcChar32 bits = map[i]; 2210 first += (FcChar32) i *32; 2211 while (!(bits & 0x1)) { 2212 bits >>= 1; 2213 first++; 2214 } 2215 break; 2216 } 2217 } 2218 return first; 2219} 2220 2221static FcChar32 2222xtermXftLastChar(XftFont *xft) 2223{ 2224 FcChar32 this, last, next; 2225 FcChar32 map[FC_CHARSET_MAP_SIZE]; 2226 int i; 2227 last = FcCharSetFirstPage(xft->charset, map, &next); 2228 while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 2229 last = this; 2230 last &= (FcChar32) ~ 0xff; 2231 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) { 2232 if (map[i]) { 2233 FcChar32 bits = map[i]; 2234 last += (FcChar32) i *32 + 31; 2235 while (!(bits & 0x80000000)) { 2236 last--; 2237 bits <<= 1; 2238 } 2239 break; 2240 } 2241 } 2242 return (FcChar32) last; 2243} 2244#endif /* OPT_REPORT_FONTS */ 2245 2246#if OPT_TRACE > 1 2247static void 2248dumpXft(XtermWidget xw, XTermXftFonts *data) 2249{ 2250 XftFont *xft = data->font; 2251 TScreen *screen = TScreenOf(xw); 2252 VTwin *win = WhichVWin(screen); 2253 2254 FcChar32 c; 2255 FcChar32 first = xtermXftFirstChar(xft); 2256 FcChar32 last = xtermXftLastChar(xft); 2257 unsigned count = 0; 2258 unsigned outside = 0; 2259 2260 TRACE(("dumpXft {{\n")); 2261 TRACE((" data range %#6x..%#6x\n", first, last)); 2262 for (c = first; c <= last; ++c) { 2263 if (FcCharSetHasChar(xft->charset, c)) { 2264 int width = my_wcwidth((int) c); 2265 XGlyphInfo extents; 2266 2267 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2268 TRACE(("%#6x %2d %.1f\n", c, width, 2269 ((double) extents.width) / win->f_width)); 2270 if (extents.width > win->f_width) 2271 ++outside; 2272 ++count; 2273 } 2274 } 2275 TRACE(("}} %u total, %u outside\n", count, outside)); 2276} 2277#define DUMP_XFT(xw, data) dumpXft(xw, data) 2278#else 2279#define DUMP_XFT(xw, data) /* nothing */ 2280#endif 2281 2282static void 2283checkXft(XtermWidget xw, XTermXftFonts *data, XftFont *xft) 2284{ 2285 FcChar32 c; 2286 Dimension width = 0; 2287 2288 data->font = xft; 2289 data->map.min_width = 0; 2290 data->map.max_width = (Dimension) xft->max_advance_width; 2291 2292 /* 2293 * For each ASCII or ISO-8859-1 printable code, ask what its width is. 2294 * Given the maximum width for those, we have a reasonable estimate of 2295 * the single-column width. 2296 * 2297 * Ignore control characters - their extent information is misleading. 2298 */ 2299 for (c = 32; c < 256; ++c) { 2300 if (c >= 127 && c <= 159) 2301 continue; 2302 if (FcCharSetHasChar(xft->charset, c)) { 2303 XGlyphInfo extents; 2304 2305 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2306 if (width < extents.width && extents.width <= data->map.max_width) { 2307 width = extents.width; 2308 } 2309 } 2310 } 2311 data->map.min_width = width; 2312 data->map.mixed = (data->map.max_width >= (data->map.min_width + 1)); 2313} 2314 2315#if OPT_REPORT_FONTS 2316static void 2317reportXftFonts(XtermWidget xw, 2318 XftFont *fp, 2319 const char *name, 2320 const char *tag, 2321 XftPattern *match) 2322{ 2323 if (resource.reportFonts) { 2324 char buffer[1024]; 2325 FcChar32 first_char = xtermXftFirstChar(fp); 2326 FcChar32 last_char = xtermXftLastChar(fp); 2327 FcChar32 ch; 2328 unsigned missing = 0; 2329 2330 printf("Loaded XftFonts(%s[%s])\n", name, tag); 2331 2332 for (ch = first_char; ch <= last_char; ++ch) { 2333 if (xtermXftMissing(xw, fp, ch)) { 2334 ++missing; 2335 } 2336 } 2337 printf("\t\tfirst char: %u\n", first_char); 2338 printf("\t\tlast char: %u\n", last_char); 2339 printf("\t\tmissing-chars: %u\n", missing); 2340 printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing); 2341 2342 if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 2343 char *target; 2344 char *source = buffer; 2345 while ((target = strtok(source, ":")) != 0) { 2346 printf("\t%s\n", target); 2347 source = 0; 2348 } 2349 } 2350 } 2351} 2352#else 2353#define reportXftFonts(xw, result, name, tag, match) /* empty */ 2354#endif /* OPT_REPORT_FONTS */ 2355 2356static XftFont * 2357xtermOpenXft(XtermWidget xw, const char *name, XftPattern *pat, const char *tag) 2358{ 2359 TScreen *screen = TScreenOf(xw); 2360 Display *dpy = screen->display; 2361 XftResult status; 2362 XftFont *result = 0; 2363 2364 if (pat != 0) { 2365 XftPattern *match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status); 2366 if (match != 0) { 2367 result = XftFontOpenPattern(dpy, match); 2368 if (result != 0) { 2369 TRACE(("...matched %s font\n", tag)); 2370 reportXftFonts(xw, result, name, tag, match); 2371 } else { 2372 TRACE(("...could did not open %s font\n", tag)); 2373 XftPatternDestroy(match); 2374 if (xw->misc.fontWarnings >= fwAlways) { 2375 TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name)); 2376 cannotFont(xw, "open", tag, name); 2377 } 2378 } 2379 } else { 2380 TRACE(("...did not match %s font\n", tag)); 2381 if (xw->misc.fontWarnings >= fwResource) { 2382 TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name)); 2383 cannotFont(xw, "match", tag, name); 2384 } 2385 } 2386 } 2387 return result; 2388} 2389#endif 2390 2391#if OPT_RENDERFONT 2392#if OPT_SHIFT_FONTS 2393/* 2394 * Don't make a dependency on the math library for a single function. 2395 * (Newton Raphson). 2396 */ 2397static double 2398dimSquareRoot(double value) 2399{ 2400 double result = 0.0; 2401 if (value > 0.0) { 2402 int n; 2403 double older = value; 2404 for (n = 0; n < 10; ++n) { 2405 double delta = (older * older - value) / (2.0 * older); 2406 double newer = older - delta; 2407 older = newer; 2408 result = newer; 2409 if (delta > -0.001 && delta < 0.001) 2410 break; 2411 } 2412 } 2413 return result; 2414} 2415#endif 2416 2417/* 2418 * Given the Xft font metrics, determine the actual font size. This is used 2419 * for each font to ensure that normal, bold and italic fonts follow the same 2420 * rule. 2421 */ 2422static void 2423setRenderFontsize(TScreen *screen, VTwin *win, XftFont *font, const char *tag) 2424{ 2425 if (font != 0) { 2426 int width, height, ascent, descent; 2427 2428 (void) screen; 2429 2430 width = font->max_advance_width; 2431 height = font->height; 2432 ascent = font->ascent; 2433 descent = font->descent; 2434 if (height < ascent + descent) { 2435 TRACE(("...increase height from %d\n", height)); 2436 height = ascent + descent; 2437 } 2438 if (is_double_width_font_xft(screen->display, font)) { 2439 TRACE(("...reduced width from %d\n", width)); 2440 width >>= 1; 2441 } 2442 if (tag == 0) { 2443 SetFontWidth(screen, win, width); 2444 SetFontHeight(screen, win, height); 2445 win->f_ascent = ascent; 2446 win->f_descent = descent; 2447 TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 2448 width, height, ascent, descent)); 2449 } else if (win->f_width < width || 2450 win->f_height < height || 2451 win->f_ascent < ascent || 2452 win->f_descent < descent) { 2453 TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 2454 tag, 2455 win->f_width, win->f_height, win->f_ascent, win->f_descent, 2456 width, height, ascent, descent)); 2457 2458 SetFontWidth(screen, win, width); 2459 SetFontHeight(screen, win, height); 2460 win->f_ascent = ascent; 2461 win->f_descent = descent; 2462 } else { 2463 TRACE(("setRenderFontsize %s unchanged\n", tag)); 2464 } 2465 } 2466} 2467#endif 2468 2469static void 2470checkFontInfo(int value, const char *tag) 2471{ 2472 if (value == 0) { 2473 xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 2474 exit(1); 2475 } 2476} 2477 2478#if OPT_RENDERFONT 2479void 2480xtermCloseXft(TScreen *screen, XTermXftFonts *pub) 2481{ 2482 if (pub->font != 0) { 2483 XftFontClose(screen->display, pub->font); 2484 pub->font = 0; 2485 } 2486} 2487 2488/* 2489 * Get the faceName/faceDoublesize resource setting. 2490 */ 2491String 2492getFaceName(XtermWidget xw, Bool wideName GCC_UNUSED) 2493{ 2494#if OPT_RENDERWIDE 2495 String result = (wideName 2496 ? FirstItemOf(xw->work.fonts.xft.list_w) 2497 : CurrentXftFont(xw)); 2498#else 2499 String result = CurrentXftFont(xw); 2500#endif 2501 return x_nonempty(result); 2502} 2503 2504/* 2505 * If we change the faceName, we'll have to re-acquire all of the fonts that 2506 * are derived from it. 2507 */ 2508void 2509setFaceName(XtermWidget xw, const char *value) 2510{ 2511 TScreen *screen = TScreenOf(xw); 2512 Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0) 2513 || strcmp(CurrentXftFont(xw), value)); 2514 2515 if (changed) { 2516 int n; 2517 2518 CurrentXftFont(xw) = x_strdup(value); 2519 for (n = 0; n < NMENUFONTS; ++n) { 2520 int e; 2521 xw->misc.face_size[n] = -1.0; 2522 for (e = 0; e < fMAX; ++e) { 2523 xtermCloseXft(screen, getMyXftFont(xw, e, n)); 2524 } 2525 } 2526 } 2527} 2528#endif 2529 2530/* 2531 * Compute useful values for the font/window sizes 2532 */ 2533void 2534xtermComputeFontInfo(XtermWidget xw, 2535 VTwin *win, 2536 XFontStruct *font, 2537 int sbwidth) 2538{ 2539 TScreen *screen = TScreenOf(xw); 2540 2541 int i, j, width, height; 2542#if OPT_RENDERFONT 2543 int fontnum = screen->menu_font_number; 2544#endif 2545 2546#if OPT_RENDERFONT 2547 /* 2548 * xterm contains a lot of references to fonts, assuming they are fixed 2549 * size. This chunk of code overrides the actual font-selection (see 2550 * drawXtermText()), if the user has selected render-font. All of the 2551 * font-loading for fixed-fonts still goes on whether or not this chunk 2552 * overrides it. 2553 */ 2554 if (UsingRenderFont(xw) && fontnum >= 0) { 2555 String face_name = getFaceName(xw, False); 2556 XftFont *norm = screen->renderFontNorm[fontnum].font; 2557 XftFont *bold = screen->renderFontBold[fontnum].font; 2558 XftFont *ital = screen->renderFontItal[fontnum].font; 2559#if OPT_RENDERWIDE 2560 XftFont *wnorm = screen->renderWideNorm[fontnum].font; 2561 XftFont *wbold = screen->renderWideBold[fontnum].font; 2562 XftFont *wital = screen->renderWideItal[fontnum].font; 2563#endif 2564 2565 if (norm == 0 && face_name) { 2566 XftPattern *pat; 2567 double face_size; 2568 2569 TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 2570 fontnum, face_name, 2571 xw->misc.face_size[fontnum])); 2572 2573 fillInFaceSize(xw, fontnum); 2574 face_size = xw->misc.face_size[fontnum]; 2575 2576 /* 2577 * By observation (there is no documentation), XftPatternBuild is 2578 * cumulative. Build the bold- and italic-patterns on top of the 2579 * normal pattern. 2580 */ 2581#define NormXftPattern \ 2582 XFT_FAMILY, XftTypeString, "mono", \ 2583 XFT_SIZE, XftTypeDouble, face_size 2584 2585#define BoldXftPattern(norm) \ 2586 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 2587 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 2588 2589#define ItalXftPattern(norm) \ 2590 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 2591 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 2592 2593#if OPT_WIDE_ATTRS 2594#define HAVE_ITALICS 1 2595#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0) 2596#elif OPT_ISO_COLORS 2597#define HAVE_ITALICS 1 2598#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0) 2599#else 2600#define HAVE_ITALICS 0 2601#endif 2602 2603 if ((pat = XftNameParse(face_name)) != 0) { 2604#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 2605 XftPatternBuild(pat, 2606 NormXftPattern, 2607 (void *) 0); 2608 norm = OPEN_XFT("normal"); 2609 2610 if (norm != 0) { 2611 XftPatternBuild(pat, 2612 BoldXftPattern(norm), 2613 (void *) 0); 2614 bold = OPEN_XFT("bold"); 2615 2616#if HAVE_ITALICS 2617 if (FIND_ITALICS) { 2618 XftPatternBuild(pat, 2619 NormXftPattern, 2620 ItalXftPattern(norm), 2621 (void *) 0); 2622 ital = OPEN_XFT("italic"); 2623 } 2624#endif 2625#undef OPEN_XFT 2626 2627 /* 2628 * FIXME: just assume that the corresponding font has no 2629 * graphics characters. 2630 */ 2631 if (screen->fnt_boxes) { 2632 screen->fnt_boxes = False; 2633 TRACE(("Xft opened - will %suse internal line-drawing characters\n", 2634 screen->fnt_boxes ? "not " : "")); 2635 } 2636 } 2637 2638 XftPatternDestroy(pat); 2639 } 2640 2641 CACHE_XFT(screen->renderFontNorm, norm); 2642 CACHE_XFT(screen->renderFontBold, bold); 2643 CACHE_XFT(screen->renderFontItal, ital); 2644 2645 /* 2646 * See xtermXftDrawString(). 2647 */ 2648#if OPT_RENDERWIDE 2649 if (norm != 0 && screen->wide_chars) { 2650 int char_width = norm->max_advance_width * 2; 2651#ifdef FC_ASPECT 2652 double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w) 2653 || screen->renderFontNorm[fontnum].map.mixed) 2654 ? 1.0 2655 : 2.0); 2656#endif 2657 2658 face_name = getFaceName(xw, True); 2659 TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 2660 NonNull(face_name), 2661 char_width)); 2662 2663#define WideXftPattern \ 2664 XFT_FAMILY, XftTypeString, "mono", \ 2665 XFT_SIZE, XftTypeDouble, face_size, \ 2666 XFT_SPACING, XftTypeInteger, XFT_MONO 2667 2668 if (face_name && (pat = XftNameParse(face_name)) != 0) { 2669#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 2670 XftPatternBuild(pat, 2671 WideXftPattern, 2672 XFT_CHAR_WIDTH, XftTypeInteger, char_width, 2673#ifdef FC_ASPECT 2674 FC_ASPECT, XftTypeDouble, aspect, 2675#endif 2676 (void *) 0); 2677 wnorm = OPEN_XFT("wide"); 2678 2679 if (wnorm != 0) { 2680 XftPatternBuild(pat, 2681 WideXftPattern, 2682 BoldXftPattern(wnorm), 2683 (void *) 0); 2684 wbold = OPEN_XFT("wide-bold"); 2685 2686#if HAVE_ITALICS 2687 if (FIND_ITALICS) { 2688 XftPatternBuild(pat, 2689 WideXftPattern, 2690 ItalXftPattern(wnorm), 2691 (void *) 0); 2692 wital = OPEN_XFT("wide-italic"); 2693 } 2694#endif 2695#undef OPEN_XFT 2696 } 2697 XftPatternDestroy(pat); 2698 } 2699 2700 CACHE_XFT(screen->renderWideNorm, wnorm); 2701 CACHE_XFT(screen->renderWideBold, wbold); 2702 CACHE_XFT(screen->renderWideItal, wital); 2703 } 2704#endif /* OPT_RENDERWIDE */ 2705 } 2706 if (norm == 0) { 2707 TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 2708 xw->work.render_font = False; 2709 update_font_renderfont(); 2710 /* now we will fall through into the bitmap fonts */ 2711 } else { 2712 setRenderFontsize(screen, win, norm, NULL); 2713 setRenderFontsize(screen, win, bold, "bold"); 2714 setRenderFontsize(screen, win, ital, "ital"); 2715#if OPT_BOX_CHARS 2716 setupPackedFonts(xw); 2717 2718 if (screen->force_packed) { 2719 XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 2720 SetFontHeight(screen, win, use->font->ascent + use->font->descent); 2721 SetFontWidth(screen, win, use->map.min_width); 2722 TRACE(("...packed TrueType font %dx%d vs %d\n", 2723 win->f_height, 2724 win->f_width, 2725 use->map.max_width)); 2726 } 2727#endif 2728 DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 2729 } 2730 } 2731 /* 2732 * Are we handling a bitmap font? 2733 */ 2734 else 2735#endif /* OPT_RENDERFONT */ 2736 { 2737 if (is_double_width_font(font) && !(screen->fnt_prop)) { 2738 SetFontWidth(screen, win, font->min_bounds.width); 2739 } else { 2740 SetFontWidth(screen, win, font->max_bounds.width); 2741 } 2742 SetFontHeight(screen, win, font->ascent + font->descent); 2743 win->f_ascent = font->ascent; 2744 win->f_descent = font->descent; 2745 } 2746 i = 2 * screen->border + sbwidth; 2747 j = 2 * screen->border; 2748 width = MaxCols(screen) * win->f_width + i; 2749 height = MaxRows(screen) * win->f_height + j; 2750 win->fullwidth = (Dimension) width; 2751 win->fullheight = (Dimension) height; 2752 win->width = width - i; 2753 win->height = height - j; 2754 2755 TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 2756 win->height, 2757 win->width, 2758 win->fullheight, 2759 win->fullwidth, 2760 win->f_height, 2761 win->f_width, 2762 win->f_ascent, 2763 win->f_descent)); 2764 2765 checkFontInfo(win->f_height, "height"); 2766 checkFontInfo(win->f_width, "width"); 2767} 2768 2769/* save this information as a side-effect for double-sized characters */ 2770void 2771xtermSaveFontInfo(TScreen *screen, XFontStruct *font) 2772{ 2773 screen->fnt_wide = (Dimension) (font->max_bounds.width); 2774 screen->fnt_high = (Dimension) (font->ascent + font->descent); 2775 TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 2776} 2777 2778/* 2779 * After loading a new font, update the structures that use its size. 2780 */ 2781void 2782xtermUpdateFontInfo(XtermWidget xw, Bool doresize) 2783{ 2784 TScreen *screen = TScreenOf(xw); 2785 2786 int scrollbar_width; 2787 VTwin *win = &(screen->fullVwin); 2788 2789 scrollbar_width = (xw->misc.scrollbar 2790 ? (screen->scrollWidget->core.width + 2791 BorderWidth(screen->scrollWidget)) 2792 : 0); 2793 xtermComputeFontInfo(xw, win, getNormalFont(screen, fNorm)->fs, scrollbar_width); 2794 xtermSaveFontInfo(screen, getNormalFont(screen, fNorm)->fs); 2795 2796 if (doresize) { 2797 if (VWindow(screen)) { 2798 xtermClear(xw); 2799 } 2800 TRACE(("xtermUpdateFontInfo {{\n")); 2801 DoResizeScreen(xw); /* set to the new natural size */ 2802 ResizeScrollBar(xw); 2803 Redraw(); 2804 TRACE(("... }} xtermUpdateFontInfo\n")); 2805#ifdef SCROLLBAR_RIGHT 2806 updateRightScrollbar(xw); 2807#endif 2808 } 2809 xtermSetCursorBox(screen); 2810} 2811 2812#if OPT_BOX_CHARS || OPT_REPORT_FONTS 2813 2814/* 2815 * Returns true if the given character is missing from the specified font. 2816 */ 2817Bool 2818xtermMissingChar(unsigned ch, XTermFonts * font) 2819{ 2820 Bool result = False; 2821 XFontStruct *fs = font->fs; 2822 XCharStruct *pc = 0; 2823 2824 if (fs->max_byte1 == 0) { 2825#if OPT_WIDE_CHARS 2826 if (ch < 256) 2827#endif 2828 { 2829 CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc); 2830 } 2831 } 2832#if OPT_WIDE_CHARS 2833 else { 2834 unsigned row = (ch >> 8); 2835 unsigned col = (ch & 0xff); 2836 CI_GET_CHAR_INFO_2D(fs, row, col, pc); 2837 } 2838#endif 2839 2840 if (pc == 0 || CI_NONEXISTCHAR(pc)) { 2841 TRACE2(("xtermMissingChar %#04x (!exists), %d cells\n", 2842 ch, my_wcwidth((wchar_t) ch))); 2843 result = True; 2844 } 2845 if (ch < KNOWN_MISSING) { 2846 font->known_missing[ch] = (Char) (result ? 2 : 1); 2847 } 2848 return result; 2849} 2850#endif 2851 2852#if OPT_BOX_CHARS 2853/* 2854 * The grid is arbitrary, enough resolution that nothing's lost in 2855 * initialization. 2856 */ 2857#define BOX_HIGH 60 2858#define BOX_WIDE 60 2859 2860#define MID_HIGH (BOX_HIGH/2) 2861#define MID_WIDE (BOX_WIDE/2) 2862 2863#define CHR_WIDE ((9*BOX_WIDE)/10) 2864#define CHR_HIGH ((9*BOX_HIGH)/10) 2865 2866/* 2867 * ...since we'll scale the values anyway. 2868 */ 2869#define SCALED_X(n) ((int)(n) * (((int) font_width) - 1)) / (BOX_WIDE-1) 2870#define SCALED_Y(n) ((int)(n) * (((int) font_height) - 1)) / (BOX_HIGH-1) 2871#define SCALE_X(n) n = SCALED_X(n) 2872#define SCALE_Y(n) n = SCALED_Y(n) 2873 2874#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 2875 2876/* 2877 * Draw the given graphic character, if it is simple enough (i.e., a 2878 * line-drawing character). 2879 */ 2880void 2881xtermDrawBoxChar(XtermWidget xw, 2882 unsigned ch, 2883 unsigned attr_flags, 2884 unsigned draw_flags, 2885 GC gc, 2886 int x, 2887 int y, 2888 int cells) 2889{ 2890 TScreen *screen = TScreenOf(xw); 2891 /* *INDENT-OFF* */ 2892 static const short glyph_ht[] = { 2893 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 2894 SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 2895 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 2896 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2897 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2898 -1 2899 }, glyph_ff[] = { 2900 SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 2901 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 2902 SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 2903 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2904 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2905 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2906 -1 2907 }, glyph_lf[] = { 2908 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 2909 SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 2910 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2911 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2912 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2913 -1 2914 }, glyph_nl[] = { 2915 SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 2916 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 2917 SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2918 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 2919 SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 2920 -1 2921 }, glyph_vt[] = { 2922 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 2923 SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2924 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2925 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2926 -1 2927 }, plus_or_minus[] = 2928 { 2929 SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 2930 SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 2931 SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 2932 -1 2933 }, lower_right_corner[] = 2934 { 2935 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2936 SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 2937 -1 2938 }, upper_right_corner[] = 2939 { 2940 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2941 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2942 -1 2943 }, upper_left_corner[] = 2944 { 2945 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2946 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2947 -1 2948 }, lower_left_corner[] = 2949 { 2950 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2951 SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 2952 -1 2953 }, cross[] = 2954 { 2955 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2956 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2957 -1 2958 }, scan_line_1[] = 2959 { 2960 SEG( 0, 0, BOX_WIDE, 0), 2961 -1 2962 }, scan_line_3[] = 2963 { 2964 SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 2965 -1 2966 }, scan_line_7[] = 2967 { 2968 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2969 -1 2970 }, scan_line_9[] = 2971 { 2972 SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 2973 -1 2974 }, horizontal_line[] = 2975 { 2976 SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 2977 -1 2978 }, left_tee[] = 2979 { 2980 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2981 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2982 -1 2983 }, right_tee[] = 2984 { 2985 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2986 SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 2987 -1 2988 }, bottom_tee[] = 2989 { 2990 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2991 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2992 -1 2993 }, top_tee[] = 2994 { 2995 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2996 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2997 -1 2998 }, vertical_line[] = 2999 { 3000 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 3001 -1 3002 }, less_than_or_equal[] = 3003 { 3004 SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 3005 SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 3006 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3007 -1 3008 }, greater_than_or_equal[] = 3009 { 3010 SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3011 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 3012 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 3013 -1 3014 }, greek_pi[] = 3015 { 3016 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3017 SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 3018 SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 3019 -1 3020 }, not_equal_to[] = 3021 { 3022 SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 3023 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 3024 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 3025 -1 3026 }; 3027 /* *INDENT-ON* */ 3028 3029 static const short *lines[] = 3030 { 3031 0, /* 00 (unused) */ 3032 0, /* 01 diamond */ 3033 0, /* 02 box */ 3034 glyph_ht, /* 03 HT */ 3035 glyph_ff, /* 04 FF */ 3036 0, /* 05 CR */ 3037 glyph_lf, /* 06 LF */ 3038 0, /* 07 degrees (small circle) */ 3039 plus_or_minus, /* 08 */ 3040 glyph_nl, /* 09 */ 3041 glyph_vt, /* 0A */ 3042 lower_right_corner, /* 0B */ 3043 upper_right_corner, /* 0C */ 3044 upper_left_corner, /* 0D */ 3045 lower_left_corner, /* 0E */ 3046 cross, /* 0F */ 3047 scan_line_1, /* 10 */ 3048 scan_line_3, /* 11 */ 3049 scan_line_7, /* 12 */ 3050 scan_line_9, /* 13 */ 3051 horizontal_line, /* 14 */ 3052 left_tee, /* 15 */ 3053 right_tee, /* 16 */ 3054 bottom_tee, /* 17 */ 3055 top_tee, /* 18 */ 3056 vertical_line, /* 19 */ 3057 less_than_or_equal, /* 1A */ 3058 greater_than_or_equal, /* 1B */ 3059 greek_pi, /* 1C */ 3060 not_equal_to, /* 1D */ 3061 0, /* 1E LB */ 3062 0, /* 1F bullet */ 3063 }; 3064 3065 GC gc2; 3066 CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 3067 VTwin *cgsWin = WhichVWin(screen); 3068 const short *p; 3069 unsigned font_width = (unsigned) (((draw_flags & DOUBLEWFONT) ? 2 : 1) 3070 * screen->fnt_wide); 3071 unsigned font_height = (unsigned) (((draw_flags & DOUBLEHFONT) ? 2 : 1) 3072 * screen->fnt_high); 3073 3074 if (cells > 1) 3075 font_width *= (unsigned) cells; 3076 3077#if OPT_WIDE_CHARS 3078 /* 3079 * Try to show line-drawing characters if we happen to be in UTF-8 3080 * mode, but have gotten an old-style font. 3081 */ 3082 if (screen->utf8_mode 3083#if OPT_RENDERFONT 3084 && !UsingRenderFont(xw) 3085#endif 3086 && (ch > 127) 3087 && (ch != UCS_REPL)) { 3088 unsigned n; 3089 for (n = 1; n < 32; n++) { 3090 if (dec2ucs(n) == ch 3091 && !((attr_flags & BOLD) 3092 ? IsXtermMissingChar(screen, n, getNormalFont(screen, fBold)) 3093 : IsXtermMissingChar(screen, n, getNormalFont(screen, fNorm)))) { 3094 TRACE(("...use xterm-style linedrawing\n")); 3095 ch = n; 3096 break; 3097 } 3098 } 3099 } 3100#endif 3101 3102 TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n", 3103 ch, font_height, font_width, y, x, 3104 (ch >= (sizeof(lines) / sizeof(lines[0])) 3105 ? "-BAD" 3106 : ""))); 3107 3108 if (cgsId == gcDots) { 3109 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 3110 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 3111 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 3112 } else { 3113 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 3114 setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 3115 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 3116 } 3117 gc2 = getCgsGC(xw, cgsWin, cgsId); 3118 3119 if (!(draw_flags & NOBACKGROUND)) { 3120 XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 3121 font_width, 3122 font_height); 3123 } 3124 3125 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 3126 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 3127 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 3128 gc2 = getCgsGC(xw, cgsWin, cgsId); 3129 3130 XSetLineAttributes(screen->display, gc2, 3131 (attr_flags & BOLD) 3132 ? ((font_height > 12) 3133 ? font_height / 12 3134 : 1) 3135 : ((font_height > 16) 3136 ? font_height / 16 3137 : 1), 3138 LineSolid, 3139 CapProjecting, 3140 JoinMiter); 3141 3142 if (ch == 1) { /* diamond */ 3143 XPoint points[5]; 3144 int npoints = 5, n; 3145 3146 points[0].x = MID_WIDE; 3147 points[0].y = BOX_HIGH / 4; 3148 3149 points[1].x = 8 * BOX_WIDE / 8; 3150 points[1].y = MID_HIGH; 3151 3152 points[2].x = points[0].x; 3153 points[2].y = 3 * BOX_HIGH / 4; 3154 3155 points[3].x = 0 * BOX_WIDE / 8; 3156 points[3].y = points[1].y; 3157 3158 points[4].x = points[0].x; 3159 points[4].y = points[0].y; 3160 3161 for (n = 0; n < npoints; ++n) { 3162 points[n].x = (short) SCALED_X(points[n].x); 3163 points[n].y = (short) SCALED_Y(points[n].y); 3164 points[n].x = (short) (points[n].x + x); 3165 points[n].y = (short) (points[n].y + y); 3166 } 3167 3168 XFillPolygon(screen->display, 3169 VDrawable(screen), gc2, 3170 points, npoints, 3171 Convex, CoordModeOrigin); 3172 } else if (ch == 7) { /* degrees */ 3173 unsigned width = (BOX_WIDE / 3); 3174 int x_coord = MID_WIDE - (int) (width / 2); 3175 int y_coord = MID_HIGH - (int) width; 3176 3177 SCALE_X(x_coord); 3178 SCALE_Y(y_coord); 3179 width = (unsigned) SCALED_X(width); 3180 3181 XDrawArc(screen->display, 3182 VDrawable(screen), gc2, 3183 x + x_coord, y + y_coord, width, width, 3184 0, 3185 360 * 64); 3186 } else if (ch == 0x1f) { /* bullet */ 3187 unsigned width = 7 * BOX_WIDE / 10; 3188 int x_coord = MID_WIDE - (int) (width / 3); 3189 int y_coord = MID_HIGH - (int) (width / 3); 3190 3191 SCALE_X(x_coord); 3192 SCALE_Y(y_coord); 3193 width = (unsigned) SCALED_X(width); 3194 3195 XDrawArc(screen->display, 3196 VDrawable(screen), gc2, 3197 x + x_coord, y + y_coord, width, width, 3198 0, 3199 360 * 64); 3200 } else if (ch < (sizeof(lines) / sizeof(lines[0])) 3201 && (p = lines[ch]) != 0) { 3202 int coord[4]; 3203 int n = 0; 3204 while (*p >= 0) { 3205 coord[n++] = *p++; 3206 if (n == 4) { 3207 SCALE_X(coord[0]); 3208 SCALE_Y(coord[1]); 3209 SCALE_X(coord[2]); 3210 SCALE_Y(coord[3]); 3211 XDrawLine(screen->display, 3212 VDrawable(screen), gc2, 3213 x + coord[0], y + coord[1], 3214 x + coord[2], y + coord[3]); 3215 n = 0; 3216 } 3217 } 3218 } else if (screen->force_all_chars) { 3219 /* bounding rectangle, for debugging */ 3220 XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y, 3221 font_width - 1, 3222 font_height - 1); 3223 } 3224} 3225#endif /* OPT_BOX_CHARS */ 3226 3227#if OPT_RENDERFONT 3228 3229/* 3230 * Check if the given character has a glyph known to Xft. 3231 * 3232 * see xc/lib/Xft/xftglyphs.c 3233 */ 3234Bool 3235xtermXftMissing(XtermWidget xw, XftFont *font, unsigned wc) 3236{ 3237 Bool result = False; 3238 3239 if (font != 0) { 3240 TScreen *screen = TScreenOf(xw); 3241 if (!XftGlyphExists(screen->display, font, wc)) { 3242#if OPT_WIDE_CHARS 3243 TRACE2(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 3244 wc, ucs2dec(wc), dec2ucs(wc))); 3245#else 3246 TRACE2(("xtermXftMissing %d\n", wc)); 3247#endif 3248 result = True; 3249 } 3250 } 3251 return result; 3252} 3253#endif /* OPT_RENDERFONT */ 3254 3255#if OPT_WIDE_CHARS 3256#define MY_UCS(ucs,dec) case ucs: result = dec; break 3257unsigned 3258ucs2dec(unsigned ch) 3259{ 3260 unsigned result = ch; 3261 if ((ch > 127) 3262 && (ch != UCS_REPL)) { 3263 switch (ch) { 3264 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 3265 MY_UCS(0x25c6, 1); /* black diamond */ 3266 MY_UCS(0x2592, 2); /* medium shade */ 3267 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 3268 MY_UCS(0x240c, 4); /* symbol for form feed */ 3269 MY_UCS(0x240d, 5); /* symbol for carriage return */ 3270 MY_UCS(0x240a, 6); /* symbol for line feed */ 3271 MY_UCS(0x00b0, 7); /* degree sign */ 3272 MY_UCS(0x00b1, 8); /* plus-minus sign */ 3273 MY_UCS(0x2424, 9); /* symbol for newline */ 3274 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 3275 MY_UCS(0x2518, 11); /* box drawings light up and left */ 3276 MY_UCS(0x2510, 12); /* box drawings light down and left */ 3277 MY_UCS(0x250c, 13); /* box drawings light down and right */ 3278 MY_UCS(0x2514, 14); /* box drawings light up and right */ 3279 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 3280 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 3281 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 3282 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 3283 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 3284 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 3285 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 3286 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 3287 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 3288 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 3289 MY_UCS(0x2502, 25); /* box drawings light vertical */ 3290 MY_UCS(0x2264, 26); /* less-than or equal to */ 3291 MY_UCS(0x2265, 27); /* greater-than or equal to */ 3292 MY_UCS(0x03c0, 28); /* greek small letter pi */ 3293 MY_UCS(0x2260, 29); /* not equal to */ 3294 MY_UCS(0x00a3, 30); /* pound sign */ 3295 MY_UCS(0x00b7, 31); /* middle dot */ 3296 } 3297 } 3298 return result; 3299} 3300 3301#undef MY_UCS 3302#define MY_UCS(ucs,dec) case dec: result = ucs; break 3303 3304unsigned 3305dec2ucs(unsigned ch) 3306{ 3307 unsigned result = ch; 3308 if (xtermIsDecGraphic(ch)) { 3309 switch (ch) { 3310 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 3311 MY_UCS(0x25c6, 1); /* black diamond */ 3312 MY_UCS(0x2592, 2); /* medium shade */ 3313 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 3314 MY_UCS(0x240c, 4); /* symbol for form feed */ 3315 MY_UCS(0x240d, 5); /* symbol for carriage return */ 3316 MY_UCS(0x240a, 6); /* symbol for line feed */ 3317 MY_UCS(0x00b0, 7); /* degree sign */ 3318 MY_UCS(0x00b1, 8); /* plus-minus sign */ 3319 MY_UCS(0x2424, 9); /* symbol for newline */ 3320 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 3321 MY_UCS(0x2518, 11); /* box drawings light up and left */ 3322 MY_UCS(0x2510, 12); /* box drawings light down and left */ 3323 MY_UCS(0x250c, 13); /* box drawings light down and right */ 3324 MY_UCS(0x2514, 14); /* box drawings light up and right */ 3325 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 3326 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 3327 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 3328 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 3329 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 3330 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 3331 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 3332 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 3333 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 3334 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 3335 MY_UCS(0x2502, 25); /* box drawings light vertical */ 3336 MY_UCS(0x2264, 26); /* less-than or equal to */ 3337 MY_UCS(0x2265, 27); /* greater-than or equal to */ 3338 MY_UCS(0x03c0, 28); /* greek small letter pi */ 3339 MY_UCS(0x2260, 29); /* not equal to */ 3340 MY_UCS(0x00a3, 30); /* pound sign */ 3341 MY_UCS(0x00b7, 31); /* middle dot */ 3342 } 3343 } 3344 return result; 3345} 3346 3347#endif /* OPT_WIDE_CHARS */ 3348 3349#if OPT_RENDERFONT || OPT_SHIFT_FONTS 3350static int 3351lookupOneFontSize(XtermWidget xw, int fontnum) 3352{ 3353 TScreen *screen = TScreenOf(xw); 3354 3355 if (screen->menu_font_sizes[fontnum] == 0) { 3356 XTermFonts fnt; 3357 3358 memset(&fnt, 0, sizeof(fnt)); 3359 screen->menu_font_sizes[fontnum] = -1; 3360 if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, True)) { 3361 if (fontnum <= fontMenu_lastBuiltin 3362 || strcmp(fnt.fn, DEFFONT)) { 3363 screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 3364 if (screen->menu_font_sizes[fontnum] <= 0) 3365 screen->menu_font_sizes[fontnum] = -1; 3366 } 3367 xtermCloseFont(xw, &fnt); 3368 } 3369 } 3370 return (screen->menu_font_sizes[fontnum] > 0); 3371} 3372 3373/* 3374 * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 3375 */ 3376static void 3377lookupFontSizes(XtermWidget xw) 3378{ 3379 int n; 3380 3381 for (n = 0; n < NMENUFONTS; n++) { 3382 (void) lookupOneFontSize(xw, n); 3383 } 3384} 3385#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 3386 3387#if OPT_RENDERFONT 3388static double 3389defaultFaceSize(void) 3390{ 3391 double result; 3392 float value; 3393 3394 if (sscanf(DEFFACESIZE, "%f", &value) == 1) 3395 result = value; 3396 else 3397 result = 14.0; 3398 return result; 3399} 3400 3401static void 3402fillInFaceSize(XtermWidget xw, int fontnum) 3403{ 3404 TScreen *screen = TScreenOf(xw); 3405 double face_size = xw->misc.face_size[fontnum]; 3406 3407 if (face_size <= 0.0) { 3408#if OPT_SHIFT_FONTS 3409 /* 3410 * If the user is switching font-sizes, make it follow by 3411 * default the same ratios to the default as the fixed fonts 3412 * would, for easy comparison. There will be some differences 3413 * since the fixed fonts have a variety of height/width ratios, 3414 * but this is simpler than adding another resource value - and 3415 * as noted above, the data for the fixed fonts are available. 3416 */ 3417 (void) lookupOneFontSize(xw, 0); 3418 if (fontnum == fontMenu_default) { 3419 face_size = defaultFaceSize(); 3420 } else if (lookupOneFontSize(xw, fontnum) 3421 && (screen->menu_font_sizes[0] 3422 != screen->menu_font_sizes[fontnum])) { 3423 double ratio; 3424 long num = screen->menu_font_sizes[fontnum]; 3425 long den = screen->menu_font_sizes[0]; 3426 3427 if (den <= 0) 3428 den = 1; 3429 ratio = dimSquareRoot((double) num / (double) den); 3430 3431 face_size = (ratio * xw->misc.face_size[0]); 3432 TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 3433 fontnum, num, den, ratio, face_size)); 3434 } else 3435#endif 3436 { 3437#define LikeBitmap(s) (((s) / 78.0) * xw->misc.face_size[fontMenu_default]) 3438 switch (fontnum) { 3439 case fontMenu_font1: 3440 face_size = LikeBitmap(2.0); 3441 break; 3442 case fontMenu_font2: 3443 face_size = LikeBitmap(35.0); 3444 break; 3445 case fontMenu_font3: 3446 face_size = LikeBitmap(60.0); 3447 break; 3448 default: 3449 face_size = defaultFaceSize(); 3450 break; 3451 case fontMenu_font4: 3452 face_size = LikeBitmap(90.0); 3453 break; 3454 case fontMenu_font5: 3455 face_size = LikeBitmap(135.0); 3456 break; 3457 case fontMenu_font6: 3458 face_size = LikeBitmap(200.0); 3459 break; 3460 } 3461 TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 3462 } 3463 xw->misc.face_size[fontnum] = (float) face_size; 3464 } 3465} 3466 3467/* no selection or escape */ 3468#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 3469 3470/* 3471 * Workaround for breakage in font-packages - check if all of the bitmap font 3472 * sizes are the same, and if we're using TrueType fonts. 3473 */ 3474static Boolean 3475useFaceSizes(XtermWidget xw) 3476{ 3477 Boolean result = False; 3478 3479 TRACE(("useFaceSizes {{\n")); 3480 if (UsingRenderFont(xw)) { 3481 Boolean nonzero = True; 3482 int n; 3483 3484 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 3485 if (xw->misc.face_size[n] <= 0.0) { 3486 nonzero = False; 3487 break; 3488 } 3489 } 3490 if (!nonzero) { 3491 Boolean broken_fonts = True; 3492 TScreen *screen = TScreenOf(xw); 3493 long first; 3494 3495 lookupFontSizes(xw); 3496 first = screen->menu_font_sizes[0]; 3497 for (n = 0; n < NMENUFONTS; n++) { 3498 if (screen->menu_font_sizes[n] > 0 3499 && screen->menu_font_sizes[n] != first) { 3500 broken_fonts = False; 3501 break; 3502 } 3503 } 3504 3505 if (broken_fonts) { 3506 3507 TRACE(("bitmap fonts are broken - set faceSize resources\n")); 3508 for (n = 0; n < NMENUFONTS; n++) { 3509 fillInFaceSize(xw, n); 3510 } 3511 3512 } 3513 } 3514 result = True; 3515 } 3516 TRACE(("...}}useFaceSizes %d\n", result)); 3517 return result; 3518} 3519#endif /* OPT_RENDERFONT */ 3520 3521#if OPT_SHIFT_FONTS 3522/* 3523 * Find the index of a larger/smaller font (according to the sign of 'relative' 3524 * and its magnitude), starting from the 'old' index. 3525 */ 3526int 3527lookupRelativeFontSize(XtermWidget xw, int old, int relative) 3528{ 3529 TScreen *screen = TScreenOf(xw); 3530 int m = -1; 3531 3532 TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 3533 if (!IsIcon(screen)) { 3534#if OPT_RENDERFONT 3535 if (useFaceSizes(xw)) { 3536 TRACE(("...using FaceSize\n")); 3537 if (relative != 0) { 3538 int n; 3539 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 3540 fillInFaceSize(xw, n); 3541 if (xw->misc.face_size[n] > 0 && 3542 xw->misc.face_size[n] != xw->misc.face_size[old]) { 3543 int cmp_0 = ((xw->misc.face_size[n] > 3544 xw->misc.face_size[old]) 3545 ? relative 3546 : -relative); 3547 int cmp_m = ((m < 0) 3548 ? 1 3549 : ((xw->misc.face_size[n] < 3550 xw->misc.face_size[m]) 3551 ? relative 3552 : -relative)); 3553 if (cmp_0 > 0 && cmp_m > 0) { 3554 m = n; 3555 } 3556 } 3557 } 3558 } 3559 } else 3560#endif 3561 { 3562 TRACE(("...using bitmap areas\n")); 3563 lookupFontSizes(xw); 3564 if (relative != 0) { 3565 int n; 3566 for (n = 0; n < NMENUFONTS; ++n) { 3567 if (screen->menu_font_sizes[n] > 0 && 3568 screen->menu_font_sizes[n] != 3569 screen->menu_font_sizes[old]) { 3570 int cmp_0 = ((screen->menu_font_sizes[n] > 3571 screen->menu_font_sizes[old]) 3572 ? relative 3573 : -relative); 3574 int cmp_m = ((m < 0) 3575 ? 1 3576 : ((screen->menu_font_sizes[n] < 3577 screen->menu_font_sizes[m]) 3578 ? relative 3579 : -relative)); 3580 if (cmp_0 > 0 && cmp_m > 0) { 3581 m = n; 3582 } 3583 } 3584 } 3585 } 3586 } 3587 TRACE(("...new index %d\n", m)); 3588 if (m >= 0) { 3589 if (relative > 1) 3590 m = lookupRelativeFontSize(xw, m, relative - 1); 3591 else if (relative < -1) 3592 m = lookupRelativeFontSize(xw, m, relative + 1); 3593 } 3594 } 3595 return m; 3596} 3597 3598/* ARGSUSED */ 3599void 3600HandleLargerFont(Widget w GCC_UNUSED, 3601 XEvent *event GCC_UNUSED, 3602 String *params GCC_UNUSED, 3603 Cardinal *param_count GCC_UNUSED) 3604{ 3605 XtermWidget xw; 3606 3607 TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 3608 if ((xw = getXtermWidget(w)) != 0) { 3609 if (xw->misc.shift_fonts) { 3610 TScreen *screen = TScreenOf(xw); 3611 int m; 3612 3613 m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 3614 if (m >= 0) { 3615 SetVTFont(xw, m, True, NULL); 3616 } else { 3617 Bell(xw, XkbBI_MinorError, 0); 3618 } 3619 } 3620 } 3621} 3622 3623/* ARGSUSED */ 3624void 3625HandleSmallerFont(Widget w GCC_UNUSED, 3626 XEvent *event GCC_UNUSED, 3627 String *params GCC_UNUSED, 3628 Cardinal *param_count GCC_UNUSED) 3629{ 3630 XtermWidget xw; 3631 3632 TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 3633 if ((xw = getXtermWidget(w)) != 0) { 3634 if (xw->misc.shift_fonts) { 3635 TScreen *screen = TScreenOf(xw); 3636 int m; 3637 3638 m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 3639 if (m >= 0) { 3640 SetVTFont(xw, m, True, NULL); 3641 } else { 3642 Bell(xw, XkbBI_MinorError, 0); 3643 } 3644 } 3645 } 3646} 3647#endif /* OPT_SHIFT_FONTS */ 3648 3649int 3650xtermGetFont(const char *param) 3651{ 3652 int fontnum; 3653 3654 switch (param[0]) { 3655 case 'd': 3656 case 'D': 3657 case '0': 3658 fontnum = fontMenu_default; 3659 break; 3660 case '1': 3661 fontnum = fontMenu_font1; 3662 break; 3663 case '2': 3664 fontnum = fontMenu_font2; 3665 break; 3666 case '3': 3667 fontnum = fontMenu_font3; 3668 break; 3669 case '4': 3670 fontnum = fontMenu_font4; 3671 break; 3672 case '5': 3673 fontnum = fontMenu_font5; 3674 break; 3675 case '6': 3676 fontnum = fontMenu_font6; 3677 break; 3678 case 'e': 3679 case 'E': 3680 fontnum = fontMenu_fontescape; 3681 break; 3682 case 's': 3683 case 'S': 3684 fontnum = fontMenu_fontsel; 3685 break; 3686 default: 3687 fontnum = -1; 3688 break; 3689 } 3690 return fontnum; 3691} 3692 3693/* ARGSUSED */ 3694void 3695HandleSetFont(Widget w GCC_UNUSED, 3696 XEvent *event GCC_UNUSED, 3697 String *params, 3698 Cardinal *param_count) 3699{ 3700 XtermWidget xw; 3701 3702 if ((xw = getXtermWidget(w)) != 0) { 3703 int fontnum; 3704 VTFontNames fonts; 3705 3706 memset(&fonts, 0, sizeof(fonts)); 3707 3708 if (*param_count == 0) { 3709 fontnum = fontMenu_default; 3710 } else { 3711 Cardinal maxparams = 1; /* total number of params allowed */ 3712 int result = xtermGetFont(params[0]); 3713 3714 switch (result) { 3715 case fontMenu_default: /* FALLTHRU */ 3716 case fontMenu_font1: /* FALLTHRU */ 3717 case fontMenu_font2: /* FALLTHRU */ 3718 case fontMenu_font3: /* FALLTHRU */ 3719 case fontMenu_font4: /* FALLTHRU */ 3720 case fontMenu_font5: /* FALLTHRU */ 3721 case fontMenu_font6: /* FALLTHRU */ 3722 break; 3723 case fontMenu_fontescape: 3724#if OPT_WIDE_CHARS 3725 maxparams = 5; 3726#else 3727 maxparams = 3; 3728#endif 3729 break; 3730 case fontMenu_fontsel: 3731 maxparams = 2; 3732 break; 3733 default: 3734 Bell(xw, XkbBI_MinorError, 0); 3735 return; 3736 } 3737 fontnum = result; 3738 3739 if (*param_count > maxparams) { /* see if extra args given */ 3740 Bell(xw, XkbBI_MinorError, 0); 3741 return; 3742 } 3743 switch (*param_count) { /* assign 'em */ 3744#if OPT_WIDE_CHARS 3745 case 5: 3746 fonts.f_wb = x_strdup(params[4]); 3747 /* FALLTHRU */ 3748 case 4: 3749 fonts.f_w = x_strdup(params[3]); 3750#endif 3751 /* FALLTHRU */ 3752 case 3: 3753 fonts.f_b = x_strdup(params[2]); 3754 /* FALLTHRU */ 3755 case 2: 3756 fonts.f_n = x_strdup(params[1]); 3757 break; 3758 } 3759 } 3760 3761 SetVTFont(xw, fontnum, True, &fonts); 3762 } 3763} 3764 3765void 3766SetVTFont(XtermWidget xw, 3767 int which, 3768 Bool doresize, 3769 const VTFontNames * fonts) 3770{ 3771 TScreen *screen = TScreenOf(xw); 3772 3773 TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 3774 (fonts && fonts->f_n) ? fonts->f_n : "<null>", 3775 (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 3776 3777 if (IsIcon(screen)) { 3778 Bell(xw, XkbBI_MinorError, 0); 3779 } else if (which >= 0 && which < NMENUFONTS) { 3780 VTFontNames myfonts; 3781 3782 memset(&myfonts, 0, sizeof(myfonts)); 3783 if (fonts != 0) 3784 myfonts = *fonts; 3785 3786 if (which == fontMenu_fontsel) { /* go get the selection */ 3787 FindFontSelection(xw, myfonts.f_n, False); 3788 } else { 3789 int oldFont = screen->menu_font_number; 3790 3791#define USE_CACHED(field, name) \ 3792 if (myfonts.field == 0) { \ 3793 myfonts.field = x_strdup(screen->menu_font_names[which][name]); \ 3794 TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 3795 which, NonNull(myfonts.field))); \ 3796 } else { \ 3797 TRACE(("set myfonts." #field " reused\n")); \ 3798 } 3799#define SAVE_FNAME(field, name) \ 3800 if (myfonts.field != 0) { \ 3801 if (screen->menu_font_names[which][name] == 0 \ 3802 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \ 3803 TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \ 3804 which, myfonts.field)); \ 3805 FREE_STRING(screen->menu_font_names[which][name]); \ 3806 screen->menu_font_names[which][name] = x_strdup(myfonts.field); \ 3807 } \ 3808 } 3809 3810 USE_CACHED(f_n, fNorm); 3811 USE_CACHED(f_b, fBold); 3812#if OPT_WIDE_CHARS 3813 USE_CACHED(f_w, fWide); 3814 USE_CACHED(f_wb, fWBold); 3815#endif 3816 if (xtermLoadFont(xw, 3817 &myfonts, 3818 doresize, which)) { 3819 /* 3820 * If successful, save the data so that a subsequent query via 3821 * OSC-50 will return the expected values. 3822 */ 3823 SAVE_FNAME(f_n, fNorm); 3824 SAVE_FNAME(f_b, fBold); 3825#if OPT_WIDE_CHARS 3826 SAVE_FNAME(f_w, fWide); 3827 SAVE_FNAME(f_wb, fWBold); 3828#endif 3829 } else { 3830 (void) xtermLoadFont(xw, 3831 xtermFontName(screen->MenuFontName(oldFont)), 3832 doresize, oldFont); 3833 Bell(xw, XkbBI_MinorError, 0); 3834 } 3835 FREE_FNAME(f_n); 3836 FREE_FNAME(f_b); 3837#if OPT_WIDE_CHARS 3838 FREE_FNAME(f_w); 3839 FREE_FNAME(f_wb); 3840#endif 3841 } 3842 } else { 3843 Bell(xw, XkbBI_MinorError, 0); 3844 } 3845 return; 3846} 3847 3848#if OPT_RENDERFONT 3849static void 3850trimSizeFromFace(char *face_name, float *face_size) 3851{ 3852 char *first = strstr(face_name, ":size="); 3853 if (first == 0) { 3854 first = face_name; 3855 } else { 3856 first++; 3857 } 3858 if (!strncmp(first, "size=", (size_t) 5)) { 3859 char *last = strchr(first, ':'); 3860 char mark; 3861 float value; 3862 char extra; 3863 TRACE(("...before trimming, font = \"%s\"\n", face_name)); 3864 if (last == 0) 3865 last = first + strlen(first); 3866 mark = *last; 3867 *last = '\0'; 3868 if (sscanf(first, "size=%g%c", &value, &extra) == 1) { 3869 TRACE(("...trimmed size from font: %g\n", value)); 3870 if (face_size != 0) 3871 *face_size = value; 3872 } 3873 if (mark) { 3874 while ((*first++ = *++last) != '\0') { 3875 ; 3876 } 3877 } else { 3878 if (first != face_name) 3879 --first; 3880 *first = '\0'; 3881 } 3882 TRACE(("...after trimming, font = \"%s\"\n", face_name)); 3883 } 3884} 3885#endif 3886 3887/* 3888 * Save a font specification to the proper list. 3889 */ 3890static void 3891save2FontList(XtermWidget xw, 3892 const char *name, 3893 XtermFontNames * fontnames, 3894 VTFontEnum which, 3895 const char *source, 3896 Bool ttf) 3897{ 3898 char *value; 3899 size_t plen; 3900 Bool marked = False; 3901 Bool use_ttf = ttf; 3902 3903 (void) xw; 3904 3905 if (source == 0) 3906 source = ""; 3907 while (isspace(CharOf(*source))) 3908 ++source; 3909 3910 /* fontconfig patterns can contain ':' separators, but we'll treat 3911 * a leading prefix specially to denote whether the pattern might be 3912 * XLFD ("x" or "xlfd") versus Xft ("xft"). 3913 */ 3914 for (plen = 0; source[plen] != '\0'; ++plen) { 3915 if (source[plen] == ':') { 3916 marked = True; 3917 switch (plen) { 3918 case 0: 3919 ++plen; /* trim leading ':' */ 3920 break; 3921 case 1: 3922 if (!strncmp(source, "x", plen)) { 3923 ++plen; 3924 use_ttf = False; 3925 } else { 3926 marked = False; 3927 } 3928 break; 3929 case 3: 3930 if (!strncmp(source, "xft", plen)) { 3931 ++plen; 3932 use_ttf = True; 3933 } else { 3934 marked = False; 3935 } 3936 break; 3937 case 4: 3938 if (!strncmp(source, "xlfd", plen)) { 3939 ++plen; 3940 use_ttf = False; 3941 } else { 3942 marked = False; 3943 } 3944 break; 3945 default: 3946 marked = False; 3947 plen = 0; 3948 break; 3949 } 3950 break; 3951 } 3952 } 3953 if (!marked) 3954 plen = 0; 3955 value = x_strtrim(source + plen); 3956 if (value != 0) { 3957 Bool success = False; 3958#if OPT_RENDERFONT 3959 VTFontList *target = (use_ttf 3960 ? &(fontnames->xft) 3961 : &(fontnames->x11)); 3962#else 3963 VTFontList *target = &(fontnames->x11); 3964#endif 3965 char ***list = 0; 3966 char **next = 0; 3967 size_t count = 0; 3968 3969 (void) use_ttf; 3970 switch (which) { 3971 case fNorm: 3972 list = &(target->list_n); 3973 break; 3974 case fBold: 3975 list = &(target->list_b); 3976 break; 3977#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 3978 case fItal: 3979 list = &(target->list_i); 3980 break; 3981#endif 3982#if OPT_WIDE_CHARS 3983 case fWide: 3984 list = &(target->list_w); 3985 break; 3986 case fWBold: 3987 list = &(target->list_wb); 3988 break; 3989 case fWItal: 3990 list = &(target->list_wi); 3991 break; 3992#endif 3993 case fMAX: 3994 list = 0; 3995 break; 3996 } 3997 3998 if (list != 0) { 3999 success = True; 4000 if (*list != 0) { 4001 while ((*list)[count] != 0) { 4002 if (IsEmpty((*list)[count])) { 4003 TRACE(("... initial %s\n", value)); 4004 free((*list)[count]); 4005 break; 4006 } else if (!strcmp(value, (*list)[count])) { 4007 TRACE(("... duplicate %s\n", value)); 4008 success = False; 4009 break; 4010 } 4011 ++count; 4012 } 4013 } 4014 if (success) { 4015 next = realloc(*list, sizeof(char *) * (count + 2)); 4016 if (next != 0) { 4017#if OPT_RENDERFONT 4018 if (use_ttf) { 4019 trimSizeFromFace(value, 4020 (count == 0 && which == fNorm) 4021 ? &(xw->misc.face_size[0]) 4022 : (float *) 0); 4023 } 4024#endif 4025 next[count++] = value; 4026 next[count] = 0; 4027 *list = next; 4028 TRACE(("... saved %s %s %lu:%s\n", 4029 whichFontList(xw, target), 4030 whichFontList2(xw, *list), 4031 (unsigned long) count, 4032 value)); 4033 } else { 4034 fprintf(stderr, 4035 "realloc failure in save2FontList(%s)\n", 4036 name); 4037 freeFontList(list); 4038 success = False; 4039 } 4040 } 4041 } 4042 if (success) { 4043 size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS; 4044 if (count > limit && !IsEmpty(value)) { 4045 fprintf(stderr, "%s: too many fonts for %s, ignoring %s\n", 4046 ProgramName, 4047 whichFontEnum(which), 4048 value); 4049 if (list && *list) { 4050 free((*list)[limit]); 4051 (*list)[limit] = 0; 4052 } 4053 } 4054 } else { 4055 free(value); 4056 } 4057 } 4058} 4059 4060/* 4061 * In principle, any of the font-name resources could be extended to be a list 4062 * of font-names. That would be bad for performance, but as a basis for an 4063 * extension, parse the font-name as a comma-separated list, creating/updating 4064 * an array of font-names. 4065 */ 4066void 4067allocFontList(XtermWidget xw, 4068 const char *name, 4069 XtermFontNames * target, 4070 VTFontEnum which, 4071 const char *source, 4072 Bool ttf) 4073{ 4074 char *blob; 4075 4076 blob = x_strdup(source); 4077 if (!IsEmpty(blob)) { 4078 int n; 4079 int pass; 4080 char **list = 0; 4081 4082 TRACE(("allocFontList %s %s '%s'\n", whichFontEnum(which), name, blob)); 4083 4084 for (pass = 0; pass < 2; ++pass) { 4085 unsigned count = 0; 4086 if (pass) 4087 list[0] = blob; 4088 for (n = 0; blob[n] != '\0'; ++n) { 4089 if (blob[n] == ',') { 4090 ++count; 4091 if (pass != 0) { 4092 blob[n] = '\0'; 4093 list[count] = blob + n + 1; 4094 } 4095 } 4096 } 4097 if (!pass) { 4098 if (count == 0 && *blob == '\0') 4099 break; 4100 list = TypeCallocN(char *, count + 2); 4101 if (list == 0) 4102 break; 4103 } 4104 } 4105 if (list) { 4106 for (n = 0; list[n] != 0; ++n) { 4107 if (*list[n]) { 4108 save2FontList(xw, name, target, which, list[n], ttf); 4109 } 4110 } 4111 free(list); 4112 } 4113 } 4114 free(blob); 4115} 4116 4117static void 4118initFontList(XtermWidget xw, 4119 const char *name, 4120 XtermFontNames * target, 4121 Bool ttf) 4122{ 4123 int which; 4124 4125 TRACE(("initFontList(%s)\n", name)); 4126 for (which = 0; which < fMAX; ++which) { 4127 save2FontList(xw, name, target, (VTFontEnum) which, "", ttf); 4128 } 4129} 4130 4131void 4132initFontLists(XtermWidget xw) 4133{ 4134 TRACE(("initFontLists\n")); 4135 initFontList(xw, "x11 font", &(xw->work.fonts), False); 4136#if OPT_RENDERFONT 4137 initFontList(xw, "xft font", &(xw->work.fonts), True); 4138#endif 4139#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 4140 initFontList(xw, "cached font", 4141 &(xw->screen.cacheVTFonts.fonts), False); 4142#endif 4143} 4144 4145void 4146copyFontList(char ***targetp, char **source) 4147{ 4148 freeFontList(targetp); 4149 4150 if (source != 0) { 4151 int pass; 4152 size_t count; 4153 4154 for (pass = 0; pass < 2; ++pass) { 4155 for (count = 0; source[count] != 0; ++count) { 4156 if (pass) 4157 (*targetp)[count] = x_strdup(source[count]); 4158 } 4159 if (!pass) { 4160 ++count; 4161 *targetp = TypeCallocN(char *, count); 4162 } 4163 } 4164 } else { 4165 *targetp = TypeCallocN(char *, 2); 4166 (*targetp)[0] = x_strdup(""); 4167 } 4168} 4169 4170#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 4171static Boolean 4172merge_sublist(char ***targetp, char **source) 4173{ 4174 Boolean result = False; 4175 if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) { 4176 copyFontList(targetp, source); 4177 result = True; 4178 } 4179 return result; 4180} 4181#endif 4182 4183void 4184freeFontList(char ***targetp) 4185{ 4186 if (targetp != 0) { 4187 char **target = *targetp; 4188 if (target != 0) { 4189 int n; 4190 for (n = 0; target[n] != 0; ++n) { 4191 free(target[n]); 4192 } 4193 free(target); 4194 *targetp = 0; 4195 } 4196 } 4197} 4198 4199void 4200freeFontLists(VTFontList * lists) 4201{ 4202 int which; 4203 4204 TRACE(("freeFontLists\n")); 4205 for (which = 0; which < fMAX; ++which) { 4206 char ***target = 0; 4207 switch (which) { 4208 case fNorm: 4209 target = &(lists->list_n); 4210 break; 4211 case fBold: 4212 target = &(lists->list_b); 4213 break; 4214#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 4215 case fItal: 4216 target = &(lists->list_i); 4217 break; 4218#endif 4219#if OPT_WIDE_CHARS 4220 case fWide: 4221 target = &(lists->list_w); 4222 break; 4223 case fWBold: 4224 target = &(lists->list_wb); 4225 break; 4226 case fWItal: 4227 target = &(lists->list_wi); 4228 break; 4229#endif 4230 default: 4231 target = 0; 4232 break; 4233 } 4234 freeFontList(target); 4235 } 4236} 4237 4238/* 4239 * Return a pointer to the XLFD font information for a given font class. 4240 * XXX make this allocate the font on demand. 4241 */ 4242XTermFonts * 4243getNormalFont(TScreen *screen, int which) 4244{ 4245 XTermFonts *result = 0; 4246 if (which >= 0 && which < fMAX) 4247 result = &(screen->fnts[which]); 4248 return result; 4249} 4250 4251#if OPT_DEC_CHRSET 4252XTermFonts * 4253getDoubleFont(TScreen *screen, int which) 4254{ 4255 XTermFonts *result = 0; 4256 if ((int) which >= 0 && which < NUM_CHRSET) 4257 result = &(screen->double_fonts[which]); 4258 return result; 4259} 4260#endif 4261 4262#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 4263XTermFonts * 4264getItalicFont(TScreen *screen, int which) 4265{ 4266 XTermFonts *result = 0; 4267#if OPT_WIDE_ATTRS 4268 if (which >= 0 && which < fMAX) 4269 result = &(screen->ifnts[which]); 4270#else 4271 (void) screen; 4272 (void) which; 4273#endif 4274 return result; 4275} 4276#endif 4277 4278#if OPT_RENDERFONT 4279/* 4280 * This returns a pointer to everything known about a given Xft font. 4281 * XXX make this allocate the font on demand. 4282 */ 4283XTermXftFonts * 4284getMyXftFont(XtermWidget xw, int which, int fontnum) 4285{ 4286 TScreen *screen = TScreenOf(xw); 4287 XTermXftFonts *result = 0; 4288 if (fontnum >= 0 && fontnum < NMENUFONTS) { 4289 switch ((VTFontEnum) which) { 4290 case fNorm: 4291 result = &(screen->renderFontNorm[fontnum]); 4292 break; 4293 case fBold: 4294 result = &(screen->renderFontBold[fontnum]); 4295 break; 4296#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 4297 case fItal: 4298 result = &(screen->renderFontItal[fontnum]); 4299 break; 4300#endif 4301#if OPT_WIDE_CHARS 4302 case fWide: 4303 result = &(screen->renderWideNorm[fontnum]); 4304 break; 4305 case fWBold: 4306 result = &(screen->renderWideBold[fontnum]); 4307 break; 4308 case fWItal: 4309 result = &(screen->renderWideItal[fontnum]); 4310 break; 4311#endif 4312 case fMAX: 4313 break; 4314 } 4315 } 4316 return result; 4317} 4318 4319XftFont * 4320getXftFont(XtermWidget xw, VTFontEnum which, int fontnum) 4321{ 4322 XTermXftFonts *data = getMyXftFont(xw, which, fontnum); 4323 XftFont *result = 0; 4324 if (data != 0) 4325 result = data->font; 4326 return result; 4327} 4328#endif 4329 4330const char * 4331whichFontEnum(VTFontEnum value) 4332{ 4333 const char *result = "?"; 4334#define DATA(name) case name: result = #name; break 4335 switch (value) { 4336 DATA(fNorm); 4337 DATA(fBold); 4338#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 4339 DATA(fItal); 4340#endif 4341#if OPT_WIDE_CHARS 4342 DATA(fWide); 4343 DATA(fWBold); 4344 DATA(fWItal); 4345#endif 4346 DATA(fMAX); 4347 } 4348#undef DATA 4349 return result; 4350} 4351 4352const char * 4353whichFontList(XtermWidget xw, VTFontList * value) 4354{ 4355 const char *result = "?"; 4356 if (value == &(xw->work.fonts.x11)) 4357 result = "x11_fontnames"; 4358#if OPT_RENDERFONT 4359 else if (value == &(xw->work.fonts.xft)) 4360 result = "xft_fontnames"; 4361#endif 4362#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 4363 else if (value == &(xw->screen.cacheVTFonts.fonts.x11)) 4364 result = "cached_fontnames"; 4365#endif 4366 return result; 4367} 4368 4369static const char * 4370whichFontList2s(VTFontList * list, char **value) 4371{ 4372 const char *result = 0; 4373#define DATA(name) if (value == (list->name)) result = #name 4374 DATA(list_n); 4375 DATA(list_b); 4376#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 4377 DATA(list_i); 4378#endif 4379#if OPT_WIDE_CHARS 4380 DATA(list_w); 4381 DATA(list_wb); 4382 DATA(list_wi); 4383#endif 4384#undef DATA 4385 return result; 4386} 4387 4388const char * 4389whichFontList2(XtermWidget xw, char **value) 4390{ 4391 const char *result = 0; 4392#define DATA(name) (result = whichFontList2s(&(xw->name), value)) 4393 if (DATA(work.fonts.x11) == 0) { 4394#if OPT_RENDERFONT 4395 if (DATA(work.fonts.xft) == 0) 4396#endif 4397#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 4398 if (DATA(screen.cacheVTFonts.fonts.x11) == 0) 4399#endif 4400 result = "?"; 4401 } 4402#undef DATA 4403 return result; 4404} 4405