ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/defaultfont.C
Revision: 1.6
Committed: Wed Dec 17 22:29:03 2003 UTC (20 years, 5 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.5: +22 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*--------------------------------*-C-*---------------------------------*;
2     * File: defaultfont.C
3     *----------------------------------------------------------------------*
4     * Copyright (c) 2003 Marc Lehmann rxvt@plan9.de>
5     * - original version.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     *---------------------------------------------------------------------*/
21    
22     #include "../config.h"
23     #include "rxvt.h"
24     #include "defaultfont.h"
25    
26 pcg 1.2 #define DISPLAY r->Xdisplay
27     #define DRAWABLE r->TermWin.vt
28     #define GC r->TermWin.gc
29 pcg 1.1
30     const struct rxvt_fallback_font {
31     codeset cs;
32     const char *name;
33     } fallback_fonts[] = {
34     { CS_ISO8859_1, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-1" },
35     { CS_ISO8859_15, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-15" },
36     { CS_ISO8859_15, "-*-*-*-r-*--*-*-*-*-c-*-fcd8859-15" },
37    
38     #if ENCODING_EU
39     // cyrillic
40     { CS_KOI8_R, "-*-*-*-r-*--*-*-*-*-c-*-koi8-r" },
41     { CS_KOI8_U, "-*-*-*-r-*--*-*-*-*-c-*-koi8-u" },
42    
43     { CS_ISO8859_2, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-2" },
44     { CS_ISO8859_3, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-3" },
45     { CS_ISO8859_4, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-4" },
46     { CS_ISO8859_5, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-5" },
47     { CS_ISO8859_6, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-6" },
48     { CS_ISO8859_7, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-7" },
49     { CS_ISO8859_8, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-8" },
50     { CS_ISO8859_9, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-9" },
51     { CS_ISO8859_10, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-10" },
52     { CS_ISO8859_11, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-11" },
53     { CS_ISO8859_13, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-13" },
54     { CS_ISO8859_14, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-14" },
55     { CS_ISO8859_16, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-16" },
56     #endif
57    
58     // japanese
59     #if ENCODING_JP || ENCODING_JP_EXT
60     # if XFT
61     // prefer xft for complex scripts
62     { CS_UNICODE, "xft:Kochi Gothic" },
63     # endif
64     { CS_JIS0201_1976_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0201*-0" },
65     { CS_JIS0208_1983_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0208*-0" },
66     { CS_JIS0212_1990_0, "-*-mincho-*-r-*--*-*-*-*-c-*-jisx0212*-0" },
67     #endif
68    
69     #if ENCODING_CN || ENCODING_CN_EXT
70     # if XFT
71     { CS_BIG5_EXT, "xft:AR PL Mingti2L Big5" },
72     { CS_BIG5_EXT, "xft:AR PL KaitiM Big5" },
73     { CS_GB2312_1980_0, "xft:AR PL KaitiM GB" },
74     { CS_GB2312_1980_0, "xft:AR PL SungtiL GB" },
75     # endif
76     { CS_CNS11643_1992_1, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-1" },
77     { CS_CNS11643_1992_2, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-2" },
78     { CS_CNS11643_1992_3, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-3" },
79     { CS_CNS11643_1992_4, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-4" },
80     { CS_CNS11643_1992_5, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-5" },
81     { CS_CNS11643_1992_6, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-6" },
82     { CS_CNS11643_1992_7, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-7" },
83     { CS_CNS11643_1992_F, "-*-*-*-r-*-*-*-*-*-*-c-*-cns11643.1992-f" },
84     #endif
85    
86     #if XFT
87     { CS_UNICODE, "xft:Andale Mono" },
88     { CS_UNICODE, "xft:Arial Unicode MS" },
89     #endif
90     { CS_UNICODE, "-*-lucidatypewriter-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
91     { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
92     { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
93     { CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
94    
95     { CS_UNKNOWN, 0 }
96     };
97    
98     /////////////////////////////////////////////////////////////////////////////
99    
100     static void *enc_buf;
101     static uint32_t enc_len;
102    
103     static inline void *
104     get_enc_buf (int len)
105     {
106     if (len > enc_len)
107     {
108     free (enc_buf);
109     enc_buf = malloc (len);
110     }
111    
112     return enc_buf;
113     }
114    
115     static const char *
116     enc_char (const text_t *text, int len, codeset cs, bool &zero)
117     {
118     uint8_t *buf = (uint8_t *)get_enc_buf (len);
119    
120     while (len--)
121     {
122     uint32_t c = FROM_UNICODE (cs, *text++);
123    
124     if (c == NOCHAR)
125     {
126     c = 0;
127     zero = true;
128     }
129    
130     *buf++ = c;
131     }
132    
133     return (const char *)enc_buf;
134     }
135    
136     static const XChar2b *
137     enc_xchar2b (const text_t *text, int len, codeset cs, bool &zero)
138     {
139     XChar2b *buf = (XChar2b *)get_enc_buf (len * sizeof (XChar2b));
140    
141     while (len--)
142     {
143     uint32_t c = FROM_UNICODE (cs, *text++);
144    
145     if (c == NOCHAR)
146     {
147     c = 0;
148     zero = true;
149     }
150    
151     buf->byte1 = c >> 8;
152     buf->byte2 = c;
153     buf++;
154     }
155    
156     return (XChar2b *)enc_buf;
157     }
158    
159     /////////////////////////////////////////////////////////////////////////////
160    
161     void
162     rxvt_font::clear_rect (int x, int y, int w, int h, int color)
163     {
164     if (color == Color_bg)
165     XClearArea (DISPLAY, DRAWABLE, x, y, w, h, FALSE);
166     else if (color >= 0)
167     {
168 pcg 1.2 XSetForeground (DISPLAY, GC, r->PixColors[color]);
169 pcg 1.1 XFillRectangle (DISPLAY, DRAWABLE, GC, x, y, w, h);
170     }
171     }
172    
173 pcg 1.3 static const char *linedraw_cmds[128] = {
174     "1hH", "2hH", "1vV", "2vV",
175     0, 0, 0, 0,
176     0, 0, 0, 0,
177     "1HV", "2H1V", "1H2V", "2HV",
178    
179     // 2510
180     "1hV", "2h1V", "1h2V", "2hV",
181     "1Hv", "2H1v", "1H2v", "2Hv",
182     "1hv", "2h1v", "1h2v", "2hv",
183     "1HvV", "2H1vV", "1HV2v", "1Hv2V",
184    
185     // 2520
186     "1H2vV", "2Hv1V", "2HV1v", "2HvV",
187     "1hvV", "2h1vV", "1hV2v", "1hv2V",
188     "1h2vV", "2hv1V", "1v2hV", "2hvV",
189     "1hHV", "2h1HV", "2H1hV", "2hH1V",
190    
191     // 2530
192     "1hH2V", "2hV1H", "1h2HV", "2hHV",
193     "1hHv", "1vH2h", "1hv2H", "1v2hH",
194     "1hH2v", "1H2hv", "1h2Hv", "2hHv",
195     "1hHvV", "1vVH2h", "1hvV2H", "1vV2hH",
196    
197     // 2540
198     "1hHV2v", "1hHv2V", "1hH2vV", "1HV2hv",
199     "1hV2Hv", "1Hv2hV", "1hv2HV", "1V2hHv",
200     "1v2hHV", "1H2hvV", "1h2HvV", "2hHvV",
201     0, 0, 0, 0,
202    
203     // 2550
204     0, 0, 0, 0,
205     0, 0, 0, 0,
206     0, 0, 0, 0,
207     0, 0, 0, 0,
208    
209     // 2560
210     0, 0, 0, 0,
211     0, 0, 0, 0,
212     0, 0, 0, 0,
213     0, 0, 0, 0,
214    
215     // 2570
216     0, "1a", "1b", "1ab",
217     "1h", "1v", "1H", "1V",
218     "2h", "2v", "2H", "2V",
219     "1h2H", "1v2V", "1H2h", "1V2v"
220    
221     // to be done
222     };
223    
224 pcg 1.1 struct rxvt_font_default : rxvt_font {
225     bool load (int maxheight)
226     {
227     width = 1; height = 1;
228     ascent = 1; descent = 0;
229    
230     return true;
231     }
232    
233     bool has_codepoint (uint32_t unicode)
234     {
235 pcg 1.3 if (unicode <= 0x001f)
236     return true;
237     if (unicode >= 0x0080 && unicode <= 0x009f)
238     return true;
239    
240     if (unicode >= 0x2500 && unicode <= 0x257f
241     && linedraw_cmds[unicode - 0x2500])
242 pcg 1.1 return true;
243    
244     switch (unicode)
245     {
246     case ZERO_WIDTH_CHAR:
247     return true;
248     }
249    
250     return false;
251     }
252    
253     void draw (int x, int y,
254     const text_t *text, int len,
255     int fg, int bg);
256     };
257    
258     void
259     rxvt_font_default::draw (int x, int y,
260     const text_t *text, int len,
261     int fg, int bg)
262     {
263 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
264 pcg 1.1
265 pcg 1.3 XSetForeground (DISPLAY, GC, r->PixColors[fg]);
266    
267 pcg 1.1 while (len--)
268     {
269 pcg 1.3 text_t t = *text++;
270    
271     if (t >= 0x2500 & t <= 0x2580 && linedraw_cmds[t - 0x2500])
272 pcg 1.1 {
273 pcg 1.3 const char *p = linedraw_cmds[t - 0x2500];
274    
275 pcg 1.4 int x0 = x, x1 = x + r->TermWin.fwidth / 2, x2 = x + r->TermWin.fwidth ;
276     int y0 = y, y1 = y + r->TermWin.fheight / 2, y2 = y + r->TermWin.fheight;
277 pcg 1.3
278     XGCValues gcv;
279    
280     while (*p)
281     {
282     switch (*p++)
283     {
284     case '1':
285     gcv.line_width = 0;
286     XChangeGC (DISPLAY, GC, GCLineWidth, &gcv);
287     break;
288    
289     case '2':
290     gcv.line_width = 2;
291     XChangeGC (DISPLAY, GC, GCLineWidth, &gcv);
292     break;
293    
294     case 'h': XDrawLine (DISPLAY, DRAWABLE, GC, x0, y1, x1, y1); break;
295     case 'H': XDrawLine (DISPLAY, DRAWABLE, GC, x1, y1, x2, y1); break;
296     case 'v': XDrawLine (DISPLAY, DRAWABLE, GC, x1, y0, x1, y1); break;
297     case 'V': XDrawLine (DISPLAY, DRAWABLE, GC, x1, y1, x1, y2); break;
298     case 'a': XDrawLine (DISPLAY, DRAWABLE, GC, x0, y2, x2, y0); break;
299     case 'b': XDrawLine (DISPLAY, DRAWABLE, GC, x0, y0, x2, y2); break;
300     }
301     }
302    
303     gcv.line_width = 0;
304     XChangeGC (DISPLAY, GC, GCLineWidth, &gcv);
305 pcg 1.1 }
306 pcg 1.3 else
307     switch (*text++)
308     {
309     case NOCHAR:
310     case ZERO_WIDTH_CHAR:
311     break;
312     default:
313     XDrawRectangle (DISPLAY, DRAWABLE, GC, x + 2, y + 2, r->TermWin.fwidth - 5, r->TermWin.fheight - 5);
314     }
315 pcg 1.1
316 pcg 1.2 x += r->TermWin.fwidth;
317 pcg 1.1 }
318     }
319    
320     /////////////////////////////////////////////////////////////////////////////
321    
322     struct rxvt_font_x11 : rxvt_font {
323     rxvt_font_x11 () { f = 0; }
324    
325     void clear ();
326    
327     bool load (int maxheight);
328    
329     bool has_codepoint (uint32_t unicode);
330    
331     void draw (int x, int y,
332     const text_t *text, int len,
333     int fg, int bg);
334    
335     XFontStruct *f;
336     codeset cs;
337     bool enc2b, encm;
338    
339     const char *get_property (const char *property, const char *repl) const;
340     };
341    
342     const char *
343     rxvt_font_x11::get_property (const char *property, const char *repl) const
344     {
345     unsigned long value;
346    
347     if (XGetFontProperty (f, XInternAtom (DISPLAY, property, 0), &value))
348     return XGetAtomName (DISPLAY, value);
349     else
350     return repl;
351     }
352    
353     bool
354     rxvt_font_x11::load (int maxheight)
355     {
356     clear ();
357    
358 pcg 1.6 char **list;
359     int count;
360     XFontStruct *info;
361     list = XListFontsWithInfo (DISPLAY, name, 128, &count, &info);
362    
363     if (!list)
364     return false;
365    
366     XFontStruct *best = 0;
367     for (int i = 0; i < count; i++)
368     {
369     XFontStruct *f = info + i;
370     if (f->ascent + f->descent <= maxheight) // weed out too large fonts
371     if (!best // compare against best found so far
372     || best->ascent + best->descent < f->ascent + f->descent)
373     best = f;
374     }
375    
376     set_name (strdup (list[best - info]));
377    
378     XFreeFontInfo (list, info, count);
379    
380 pcg 1.1 f = XLoadQueryFont (DISPLAY, name);
381    
382     if (!f)
383     return false;
384    
385     unsigned long value;
386    
387     const char *registry = get_property ("CHARSET_REGISTRY", 0);
388     const char *encoding = get_property ("CHARSET_ENCODING", 0);
389    
390     if (registry && encoding)
391     {
392     char charset[64];
393     snprintf (charset, 64, "%s-%s", registry, encoding);
394    
395     cs = codeset_from_name (charset);
396     }
397     else
398     {
399     const char *charset = get_property ("FONT", 0);
400    
401     if (!charset)
402     charset = name;
403    
404     int count = 13;
405     while (*charset)
406     if (*charset++ == '-' && !--count)
407     break;
408    
409     cs = codeset_from_name (charset);
410     }
411    
412     if (cs == CS_UNICODE)
413     cs = CS_UNICODE_16; // X11 can have a max. of 65536 chars per font
414    
415     encm = f->min_byte1 != 0 || f->max_byte1 != 0;
416     enc2b = encm || f->max_char_or_byte2 > 255;
417    
418     ascent = f->ascent;
419     descent = f->descent;
420     height = ascent + descent;
421    
422     prop = false;
423    
424     if (f->min_bounds.width == f->max_bounds.width)
425     width = f->min_bounds.width;
426     else if (f->per_char == NULL)
427     width = f->max_bounds.width;
428     else
429     {
430     prop = true;
431    
432     int N = f->max_char_or_byte2 - f->min_char_or_byte2;
433    
434     if (encm)
435     N += (f->max_byte1 - f->min_byte1)
436     * (f->max_char_or_byte2 - f->min_char_or_byte2 + 1);
437    
438     while (N)
439     {
440     if (f->per_char[N].width > width)
441     width = f->per_char[N].width;
442    
443     --N;
444     }
445     }
446    
447     if (cs == CS_UNKNOWN)
448     {
449     fprintf (stderr, "unable to deduce codeset, ignoring font '%s'\n", name);
450    
451     clear ();
452    
453     return false;
454     }
455    
456     return true;
457     }
458    
459     void
460     rxvt_font_x11::clear ()
461     {
462     if (f)
463     {
464     XFreeFont (DISPLAY, f);
465     f = 0;
466     }
467     }
468    
469     bool
470     rxvt_font_x11::has_codepoint (uint32_t unicode)
471     {
472     uint32_t ch = FROM_UNICODE (cs, unicode);
473    
474     if (ch == NOCHAR)
475     return false;
476    
477     /* check wether the character exists in _this_ font. horrible. */
478     XCharStruct *xcs;
479    
480     if (encm)
481     {
482     int byte1 = ch >> 8;
483     int byte2 = ch & 255;
484    
485     if (byte1 < f->min_byte1 || byte1 > f->max_byte1
486     || byte2 < f->min_char_or_byte2 || byte2 > f->max_char_or_byte2)
487     return false;
488    
489     if (!f->per_char)
490     return true;
491    
492     int D = f->max_char_or_byte2 - f->min_char_or_byte2 + 1;
493     int N = (byte1 - f->min_byte1) * D + byte2 - f->min_char_or_byte2;
494    
495     xcs = f->per_char + N;
496     }
497     else
498     {
499     if (ch < f->min_char_or_byte2 || ch > f->max_char_or_byte2)
500     return false;
501    
502     if (!f->per_char)
503     return true;
504    
505     xcs = f->per_char + (ch - f->min_char_or_byte2);
506     }
507    
508     if (xcs->lbearing == 0 && xcs->rbearing == 0 && xcs->width == 0
509     && xcs->ascent == 0 && xcs->descent == 0)
510     return false;
511    
512     return true;
513     }
514    
515     void
516     rxvt_font_x11::draw (int x, int y,
517     const text_t *text, int len,
518     int fg, int bg)
519     {
520     // this looks like a mess /.
521     // and it is a mess /.
522     // yet we are trying to be perfect /.
523     // but the result still isn't perfect /.
524    
525     bool slow = prop
526 pcg 1.2 || width != r->TermWin.fwidth
527     || height != r->TermWin.fheight;
528 pcg 1.1
529 pcg 1.2 int base = r->TermWin.fbase;
530 pcg 1.1
531     XGCValues v;
532 pcg 1.2 v.foreground = r->PixColors[fg];
533     v.background = r->PixColors[bg];
534 pcg 1.1 v.font = f->fid;
535    
536     if (enc2b)
537     {
538     const XChar2b *xc = enc_xchar2b (text, len, cs, slow);
539    
540     if (bg == Color_bg && !slow)
541     {
542     XChangeGC (DISPLAY, GC, GCForeground | GCBackground | GCFont, &v);
543     XDrawImageString16 (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
544     }
545     else
546     {
547 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
548 pcg 1.1
549     XChangeGC (DISPLAY, GC, GCForeground | GCFont, &v);
550    
551     if (slow)
552     {
553     do
554     {
555     if (xc->byte1 || xc->byte2)
556     XDrawString16 (DISPLAY, DRAWABLE, GC, x, y + base, xc, 1);
557    
558 pcg 1.2 x += r->TermWin.fwidth;
559 pcg 1.1 xc++; len--;
560     }
561     while (len);
562     }
563     else
564     XDrawString16 (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
565     }
566     }
567     else
568     {
569     const char *xc = enc_char (text, len, cs, slow);
570    
571     if (bg == Color_bg && !slow)
572     {
573     XChangeGC (DISPLAY, GC, GCForeground | GCBackground | GCFont, &v);
574     XDrawImageString (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
575     }
576     else
577     {
578 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
579 pcg 1.1
580     XChangeGC (DISPLAY, GC, GCForeground | GCFont, &v);
581    
582     if (slow)
583     {
584     do
585     {
586     if (*xc)
587     XDrawString (DISPLAY, DRAWABLE, GC, x, y + base, xc, 1);
588    
589 pcg 1.2 x += r->TermWin.fwidth;
590 pcg 1.1 xc++; len--;
591     }
592     while (len);
593     }
594     else
595     XDrawString (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
596     }
597     }
598     }
599    
600     /////////////////////////////////////////////////////////////////////////////
601    
602     #if XFT
603     #if 0
604     #define UNIBITS 21
605     //#define SWATHBITS (UNIBITS / 2 + 3) // minimum size for "full" tables
606     #define SWATHBITS 8
607     #endif
608    
609     struct rxvt_font_xft : rxvt_font {
610     #if 0
611     enum {
612     SWATHCOUNT = 1 << (21 - UNIBITS),
613     SWATHSIZE = 1 << (SWATHBITS - 5)
614     };
615     typedef uint32_t swath[SWATHSIZE];
616    
617     swath *cvr[SWATHCOUNT];
618     #endif
619    
620     #if 0
621     void gen_coverage_swath (unsigned int page);
622    
623     bool has_char (uint32_t ch)
624     {
625     unsigned int page = ch >> SWATHBITS;
626     unsigned int idx = ch & ((1 << SWATHBITS) - 1);
627    
628     if (page >= SWATHCOUNT)
629     return false;
630    
631     if (!cvr[page]) gen_coverage_swath (page);
632    
633     return cvr[page][idx >> 5] & (1 << (idx & 31));
634     }
635     #endif
636     rxvt_font_xft () { f = 0; d = 0; }
637    
638     void clear ();
639    
640     bool load (int maxheight);
641    
642     void draw (int x, int y,
643     const text_t *text, int len,
644     int fg, int bg);
645    
646     bool has_codepoint (uint32_t unicode);
647    
648     protected:
649     XftFont *f;
650     XftDraw *d;
651    
652     #if 0
653     virtual void populate_coverage_swath (uint32_t lo, uint32_t hi) = 0;
654     void set_swath (uint32_t ch)
655     {
656     cvr[ch >> SWATHBITS] |= 1 << (ch & ((1 << SWATHBITS) - 1));
657     }
658     #endif
659     };
660    
661     void
662     rxvt_font_xft::clear ()
663     {
664     if (f)
665     {
666 pcg 1.2 XftFontClose (DISPLAY, f);
667 pcg 1.1 f = 0;
668     }
669    
670     if (d)
671     {
672     XftDrawDestroy (d);
673     d = 0;
674     }
675    
676     #if 0
677     for (int i = 0; i < SWATHCOUNT; i++)
678     delete cvr[i];
679     #endif
680     }
681    
682     bool
683     rxvt_font_xft::load (int maxheight)
684     {
685     #if 0
686     for (int i = 0; i < SWATHCOUNT; i++)
687     cvr[i] = 0;
688     #endif
689    
690     clear ();
691    
692 pcg 1.2 f = XftFontOpenName (DISPLAY, DefaultScreen (DISPLAY), name);
693 pcg 1.1
694     if (!f)
695     return false;
696    
697     FT_Face face = XftLockFace (f);
698    
699     prop = !FT_IS_FIXED_WIDTH (face);
700    
701     int ftheight = 0;
702    
703     for (;;)
704     {
705     XGlyphInfo g1, g2;
706     FcChar8 c;
707    
708 pcg 1.2 c = 'i'; XftTextExtents8 (DISPLAY, f, &c, 1, &g1);
709     c = 'W'; XftTextExtents8 (DISPLAY, f, &c, 1, &g2);
710 pcg 1.1
711     prop = prop || g1.xOff != g2.xOff; // don't simply trust the font
712    
713     width = g2.xOff;
714     ascent = (face->size->metrics.ascender + 63) >> 6;
715     descent = (-face->size->metrics.descender + 63) >> 6;
716     height = ascent + descent;
717    
718     if (height <= maxheight || !maxheight)
719     break;
720    
721     if (ftheight)
722     {
723     // take smaller steps near the end
724     if (height > maxheight + 1) ftheight++;
725     if (height > maxheight + 2) ftheight++;
726     if (height > maxheight + 3) ftheight++;
727    
728     FT_Set_Pixel_Sizes (face, 0, ftheight -= height - maxheight);
729     }
730     else
731     FT_Set_Pixel_Sizes (face, 0, ftheight = maxheight);
732     }
733    
734     XftUnlockFace (f);
735    
736     return true;
737     }
738    
739     #if 0
740     void rxvt_font::gen_coverage_swath (unsigned int page)
741     {
742     cvr[page] = new swath;
743    
744     for (int i = 0; i < SWATHSIZE; i++)
745     cvr[page][i] = 0;
746    
747     populate_coverage_swath (cvr[page], page << SWATHBITS, ((page + 1) << SWATHBITS) - 1);
748     }
749     #endif
750    
751     bool
752     rxvt_font_xft::has_codepoint (uint32_t unicode)
753     {
754 pcg 1.2 return XftCharExists (DISPLAY, f, unicode);
755 pcg 1.1 }
756    
757     void
758     rxvt_font_xft::draw (int x, int y,
759     const text_t *text, int len,
760     int fg, int bg)
761     {
762     if (!d)
763 pcg 1.2 {
764     dR;
765     d = XftDrawCreate (DISPLAY, DRAWABLE, XVISUAL, XCMAP);
766     }
767 pcg 1.1
768     if (bg >= 0 && bg != Color_bg)
769 pcg 1.2 XftDrawRect (d, &r->PixColors[bg].c, x, y, r->TermWin.fwidth * len, r->TermWin.fheight);
770 pcg 1.1 else
771 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
772 pcg 1.1
773 pcg 1.2 if (!prop && width == r->TermWin.fwidth)
774 pcg 1.1 {
775     if (sizeof (text_t) == sizeof (FcChar16))
776 pcg 1.2 XftDrawString16 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar16 *)text, len);
777 pcg 1.1 else
778 pcg 1.2 XftDrawString32 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar32 *)text, len);
779 pcg 1.1 }
780     else
781     {
782     while (len)
783     {
784     if (*text != NOCHAR && *text != ' ')
785     {
786     if (sizeof (text_t) == sizeof (FcChar16))
787 pcg 1.2 XftDrawString16 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar16 *)text, 1);
788 pcg 1.1 else
789 pcg 1.2 XftDrawString32 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar32 *)text, 1);
790 pcg 1.1 }
791    
792 pcg 1.2 x += r->TermWin.fwidth;
793 pcg 1.1 text++;
794     len--;
795     }
796     }
797     }
798     #endif
799    
800     /////////////////////////////////////////////////////////////////////////////
801    
802 pcg 1.2 rxvt_fontset::rxvt_fontset (rxvt_t r)
803 pcg 1.1 #ifdef EXPLICIT_CONTEXT
804 pcg 1.2 : r(r)
805 pcg 1.1 #endif
806     {
807     clear ();
808     }
809    
810     rxvt_fontset::~rxvt_fontset ()
811     {
812     clear ();
813     }
814    
815     void
816     rxvt_fontset::clear ()
817     {
818     for (rxvt_font **i = fonts.begin (); i != fonts.end(); i++)
819     FONT_UNREF (*i);
820    
821     fonts.clear ();
822     base_id = 0;
823     height = 0x7fffffff;
824    
825     fallback = fallback_fonts;
826     }
827    
828     rxvt_font *
829     rxvt_fontset::new_font (const char *name, codeset cs)
830     {
831     rxvt_font *f;
832    
833     if (!name || !*name)
834     {
835     name = "";
836     f = new rxvt_font_default;
837     }
838     #if XFT
839     else if (!strncmp (name, "xft:", 4))
840     {
841     name += 4;
842     f = new rxvt_font_xft;
843     }
844     #endif
845     else if (!strncmp (name, "x:", 2))
846     {
847     name += 2;
848     f = new rxvt_font_x11;
849     }
850     else
851     f = new rxvt_font_x11;
852    
853 pcg 1.2 f->set_term (r);
854 pcg 1.1 f->set_name (strdup (name));
855    
856     f->cs = cs;
857     f->loaded = false;
858    
859     return f;
860     }
861    
862     /////////////////////////////////////////////////////////////////////////////
863    
864     void
865     rxvt_fontset::add_fonts (const char *desc)
866     {
867     if (desc)
868     {
869     char buf[512];
870     const char *end;
871    
872     do
873     {
874     while (*desc <= ' ') desc++;
875    
876     if (*desc == '[')
877     {
878     fprintf (stderr, "extra font parameters not yet supported, skipping.\n");
879    
880     const char *extra = desc++;
881    
882     desc = strchr (desc, ']');
883    
884     if (!desc)
885     {
886     fprintf (stderr, "ERROR: opening '[' without closing ']' in font specification.\n");
887     break;
888     }
889    
890     desc++;
891     while (*desc <= ' ') desc++;
892     }
893    
894     end = strchr (desc, ',');
895     if (!end)
896     end = desc + strlen (desc);
897    
898     if (end - desc < 511)
899     {
900     strncpy (buf, desc, end - desc);
901     buf[end - desc] = 0;
902    
903     fonts.push_back (new_font (buf, CS_UNICODE));
904     }
905    
906     desc = end + 1;
907     }
908     while (*end);
909     }
910     }
911    
912     bool
913     rxvt_fontset::realize_font (int i)
914     {
915     if (fonts[i]->loaded)
916     return true;
917    
918 pcg 1.5 fonts[i]->loaded = true;
919 pcg 1.1
920 pcg 1.5 if (!fonts[i]->load (height))
921     {
922     fonts[i]->cs = CS_UNKNOWN;
923     return false;
924     }
925 pcg 1.1
926 pcg 1.5 return true;
927 pcg 1.1 }
928    
929     void
930     rxvt_fontset::populate (const char *desc)
931     {
932     clear ();
933    
934     fonts.push_back (new_font (0, CS_UNICODE));
935     realize_font (0);
936    
937     add_fonts (desc);
938    
939     if (!base_id)
940     base_id = 1;
941    
942     // we currently need a base-font, no matter what
943     if (fonts.size () <= base_id)
944     {
945     add_fonts ("fixed");
946     base_id = 1;
947     }
948    
949     if (fonts.size () <= base_id || !realize_font (base_id))
950     {
951     fprintf (stderr, "unable to load a base font, please provide one using -fn fontname\n");
952     exit (1);
953     }
954    
955     height = fonts[base_id]->height;
956    
957     /*add_fonts ("-efont-fixed-medium-r-normal-*-14-*-*-*-*-*-iso10646-1,"*/
958     }
959    
960     int
961     rxvt_fontset::find_font (uint32_t unicode)
962     {
963     for (int i = 0; i < fonts.size (); i++)
964     {
965     rxvt_font *f = fonts[i];
966    
967     if (!f->loaded)
968     {
969     if (FROM_UNICODE (f->cs, unicode) == NOCHAR)
970     goto next_font;
971    
972     if (!realize_font (i))
973 pcg 1.5 goto next_font;
974 pcg 1.1 }
975    
976 pcg 1.5 if (f->cs != CS_UNKNOWN && f->has_codepoint (unicode))
977 pcg 1.1 return i;
978    
979     next_font:
980     if (i == fonts.size () - 1 && fallback->name)
981     {
982     fonts.push_back (new_font (fallback->name, fallback->cs));
983     fallback++;
984 pcg 1.5 i = 0;
985 pcg 1.1 }
986     }
987    
988     return 0; /* we must return SOME font */
989     }
990    
991    
992