ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/rxvtfont.C
(Generate patch)

Comparing rxvt-unicode/src/rxvtfont.C (file contents):
Revision 1.6 by root, Tue Aug 17 01:58:17 2004 UTC vs.
Revision 1.41 by root, Wed Aug 25 02:33:09 2004 UTC

19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *---------------------------------------------------------------------*/ 20 *---------------------------------------------------------------------*/
21 21
22#include "../config.h" 22#include "../config.h"
23#include "rxvt.h" 23#include "rxvt.h"
24#include "rxvtutil.h"
24#include "rxvtfont.h" 25#include "rxvtfont.h"
25 26
26#include <cstdlib> 27#include <cstdlib>
28#include <wchar.h>
29#include <inttypes.h>
27 30
28#define DISPLAY r->display->display 31#define DISPLAY r->display->display
29#define TGC r->TermWin.gc 32#define TGC r->TermWin.gc
33
34#define MAX_OVERLAP (4 + 1) // max. character width in 4ths of the base width
30 35
31const struct rxvt_fallback_font { 36const struct rxvt_fallback_font {
32 codeset cs; 37 codeset cs;
33 const char *name; 38 const char *name;
34} fallback_fonts[] = { 39} fallback_fonts[] = {
52 { CS_ISO8859_10, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-10" }, 57 { CS_ISO8859_10, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-10" },
53 { CS_ISO8859_11, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-11" }, 58 { CS_ISO8859_11, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-11" },
54 { CS_ISO8859_13, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-13" }, 59 { CS_ISO8859_13, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-13" },
55 { CS_ISO8859_14, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-14" }, 60 { CS_ISO8859_14, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-14" },
56 { CS_ISO8859_16, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-16" }, 61 { CS_ISO8859_16, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-16" },
62
63# if XFT
64 { CS_KOI8_U, "xft::spacing=100:lang=ru:antialias=false" },
65
66 { CS_ISO8859_5, "xft::spacing=100:lang=ru:antialias=false" },
67 { CS_ISO8859_6, "xft::spacing=100:lang=ar:antialias=false" },
68 { CS_ISO8859_7, "xft::spacing=100:lang=el:antialias=false" },
69 { CS_ISO8859_8, "xft::spacing=100:lang=he:antialias=false" },
70 { CS_ISO8859_9, "xft::spacing=100:lang=tr:antialias=false" },
71 { CS_ISO8859_10, "xft::spacing=100:lang=se:antialias=false" },
72 { CS_ISO8859_11, "xft::spacing=100:lang=th:antialias=false" },
73# endif
57#endif 74#endif
58 75
59 // japanese 76 // japanese
60#if ENCODING_JP || ENCODING_JP_EXT 77#if ENCODING_JP || ENCODING_JP_EXT
61# if XFT 78# if XFT
62 // prefer xft for complex scripts 79 // prefer xft for complex scripts
63 { CS_UNICODE, "xft:Kochi Gothic:antialias=false" }, 80 { CS_JIS0208_1990_0, "xft:Kochi Gothic:antialias=false" },
81 { CS_JIS0208_1990_0, "xft:Sazanami Mincho:antialias=false" },
82 { CS_JIS0208_1990_0, "xft:Mincho:antialias=false" },
83 { CS_JIS0208_1990_0, "xft::lang=ja:spacing=100:antialias=false" },
64# endif 84# endif
65 { CS_JIS0201_1976_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0201*-0" }, 85 { CS_JIS0201_1976_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0201*-0" },
66 { CS_JIS0208_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0208*-0" }, 86 { CS_JIS0208_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0208*-0" },
67 { CS_JIS0212_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0212*-0" }, 87 { CS_JIS0212_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0212*-0" },
68 { CS_JIS0201_1976_0, "-*-*-*-r-*--*-*-*-*-c-*-jisx0201*-0" }, 88 { CS_JIS0201_1976_0, "-*-*-*-r-*--*-*-*-*-c-*-jisx0201*-0" },
74# if XFT 94# if XFT
75 { CS_BIG5_EXT, "xft:AR PL Mingti2L Big5" }, 95 { CS_BIG5_EXT, "xft:AR PL Mingti2L Big5" },
76 { CS_BIG5_EXT, "xft:AR PL KaitiM Big5" }, 96 { CS_BIG5_EXT, "xft:AR PL KaitiM Big5" },
77 { CS_GB2312_1980_0, "xft:AR PL KaitiM GB" }, 97 { CS_GB2312_1980_0, "xft:AR PL KaitiM GB" },
78 { CS_GB2312_1980_0, "xft:AR PL SungtiL GB" }, 98 { CS_GB2312_1980_0, "xft:AR PL SungtiL GB" },
99 { CS_GB2312_1980_0, "xft::spacing=100:lang=zh" },
79# endif 100# endif
80 { CS_BIG5, "-*-*-*-*-*-*-*-*-*-*-c-*-big5-0" }, 101 { CS_BIG5, "-*-*-*-*-*-*-*-*-*-*-c-*-big5-0" },
81 { CS_BIG5_PLUS, "-*-*-*-*-*-*-*-*-*-*-c-*-big5p-0" }, 102 { CS_BIG5_PLUS, "-*-*-*-*-*-*-*-*-*-*-c-*-big5p-0" },
82 { CS_BIG5_EXT, "-*-*-*-*-*-*-*-*-*-*-c-*-big5.eten-0" }, 103 { CS_BIG5_EXT, "-*-*-*-*-*-*-*-*-*-*-c-*-big5.eten-0" },
83 { CS_CNS11643_1992_1, "-*-*-*-*-*-*-*-*-*-*-c-*-gb2312*-0" }, 104 { CS_CNS11643_1992_1, "-*-*-*-*-*-*-*-*-*-*-c-*-gb2312*-0" },
89 { CS_CNS11643_1992_6, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-6" }, 110 { CS_CNS11643_1992_6, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-6" },
90 { CS_CNS11643_1992_7, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-7" }, 111 { CS_CNS11643_1992_7, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-7" },
91 { CS_CNS11643_1992_F, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-f" }, 112 { CS_CNS11643_1992_F, "-*-*-*-*-*-*-*-*-*-*-c-*-cns11643*-f" },
92#endif 113#endif
93 114
115#if ENCODING_KR
116 { CS_KSC5601_1987_0, "-baekmuk-gulim-*-*-*-*-*-*-*-*-c-*-ksc5601*" },
117 { CS_KSC5601_1987_0, "-*-*-*-*-*-*-*-*-*-*-c-*-ksc5601*" },
94#if XFT 118# if XFT
95 { CS_UNICODE, "xft:Andale Mono" }, 119 { CS_KSC5601_1987_0, "xft:Baekmuk Gulim:antialias=false" },
96 { CS_UNICODE, "xft:Arial Unicode MS" }, 120 { CS_KSC5601_1987_0, "xft::spacing=100:lang=ko:antialias=false" },
121# endif
97#endif 122#endif
123
124 // generic font fallback
98 { CS_UNICODE, "-*-lucidatypewriter-*-*-*-*-*-*-*-*-m-*-iso10646-1" }, 125 { CS_UNICODE, "-*-lucidatypewriter-*-*-*-*-*-*-*-*-m-*-iso10646-1" },
99 { CS_UNICODE, "-*-unifont-*-*-*-*-*-*-*-*-c-*-iso10646-1" }, 126 { CS_UNICODE, "-*-unifont-*-*-*-*-*-*-*-*-c-*-iso10646-1" },
100 { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1" }, 127 { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1" },
101 { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" }, 128 { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
102#if XFT 129#if XFT
130 { CS_UNICODE, "xft:Bitstream Vera Sans Mono:antialias=false"},
131 { CS_UNICODE, "xft:Andale Mono:antialias=false" },
132 { CS_UNICODE, "xft:Arial Unicode MS:antialias=false" },
133 { CS_UNICODE, "xft:Courier New:antialias=false" },
134
103 // FreeMono is usually uglier than x fonts, so try last only. 135 // FreeMono is usually uglier than x fonts, so try last only.
104 //{ CS_UNICODE, "xft:FreeMono" }, 136 { CS_UNICODE, "xft:FreeMono" },
105#endif 137#endif
106 138
107 { CS_UNKNOWN, 0 } 139 { CS_UNKNOWN, 0 }
108}; 140};
141
142// these characters are used to guess the font height and width
143// pango uses a similar algorithm and eosn't trust the font either.
144static uint16_t extent_test_chars[] = {
145 '0', '1', '8', 'a', 'd', 'x', 'm', 'y', 'g', 'W', 'X', '\'', '_',
146 0x00cd, 0x00d5, 0x0114, 0x0177, 0x0643, // ÍÕĔŷﻙ
147 0x304c, 0x672c, // が本
148};
149
150#define NUM_EXTENT_TEST_CHARS (sizeof (extent_test_chars) / sizeof (extent_test_chars[0]))
109 151
110///////////////////////////////////////////////////////////////////////////// 152/////////////////////////////////////////////////////////////////////////////
111 153
112#if XFT 154#if XFT
113rxvt_drawable::~rxvt_drawable () 155rxvt_drawable::~rxvt_drawable ()
186 228
187 return (XChar2b *)enc_buf; 229 return (XChar2b *)enc_buf;
188} 230}
189 231
190///////////////////////////////////////////////////////////////////////////// 232/////////////////////////////////////////////////////////////////////////////
233
234void
235rxvt_font::set_name (char *name)
236{
237 if (this->name == name)
238 return;
239
240 if (this->name) free (this->name); // let the compiler optimize
241 this->name = name;
242}
191 243
192void 244void
193rxvt_font::clear_rect (rxvt_drawable &d, int x, int y, int w, int h, int color) 245rxvt_font::clear_rect (rxvt_drawable &d, int x, int y, int w, int h, int color)
194{ 246{
195 if (color == Color_bg) 247 if (color == Color_bg)
206} 258}
207 259
208#include "table/linedraw.h" 260#include "table/linedraw.h"
209 261
210struct rxvt_font_default : rxvt_font { 262struct rxvt_font_default : rxvt_font {
263 struct rxvt_fontset *fs;
264
265 rxvt_font_default (rxvt_fontset *fs)
266 : rxvt_font ()
267 {
268 this->fs = fs;
269 }
211 270
212 rxvt_fontprop properties () 271 rxvt_fontprop properties ()
213 { 272 {
214 rxvt_fontprop p; 273 rxvt_fontprop p;
215 274
223 bool load (const rxvt_fontprop &prop) 282 bool load (const rxvt_fontprop &prop)
224 { 283 {
225 width = 1; height = 1; 284 width = 1; height = 1;
226 ascent = 1; descent = 0; 285 ascent = 1; descent = 0;
227 286
228 set_name (strdup ("built-in pseudofont")); 287 set_name (strdup ("built-in support font"));
229 288
230 return true; 289 return true;
231 } 290 }
232 291
233 bool has_codepoint (unicode_t unicode) 292 bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful)
234 { 293 {
294 careful = false;
295
235 if (unicode <= 0x001f) 296 if (unicode <= 0x001f)
236 return true; 297 return true;
237 298
238 if (unicode <= 0x007f) 299 if (unicode <= 0x007f)
239 return false; 300 return false;
248 return true; 309 return true;
249 310
250 switch (unicode) 311 switch (unicode)
251 { 312 {
252 case ZERO_WIDTH_CHAR: 313 case ZERO_WIDTH_CHAR:
314 case NOCHAR:
253 return true; 315 return true;
254 } 316 }
255 317
256 return false; 318 return false;
257 } 319 }
361 rxvt_font *f1 = (*fs)[fs->find_font (cc->c1)]; 423 rxvt_font *f1 = (*fs)[fs->find_font (cc->c1)];
362 f1->draw (d, x, y, &(t = cc->c1), 1, fg, bg); 424 f1->draw (d, x, y, &(t = cc->c1), 1, fg, bg);
363 if (cc->c2 != NOCHAR) 425 if (cc->c2 != NOCHAR)
364 { 426 {
365 // prefer font of first character, for no good reasons 427 // prefer font of first character, for no good reasons
428 bool careful;
366 rxvt_font *f2 = f1->has_codepoint (cc->c2) 429 rxvt_font *f2 = f1->has_char (cc->c2, 0, careful)
367 ? f1 430 ? f1
368 : (*fs)[fs->find_font (cc->c2)]; 431 : (*fs)[fs->find_font (cc->c2)];
369 432
370 f2->draw (d, x, y, &(t = cc->c2), 1, fg, -1); 433 f2->draw (d, x, y, &(t = cc->c2), 1, fg, -1);
371 } 434 }
372 } 435 }
373#endif 436#endif
374 else 437 else
375 switch (t) 438 switch (t)
376 { 439 {
440 case '\t':
377 case ZERO_WIDTH_CHAR: 441 case ZERO_WIDTH_CHAR:
442 case NOCHAR:
378 break; 443 break;
379 444
380 default: 445 default:
381 int w = 0; 446 int w = 0;
382 while (len > 0 && *text == NOCHAR) 447 while (len > 0 && *text == NOCHAR)
404 469
405 rxvt_fontprop properties (); 470 rxvt_fontprop properties ();
406 471
407 bool load (const rxvt_fontprop &prop); 472 bool load (const rxvt_fontprop &prop);
408 473
409 bool has_codepoint (unicode_t unicode); 474 bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful);
410 475
411 void draw (rxvt_drawable &d, int x, int y, 476 void draw (rxvt_drawable &d, int x, int y,
412 const text_t *text, int len, 477 const text_t *text, int len,
413 int fg, int bg); 478 int fg, int bg);
414 479
480 bool slow; // wether this is a proportional font or has other funny characteristics
415 XFontStruct *f; 481 XFontStruct *f;
416 codeset cs; 482 codeset cs;
417 bool enc2b, encm; 483 bool enc2b, encm;
418 484
419 char *get_property (XFontStruct *f, const char *property, const char *repl) const; 485 char *get_property (XFontStruct *f, const char *property, const char *repl) const;
442} 508}
443 509
444bool 510bool
445rxvt_font_x11::set_properties (rxvt_fontprop &p, int height, const char *weight, const char *slant, int avgwidth) 511rxvt_font_x11::set_properties (rxvt_fontprop &p, int height, const char *weight, const char *slant, int avgwidth)
446{ 512{
447 p.width = avgwidth ? (avgwidth + 1) / 10 : (height + 1) / 2; 513 p.width = avgwidth ? (avgwidth + 1) / 10 : (height + 1) / 2;
448 p.height = height; 514 p.height = height;
449 p.weight = *weight == 'B' || *weight == 'b' ? rxvt_fontprop::bold : rxvt_fontprop::medium; 515 p.weight = *weight == 'B' || *weight == 'b' ? rxvt_fontprop::bold : rxvt_fontprop::medium;
450 p.slant = *slant == 'r' || *slant == 'R' ? rxvt_fontprop::roman : rxvt_fontprop::italic; 516 p.slant = *slant == 'r' || *slant == 'R' ? rxvt_fontprop::roman : rxvt_fontprop::italic;
451 517
452 return true; 518 return true;
508 else 574 else
509 return false; 575 return false;
510} 576}
511 577
512// fix the size of scalable fonts 578// fix the size of scalable fonts
513static void 579static bool
514fix_scalable (char *buf, const char *name, const rxvt_fontprop &prop) 580replace_field (char *buf, const char *name, int index, const char old, const char *replace)
515{ 581{
516 int slashes = 0; 582 int slashes = 0;
517 const char *size; 583 const char *field, *end;
518 584
519 for (const char *c = name; *c; c++) 585 for (const char *c = name; *c; c++)
520 if (*c == '-') 586 if (*c == '-')
521 { 587 {
522 if (slashes == 6) 588 if (slashes == index)
523 size = c + 1; 589 field = c + 1;
590
591 if (slashes == index + 1)
592 end = c;
524 593
525 if (++slashes >= 13) 594 if (++slashes >= 13)
526 break; 595 break;
527 } 596 }
528 597
529 if (slashes >= 13 && size[0] == '0') 598 if (slashes >= 13 && (!old || *field == old))
530 { 599 {
600 // TODO: check for overflow in font-name
531 strncpy (buf, name, size - name); 601 strncpy (buf, name, field - name);
532 buf += size - name; 602 buf += field - name;
533 buf += sprintf (buf, "%d", prop.height);
534 strcpy (buf, size + 1); 603 strcpy (buf, replace);
604 strcat (buf, end);
605
606 return true;
535 } 607 }
536 else 608 else
609 {
537 strcpy (buf, name); 610 strcpy (buf, name);
611
612 return false;
613 }
538} 614}
539 615
540bool 616bool
541rxvt_font_x11::load (const rxvt_fontprop &prop) 617rxvt_font_x11::load (const rxvt_fontprop &prop)
542{ 618{
543 clear (); 619 clear ();
620
621 char field_str[64]; // enough for 128 bits
622
623 // first morph the font if required
624 if (prop.weight != rxvt_fontprop::unset
625 || prop.slant != rxvt_fontprop::unset)
626 {
627 char fname[1024];
628
629 if (name[0] != '-')
630 {
631 f = XLoadQueryFont (DISPLAY, name);
632
633 if (!f)
634 return false;
635
636 char *new_name = get_property (f, "FONT", name);
637
638 if (new_name)
639 set_name (new_name);
640 else
641 rxvt_warn ("font '%s' has no FONT property, continuing without.", name);
642
643 XFreeFont (DISPLAY, f);
644 f = 0;
645 }
646
647 if (prop.weight != rxvt_fontprop::unset)
648 {
649 replace_field (fname, name, 2, 0,
650 prop.weight < rxvt_fontprop::bold
651 ? "medium" : "bold");
652 set_name (strdup (fname));
653 }
654
655 if (prop.slant != rxvt_fontprop::unset)
656 {
657 replace_field (fname, name, 3, 0,
658 prop.slant < rxvt_fontprop::italic
659 ? "r" : "i"); // TODO: handle "o"blique, too
660 set_name (strdup (fname));
661 }
662 }
544 663
545 char **list; 664 char **list;
546 int count; 665 int count;
547 list = XListFonts (DISPLAY, name, 1024, &count); 666 list = XListFonts (DISPLAY, name, 1024, &count);
667
548 set_name (0); 668 set_name (0);
549 669
550 if (!list) 670 if (!list)
551 return false; 671 return false;
552 672
673 sprintf (field_str, "%d", prop.height == rxvt_fontprop::unset
674 ? 0 : prop.height);
675
553 int bestdiff = 0x7fffffff; 676 int bestdiff = 0x7fffffff;
554 for (int i = 0; i < count; i++) 677 for (int i = 0; i < count; i++)
555 { 678 {
556 rxvt_fontprop p; 679 rxvt_fontprop p;
557 char fname[1024]; 680 char fname[1024];
558 fix_scalable (fname, list[i], prop); 681
682 int diff = 0;
683
684 if (replace_field (fname, list[i], 6, '0', field_str))
685 diff += 10; // slightly penalize scalable fonts
559 686
560 if (!set_properties (p, fname)) 687 if (!set_properties (p, fname))
561 continue; 688 continue;
562 689
690 if (prop.height != rxvt_fontprop::unset
563 if (p.height > prop.height) // weed out too large fonts 691 && p.height > prop.height) // weed out too large fonts
564 continue; 692 continue;
565 693
566 int diff = (prop.height - p.height) * 32 694 if (prop.height != rxvt_fontprop::unset) diff += (prop.height - p.height) * 128;
567 + abs (prop.weight - p.weight) 695 if (prop.weight != rxvt_fontprop::unset) diff += abs (prop.weight - p.weight);
568 + abs (prop.slant - p.slant ); 696 if (prop.slant != rxvt_fontprop::unset) diff += abs (prop.slant - p.slant);
697 //if (prop.width != rxvt_fontprop::unset) diff += abs (prop.width - p.width);
569 698
570 if (!name // compare against best found so far 699 if (!name // compare against best found so far
571 || diff < bestdiff) 700 || diff < bestdiff)
572 { 701 {
573 set_name (strdup (fname)); 702 set_name (strdup (fname));
617 cs = CS_UNICODE_16; // X11 can have a max. of 65536 chars per font 746 cs = CS_UNICODE_16; // X11 can have a max. of 65536 chars per font
618 747
619 encm = f->min_byte1 != 0 || f->max_byte1 != 0; 748 encm = f->min_byte1 != 0 || f->max_byte1 != 0;
620 enc2b = encm || f->max_char_or_byte2 > 255; 749 enc2b = encm || f->max_char_or_byte2 > 255;
621 750
622 ascent = f->ascent; 751 ascent = f->ascent;
623 descent = f->descent; 752 descent = f->descent;
624 height = ascent + descent; 753 height = ascent + descent;
625 754
626 slow = false; 755 slow = false;
627 756
757#if 1 // only used for slow detection, TODO optimize
628 if (f->min_bounds.width == f->max_bounds.width) 758 if (f->min_bounds.width == f->max_bounds.width)
629 width = f->min_bounds.width; 759 width = f->min_bounds.width;
630 else if (f->per_char == NULL) 760 else if (f->per_char == NULL)
631 width = f->max_bounds.width; 761 width = f->max_bounds.width;
632 else 762 else
645 width = f->per_char[N].width; 775 width = f->per_char[N].width;
646 776
647 --N; 777 --N;
648 } 778 }
649 } 779 }
780#endif
781
782 width = 1;
783
784 for (uint16_t *t = extent_test_chars + NUM_EXTENT_TEST_CHARS; t-- > extent_test_chars; )
785 {
786 if (cs != CS_UNICODE
787 && *t > 0x100
788 && FROM_UNICODE (cs, *t) == NOCHAR)
789 continue;
790
791 // ignore characters we wouldn't use anyways
792 bool careful;
793 if (!has_char (*t, &prop, careful))
794 continue;
795
796 XChar2b ch = { *t >> 8, *t };
797
798 XCharStruct g;
799 int dir_ret, asc_ret, des_ret;
800 XTextExtents16 (f, &ch, 1, &dir_ret, &asc_ret, &des_ret, &g);
801
802 int wcw = wcwidth (*t); if (wcw > 0) g.width = g.width / wcw;
803
804 if (width < g.width) width = g.width;
805 }
650 806
651 if (cs == CS_UNKNOWN) 807 if (cs == CS_UNKNOWN)
652 { 808 {
653 fprintf (stderr, "unable to deduce codeset, ignoring font '%s'\n", name); 809 fprintf (stderr, "unable to deduce codeset, ignoring font '%s'\n", name);
654 810
655 clear (); 811 clear ();
656
657 return false; 812 return false;
658 } 813 }
814
815#if 0 // do it per-character
816 if (prop && width > prop->width)
817 {
818 clear ();
819 return false;
820 }
821#endif
659 822
660 return true; 823 return true;
661} 824}
662 825
663void 826void
669 f = 0; 832 f = 0;
670 } 833 }
671} 834}
672 835
673bool 836bool
674rxvt_font_x11::has_codepoint (unicode_t unicode) 837rxvt_font_x11::has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful)
675{ 838{
676 uint32_t ch = FROM_UNICODE (cs, unicode); 839 uint32_t ch = FROM_UNICODE (cs, unicode);
677 840
678 if (ch == NOCHAR) 841 if (ch == NOCHAR)
679 return false; 842 return false;
688 851
689 if (byte1 < f->min_byte1 || byte1 > f->max_byte1 852 if (byte1 < f->min_byte1 || byte1 > f->max_byte1
690 || byte2 < f->min_char_or_byte2 || byte2 > f->max_char_or_byte2) 853 || byte2 < f->min_char_or_byte2 || byte2 > f->max_char_or_byte2)
691 return false; 854 return false;
692 855
693 if (!f->per_char) 856 if (f->per_char)
694 return true; 857 {
695
696 int D = f->max_char_or_byte2 - f->min_char_or_byte2 + 1; 858 int D = f->max_char_or_byte2 - f->min_char_or_byte2 + 1;
697 int N = (byte1 - f->min_byte1) * D + byte2 - f->min_char_or_byte2; 859 int N = (byte1 - f->min_byte1) * D + byte2 - f->min_char_or_byte2;
698 860
699 xcs = f->per_char + N; 861 xcs = f->per_char + N;
862 }
863 else
864 xcs = &f->max_bounds;
700 } 865 }
701 else 866 else
702 { 867 {
703 if (ch < f->min_char_or_byte2 || ch > f->max_char_or_byte2) 868 if (ch < f->min_char_or_byte2 || ch > f->max_char_or_byte2)
704 return false; 869 return false;
705 870
706 if (!f->per_char) 871 if (f->per_char)
707 return true;
708
709 xcs = f->per_char + (ch - f->min_char_or_byte2); 872 xcs = f->per_char + (ch - f->min_char_or_byte2);
873 else
874 xcs = &f->max_bounds;
710 } 875 }
711 876
712 if (xcs->lbearing == 0 && xcs->rbearing == 0 && xcs->width == 0 877 if (xcs->lbearing == 0 && xcs->rbearing == 0 && xcs->width == 0
713 && xcs->ascent == 0 && xcs->descent == 0) 878 && xcs->ascent == 0 && xcs->descent == 0)
879 return false;
880
881 if (!prop || prop->width == rxvt_fontprop::unset)
882 return true;
883
884 // check character against base font bounding box
885 int w = xcs->width;
886 int wcw = wcwidth (unicode);
887 if (wcw > 0) w /= wcw;
888
889 careful = w > prop->width;
890 if (careful && w > prop->width * MAX_OVERLAP >> 2)
714 return false; 891 return false;
715 892
716 return true; 893 return true;
717} 894}
718 895
728 905
729 bool slow = this->slow 906 bool slow = this->slow
730 || width != r->TermWin.fwidth 907 || width != r->TermWin.fwidth
731 || height != r->TermWin.fheight; 908 || height != r->TermWin.fheight;
732 909
733 int base = r->TermWin.fbase; 910 int base = ascent; // sorry, incorrect: r->TermWin.fbase;
734 911
735 XGCValues v; 912 XGCValues v;
736 v.foreground = r->pix_colors[fg]; 913 v.foreground = r->pix_colors[fg];
737 v.font = f->fid; 914 v.font = f->fid;
738 915
803} 980}
804 981
805///////////////////////////////////////////////////////////////////////////// 982/////////////////////////////////////////////////////////////////////////////
806 983
807#if XFT 984#if XFT
808#if 0
809#define UNIBITS 21
810//#define SWATHBITS (UNIBITS / 2 + 3) // minimum size for "full" tables
811#define SWATHBITS 8
812#endif
813 985
814struct rxvt_font_xft : rxvt_font { 986struct rxvt_font_xft : rxvt_font {
815 rxvt_font_xft () { f = 0; } 987 rxvt_font_xft () { f = 0; }
816 988
817 void clear (); 989 void clear ();
822 994
823 void draw (rxvt_drawable &d, int x, int y, 995 void draw (rxvt_drawable &d, int x, int y,
824 const text_t *text, int len, 996 const text_t *text, int len,
825 int fg, int bg); 997 int fg, int bg);
826 998
827 bool has_codepoint (unicode_t unicode); 999 bool has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &carefull);
828 1000
829protected: 1001protected:
830 XftFont *f; 1002 XftFont *f;
831}; 1003};
832 1004
860} 1032}
861 1033
862bool 1034bool
863rxvt_font_xft::load (const rxvt_fontprop &prop) 1035rxvt_font_xft::load (const rxvt_fontprop &prop)
864{ 1036{
865#if 0
866 for (int i = 0; i < SWATHCOUNT; i++)
867 cvr[i] = 0;
868#endif
869
870 clear (); 1037 clear ();
871 1038
872 FcPattern *p = FcNameParse ((FcChar8 *) name); 1039 FcPattern *p = FcNameParse ((FcChar8 *) name);
873 1040
874 if (!p) 1041 if (!p)
875 return false; 1042 return false;
876 1043
877 FcValue v; 1044 FcValue v;
878 1045
1046 if (prop.height != rxvt_fontprop::unset
879 if (FcPatternGet (p, FC_PIXEL_SIZE, 0, &v) != FcResultMatch) 1047 && FcPatternGet (p, FC_PIXEL_SIZE, 0, &v) != FcResultMatch)
880 FcPatternAddInteger (p, FC_PIXEL_SIZE, prop.height); 1048 FcPatternAddInteger (p, FC_PIXEL_SIZE, prop.height);
881 1049
1050 if (prop.weight != rxvt_fontprop::unset
882 if (FcPatternGet (p, FC_WEIGHT, 0, &v) != FcResultMatch) 1051 && FcPatternGet (p, FC_WEIGHT, 0, &v) != FcResultMatch)
883 FcPatternAddInteger (p, FC_WEIGHT, prop.weight); 1052 FcPatternAddInteger (p, FC_WEIGHT, prop.weight);
884 1053
1054 if (prop.slant != rxvt_fontprop::unset
885 if (FcPatternGet (p, FC_SLANT, 0, &v) != FcResultMatch) 1055 && FcPatternGet (p, FC_SLANT, 0, &v) != FcResultMatch)
886 FcPatternAddInteger (p, FC_SLANT, prop.slant); 1056 FcPatternAddInteger (p, FC_SLANT, prop.slant);
887
888 if (FcPatternGet (p, FC_MINSPACE, 0, &v) != FcResultMatch)
889 FcPatternAddBool (p, FC_MINSPACE, 1);
890 1057
891#if 0 // clipping unfortunately destroys our precious double-width-characters 1058#if 0 // clipping unfortunately destroys our precious double-width-characters
892 // clip width, we can't do better, or can we? 1059 // clip width, we can't do better, or can we?
893 if (FcPatternGet (p, FC_CHAR_WIDTH, 0, &v) != FcResultMatch) 1060 if (FcPatternGet (p, FC_CHAR_WIDTH, 0, &v) != FcResultMatch)
894 FcPatternAddInteger (p, FC_CHAR_WIDTH, prop.width); 1061 FcPatternAddInteger (p, FC_CHAR_WIDTH, prop->width);
895#endif 1062#endif
1063
1064 if (FcPatternGet (p, FC_MINSPACE, 0, &v) != FcResultMatch)
1065 FcPatternAddBool (p, FC_MINSPACE, 1);
1066
1067 // store generated name so iso14755 view gives better results
1068 set_name ((char *)FcNameUnparse (p));
896 1069
897 XftResult result; 1070 XftResult result;
898 FcPattern *match = XftFontMatch (DISPLAY, DefaultScreen (DISPLAY), p, &result); 1071 FcPattern *match = XftFontMatch (DISPLAY, DefaultScreen (DISPLAY), p, &result);
899 1072
900 FcPatternDestroy (p); 1073 FcPatternDestroy (p);
901 1074
902 if (!match) 1075 if (!match)
903 return false; 1076 return false;
904 1077
905 f = XftFontOpenPattern (DISPLAY, match);
906
907 if (!f)
908 {
909 FcPatternDestroy (match);
910 return false;
911 }
912
913 FT_Face face = XftLockFace (f);
914
915 slow = !FT_IS_FIXED_WIDTH (face);
916
917 int ftheight = 0; 1078 int ftheight = 0;
1079 bool success = true;
918 1080
919 for (;;) 1081 for (;;)
920 { 1082 {
921 XGlyphInfo g1, g2; 1083 f = XftFontOpenPattern (DISPLAY, FcPatternDuplicate (match));
922 FcChar8 c;
923 1084
924 c = 'i'; XftTextExtents8 (DISPLAY, f, &c, 1, &g1); 1085 if (!f)
925 c = 'W'; XftTextExtents8 (DISPLAY, f, &c, 1, &g2); 1086 {
1087 success = false;
1088 break;
1089 }
926 1090
927 if (g1.xOff != g2.xOff) // don't simply trust the font 1091 FT_Face face = XftLockFace (f);
928 slow = true;
929 1092
930 width = g2.xOff;
931 ascent = (face->size->metrics.ascender + 63) >> 6; 1093 ascent = (face->size->metrics.ascender + 63) >> 6;
932 descent = (-face->size->metrics.descender + 63) >> 6; 1094 descent = (-face->size->metrics.descender + 63) >> 6;
933 height = ascent + descent; 1095 height = max (ascent + descent, (face->size->metrics.height + 63) >> 6);
1096 width = 0;
934 1097
935 if (height <= prop.height || !prop.height) 1098 bool scalable = face->face_flags & FT_FACE_FLAG_SCALABLE;
1099
1100 XftUnlockFace (f);
1101
1102 for (uint16_t *t = extent_test_chars + NUM_EXTENT_TEST_CHARS; t-- > extent_test_chars; )
1103 {
1104 FcChar16 ch = *t;
1105
1106 if (cs != CS_UNICODE
1107 && ch > 0x100
1108 && FROM_UNICODE (cs, ch) == NOCHAR)
1109 continue;
1110
1111 // ignore characters we wouldn't use anyways
1112 bool careful;
1113 if (!has_char (*t, &prop, careful))
1114 continue;
1115
1116 XGlyphInfo g;
1117 XftTextExtents16 (DISPLAY, f, &ch, 1, &g);
1118
1119 int wcw = wcwidth (ch);
1120 if (wcw > 0) g.width = g.width / wcw;
1121
1122 if (width < g.width) width = g.width;
1123 if (height < g.height) height = g.height;
1124 }
1125
1126 if (prop.height == rxvt_fontprop::unset
1127 || height <= prop.height
1128 || height <= 2
1129 || !scalable)
936 break; 1130 break;
937 1131
938 if (ftheight) 1132 if (ftheight)
939 { 1133 {
940 // take smaller steps near the end 1134 // take smaller steps near the end
941 if (height > prop.height + 1) ftheight++; 1135 if (height > prop.height + 1) ftheight++;
942 if (height > prop.height + 2) ftheight++; 1136 if (height > prop.height + 2) ftheight++;
943 if (height > prop.height + 3) ftheight++; 1137 if (height > prop.height + 3) ftheight++;
944 1138
945 FT_Set_Pixel_Sizes (face, 0, ftheight -= height - prop.height); 1139 ftheight -= height - prop.height;
946 } 1140 }
947 else 1141 else
948 FT_Set_Pixel_Sizes (face, 0, ftheight = prop.height); 1142 ftheight = prop.height - 1;
1143
1144 XftFontClose (DISPLAY, f);
1145 FcPatternDel (match, FC_PIXEL_SIZE);
1146 FcPatternAddInteger (match, FC_PIXEL_SIZE, ftheight);
1147 }
1148
1149 FcPatternDestroy (match);
1150
1151#if 0 // do it per-character
1152 if (prop.width != rxvt_fontprop::unset && width > prop.width)
949 } 1153 {
1154 clear ();
1155 success = false;
1156 }
1157#endif
950 1158
951 XftUnlockFace (f); 1159 return success;
1160}
1161
1162bool
1163rxvt_font_xft::has_char (unicode_t unicode, const rxvt_fontprop *prop, bool &careful)
1164{
1165 careful = false;
1166
1167 if (!XftCharExists (DISPLAY, f, unicode))
1168 return false;
1169
1170 if (!prop || prop->width == rxvt_fontprop::unset)
1171 return true;
1172
1173 // check character against base font bounding box
1174 FcChar32 ch = unicode;
1175 XGlyphInfo g;
1176 XftTextExtents32 (DISPLAY, f, &ch, 1, &g);
1177
1178 int w = g.width;
1179 int wcw = wcwidth (unicode);
1180 if (wcw > 0) w /= wcw;
1181
1182 careful = w > prop->width;
1183 if (careful && w > prop->width * MAX_OVERLAP >> 2)
1184 return false;
952 1185
953 return true; 1186 return true;
954}
955
956bool
957rxvt_font_xft::has_codepoint (unicode_t unicode)
958{
959 return XftCharExists (DISPLAY, f, unicode);
960} 1187}
961 1188
962void 1189void
963rxvt_font_xft::draw (rxvt_drawable &d, int x, int y, 1190rxvt_font_xft::draw (rxvt_drawable &d, int x, int y,
964 const text_t *text, int len, 1191 const text_t *text, int len,
965 int fg, int bg) 1192 int fg, int bg)
966{ 1193{
967 clear_rect (d, x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg); 1194 clear_rect (d, x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
968 1195
969 if (0 && !slow && width == r->TermWin.fwidth) 1196 int base = ascent; // should be fbase, but that is incorrect
1197
1198 XGlyphInfo extents;
1199 FcChar32 *enc = (FcChar32 *) get_enc_buf (len * sizeof (FcChar32));
1200 FcChar32 *ep = enc;
1201 int ewidth = 0;
1202 int xoff = 0;
1203
1204 while (len)
970 { 1205 {
971 if (sizeof (text_t) == sizeof (FcChar16)) 1206 int cwidth = r->TermWin.fwidth;
972 XftDrawString16 (d, &r->pix_colors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar16 *)text, len); 1207 FcChar32 fc = *text++; len--;
1208 FT_UInt gl;
1209
1210 while (len && *text == NOCHAR)
1211 text++, len--, cwidth += r->TermWin.fwidth;
1212
1213 gl = XftCharIndex (d.display->display, f, fc);
1214 XftGlyphExtents (d.display->display, f, &gl, 1, &extents);
1215
1216 if (extents.xOff != cwidth && ep != enc)
1217 {
1218 if (xoff > ewidth) xoff = ewidth;
1219 XftDrawGlyphs (d, &r->pix_colors[fg].c, f,
1220 x + (ewidth - xoff >> 1),
1221 y + base, enc, ep - enc);
1222 x += ewidth;
1223
1224 ep = enc;
1225 ewidth = 0;
1226 xoff = 0;
1227 }
1228
1229 if (fc == ' ' && ep == enc) // skip leading spaces
1230 {
1231 x += cwidth;
1232 continue;
1233 }
1234
973 else 1235 else
974 XftDrawString32 (d, &r->pix_colors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar32 *)text, len);
975 }
976 else
977 {
978 while (len)
979 {
980 if (*text != NOCHAR && *text != ' ')
981 {
982 int fwidth = r->TermWin.fwidth;
983 if (len >= 2 && text[1] == NOCHAR)
984 fwidth *= 2;
985
986 XGlyphInfo extents;
987 if (sizeof (text_t) == sizeof (FcChar16))
988 {
989 XftTextExtents16 (d.display->display, f, (const FcChar16 *)text, 1, &extents);
990 XftDrawString16 (d, &r->pix_colors[fg].c, f, x + extents.x + (fwidth - extents.width) / 2,
991 y + r->TermWin.fbase, (const FcChar16 *)text, 1);
992 }
993 else
994 {
995 XGlyphInfo extents;
996 XftTextExtents32 (d.display->display, f, (const FcChar32 *)text, 1, &extents);
997 XftDrawString32 (d, &r->pix_colors[fg].c, f, x + extents.x + (fwidth - extents.width) / 2,
998 y + r->TermWin.fbase, (const FcChar32 *)text, 1);
999 }
1000 }
1001
1002 x += r->TermWin.fwidth;
1003 text++;
1004 len--;
1005 } 1236 {
1237 *ep++ = gl;
1238 ewidth += cwidth;
1239 xoff += extents.xOff;
1240 }
1241 }
1242
1243 if (ep != enc)
1244 {
1245 if (xoff > ewidth) xoff = ewidth;
1246 XftDrawGlyphs (d, &r->pix_colors[fg].c, f,
1247 x + (ewidth - xoff >> 1),
1248 y + base, enc, ep - enc);
1006 } 1249 }
1007} 1250}
1008#endif 1251#endif
1009 1252
1010///////////////////////////////////////////////////////////////////////////// 1253/////////////////////////////////////////////////////////////////////////////
1024rxvt_fontset::clear () 1267rxvt_fontset::clear ()
1025{ 1268{
1026 for (rxvt_font **i = fonts.begin (); i != fonts.end (); i++) 1269 for (rxvt_font **i = fonts.begin (); i != fonts.end (); i++)
1027 FONT_UNREF (*i); 1270 FONT_UNREF (*i);
1028 1271
1272 for (pagemap **p = fmap.begin (); p != fmap.end (); p++)
1273 delete *p;
1274
1029 free (fontdesc); fontdesc = 0; 1275 free (fontdesc); fontdesc = 0;
1030 1276
1031 fonts.clear (); 1277 fonts.clear ();
1032 base_id = 0;
1033 base_prop.height = 0x7fffffff;
1034 base_prop.weight = rxvt_fontprop::medium;
1035 base_prop.slant = rxvt_fontprop::roman;
1036 1278
1037 fallback = fallback_fonts; 1279 fallback = fallback_fonts;
1038} 1280}
1039 1281
1040rxvt_font * 1282rxvt_font *
1043 rxvt_font *f; 1285 rxvt_font *f;
1044 1286
1045 if (!name || !*name) 1287 if (!name || !*name)
1046 { 1288 {
1047 name = ""; 1289 name = "";
1048 f = new rxvt_font_default; 1290 f = new rxvt_font_default (this);
1049 } 1291 }
1050#if XFT 1292#if XFT
1051 else if (!strncmp (name, "xft:", 4)) 1293 else if (!strncmp (name, "xft:", 4))
1052 { 1294 {
1053 name += 4; 1295 name += 4;
1054 f = new rxvt_font_xft; 1296 f = new rxvt_font_xft ();
1055 } 1297 }
1056#endif 1298#endif
1057 else if (!strncmp (name, "x:", 2)) 1299 else if (!strncmp (name, "x:", 2))
1058 { 1300 {
1059 name += 2; 1301 name += 2;
1060 f = new rxvt_font_x11; 1302 f = new rxvt_font_x11;
1061 } 1303 }
1062 else 1304 else
1063 f = new rxvt_font_x11; 1305 f = new rxvt_font_x11;
1064 1306
1065 f->fs = this;
1066 f->set_term (r); 1307 f->set_term (r);
1067 f->set_name (strdup (name)); 1308 f->set_name (strdup (name));
1068 1309
1069 f->cs = cs; 1310 f->cs = cs;
1070 f->loaded = false; 1311 f->loaded = false;
1084 1325
1085 do 1326 do
1086 { 1327 {
1087 while (*desc <= ' ') desc++; 1328 while (*desc <= ' ') desc++;
1088 1329
1330 codeset cs = CS_UNICODE;
1331
1089 if (*desc == '[') 1332 if (*desc == '[')
1090 { 1333 {
1091 fprintf (stderr, "extra font parameters not yet supported, skipping.\n"); 1334 char spec[256];
1092
1093 //const char *extra = desc++; // not yet used 1335 const char *extra = ++desc; // not yet used
1094 1336
1095 desc = strchr (desc, ']'); 1337 desc = strchr (desc, ']');
1096 1338
1097 if (!desc) 1339 if (!desc)
1098 { 1340 {
1099 fprintf (stderr, "ERROR: opening '[' without closing ']' in font specification.\n"); 1341 rxvt_warn ("ERROR: opening '[' without closing ']' in font specification, trying to continue.\n");
1100 break; 1342 break;
1101 } 1343 }
1344
1345 memcpy (spec, extra, min (desc - extra, 255));
1346 spec[min (desc - extra, 255)] = 0;
1347
1348 if (!strncmp (extra, "codeset=", sizeof ("codeset=") - 1))
1349 cs = codeset_from_name (spec + sizeof ("codeset=") - 1);
1350 else
1351 rxvt_warn ("unknown parameter '%s' in font specification, skipping.\n", spec);
1102 1352
1103 desc++; 1353 desc++;
1104 while (*desc <= ' ') desc++; 1354 while (*desc <= ' ') desc++;
1105 } 1355 }
1106 1356
1111 if (end - desc < 511) 1361 if (end - desc < 511)
1112 { 1362 {
1113 strncpy (buf, desc, end - desc); 1363 strncpy (buf, desc, end - desc);
1114 buf[end - desc] = 0; 1364 buf[end - desc] = 0;
1115 1365
1116 fonts.push_back (new_font (buf, CS_UNICODE)); 1366 fonts.push_back (new_font (buf, cs));
1117 } 1367 }
1368 else
1369 rxvt_warn ("fontset element too long (>511 bytes), ignored.");
1118 1370
1119 desc = end + 1; 1371 desc = end + 1;
1120 } 1372 }
1121 while (*end); 1373 while (*end);
1122 } 1374 }
1123} 1375}
1124 1376
1125bool 1377bool
1126rxvt_fontset::realize_font (int i) 1378rxvt_fontset::realize_font (int i)
1127{ 1379{
1380 if (i < 0 || i >= fonts.size ())
1381 return false;
1382
1128 if (fonts[i]->loaded) 1383 if (fonts[i]->loaded)
1129 return true; 1384 return true;
1130 1385
1131 fonts[i]->loaded = true; 1386 fonts[i]->loaded = true;
1132 1387
1133 if (!fonts[i]->load (base_prop)) 1388 if (!fonts[i]->load (prop))
1134 { 1389 {
1135 fonts[i]->cs = CS_UNKNOWN; 1390 fonts[i]->cs = CS_UNKNOWN;
1136 return false; 1391 return false;
1137 } 1392 }
1138 1393
1139 return true; 1394 return true;
1140} 1395}
1141 1396
1142bool 1397bool
1143rxvt_fontset::populate (const char *desc) 1398rxvt_fontset::populate (const char *desc, const rxvt_fontprop &prop)
1144{ 1399{
1145 clear (); 1400 clear ();
1146 1401
1147 fontdesc = strdup (desc); 1402 fontdesc = strdup (desc);
1148 1403
1149 fonts.push_back (new_font (0, CS_UNICODE)); 1404 fonts.push_back (new_font (0, CS_UNICODE));
1150 realize_font (0); 1405 realize_font (0);
1151 1406
1407 this->prop = prop;
1408
1152 add_fonts (desc); 1409 add_fonts (desc);
1153
1154 if (!base_id)
1155 base_id = 1;
1156
1157 // we currently need a base-font, no matter what
1158 if ((int)fonts.size () <= base_id || !realize_font (base_id))
1159 {
1160 puts ("unable to load specified font (s), falling back to 'fixed'\n");
1161 add_fonts ("fixed");
1162 base_id = fonts.size () - 1;
1163 }
1164
1165 if ((int)fonts.size () <= base_id || !realize_font (base_id))
1166 return false;
1167
1168 base_prop = fonts[base_id]->properties ();
1169 1410
1170 return true; 1411 return true;
1171} 1412}
1172 1413
1173int 1414int
1179 1420
1180 return -1; 1421 return -1;
1181} 1422}
1182 1423
1183int 1424int
1184rxvt_fontset::find_font (unicode_t unicode, bool bold) 1425rxvt_fontset::find_font (unicode_t unicode)
1185{ 1426{
1427 if (unicode >= 1<<20)
1428 return 0;
1186 1429
1187 for (unsigned int i = !!(0x20 <= unicode && unicode <= 0x7f); // skip pseudo-font for ascii 1430 unicode_t hi = unicode >> 8;
1188 i < fonts.size (); 1431
1189 i++) 1432 if (hi < fmap.size ()
1433 && fmap[hi]
1434 && (*fmap[hi])[unicode & 0xff] != 0xff)
1435 return (*fmap[hi])[unicode & 0xff];
1436
1437 unsigned int i;
1438
1439 for (i = 0; i < fonts.size (); i++)
1190 { 1440 {
1191 rxvt_font *f = fonts[i]; 1441 rxvt_font *f = fonts[i];
1192 1442
1193 if (!f->loaded) 1443 if (!f->loaded)
1194 { 1444 {
1200 } 1450 }
1201 1451
1202 if (f->cs == CS_UNKNOWN) 1452 if (f->cs == CS_UNKNOWN)
1203 goto next_font; 1453 goto next_font;
1204 1454
1205 if (bold && f->properties ().weight < rxvt_fontprop::bold) 1455 bool careful;
1456 if (f->has_char (unicode, &prop, careful))
1457 {
1458 if (careful)
1459 i |= 128;
1460
1206 goto next_font; 1461 goto found;
1207 1462 }
1208 if (f->has_codepoint (unicode))
1209 return i;
1210 1463
1211 next_font: 1464 next_font:
1212 if (i == fonts.size () - 1) 1465 if (i == fonts.size () - 1)
1213 { 1466 {
1214 if (fallback->name) 1467 if (fallback->name)
1215 { 1468 {
1216 // search through the fallback list 1469 // search through the fallback list
1217 fonts.push_back (new_font (fallback->name, fallback->cs)); 1470 fonts.push_back (new_font (fallback->name, fallback->cs));
1218 fallback++; 1471 fallback++;
1219 } 1472 }
1220 else if (!bold) 1473 else
1221 { 1474 {
1222 // try to find a new font. 1475 // try to find a new font.
1223 // only xft currently supported, as there is no 1476 // only xft currently supported, as there is no
1224 // way to configure this and xft is easier to hack in, 1477 // way to configure this and xft is easier to hack in,
1225 // while x11 has more framework in place already. 1478 // while x11 has more framework in place already.
1226 // TODO: bold is being ignroed (obviously). 1479 // TODO: this is a real resource hog, xft takes ages(?)
1227#if XFT 1480#if XFT && USE_SLOW_LOOKUP
1228 // grab the first xft font that seems suitable 1481 // grab the first xft font that seems suitable
1229 FcPattern *p = FcPatternCreate (); 1482 FcPattern *p = FcPatternCreate ();
1230 1483
1231 FcCharSet *s = FcCharSetCreate (); 1484 FcCharSet *s = FcCharSetCreate ();
1232 FcCharSetAddChar (s, unicode); 1485 FcCharSetAddChar (s, unicode);
1233 FcPatternAddCharSet (p, FC_CHARSET, s); 1486 FcPatternAddCharSet (p, FC_CHARSET, s);
1234 // charsets don't help that much, as xft might return 1487 // charsets don't help that much, as xft might return
1235 // a non-matching font even if a better font is available :/ 1488 // a non-matching font even if a better font is available :/
1236 1489
1490 x x x x TODO prop might have unset contents
1237 FcPatternAddInteger (p, FC_PIXEL_SIZE, base_prop.height); 1491 FcPatternAddInteger (p, FC_PIXEL_SIZE, prop.height);
1238 FcPatternAddInteger (p, FC_WEIGHT, bold ? rxvt_fontprop::bold : base_prop.weight); 1492 FcPatternAddInteger (p, FC_WEIGHT, prop.weight);
1239 FcPatternAddInteger (p, FC_SLANT, base_prop.slant); 1493 FcPatternAddInteger (p, FC_SLANT, prop.slant);
1240 FcPatternAddBool (p, FC_MINSPACE, 1); 1494 FcPatternAddBool (p, FC_MINSPACE, 1);
1241 //FcPatternAddBool (p, FC_ANTIALIAS, 1); 1495 //FcPatternAddBool (p, FC_ANTIALIAS, 1);
1242 1496
1243 XftResult result; 1497 XftResult result;
1244 FcPattern *match = XftFontMatch (DISPLAY, DefaultScreen (DISPLAY), p, &result); 1498 FcPattern *match = XftFontMatch (DISPLAY, DefaultScreen (DISPLAY), p, &result);
1264#endif 1518#endif
1265 } 1519 }
1266 } 1520 }
1267 } 1521 }
1268 1522
1269 // if no bold font found, use a regular one 1523 /* we must return SOME font */
1270 if (bold) 1524 i = 0;
1271 return find_font (unicode);
1272 1525
1273 return 0; /* we must return SOME font */ 1526found:
1274} 1527 // found a font, cache it
1528 if (i < 255)
1529 {
1530 while (hi >= fmap.size ())
1531 fmap.push_back (0);
1275 1532
1533 if (!fmap[hi])
1534 {
1535 fmap[hi] = (pagemap *)new pagemap;
1536 memset (fmap[hi], 0xff, sizeof (pagemap));
1537 }
1276 1538
1539 (*fmap[hi])[unicode & 0xff] = i;
1540 }
1277 1541
1542 return i;
1543}
1544
1545
1546

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines