ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/defaultfont.C
Revision: 1.4
Committed: Sat Nov 29 18:42:07 2003 UTC (20 years, 6 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +2 -5 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     f = XLoadQueryFont (DISPLAY, name);
359    
360     if (!f)
361     return false;
362    
363     unsigned long value;
364    
365     const char *registry = get_property ("CHARSET_REGISTRY", 0);
366     const char *encoding = get_property ("CHARSET_ENCODING", 0);
367    
368     if (registry && encoding)
369     {
370     char charset[64];
371     snprintf (charset, 64, "%s-%s", registry, encoding);
372    
373     cs = codeset_from_name (charset);
374     }
375     else
376     {
377     const char *charset = get_property ("FONT", 0);
378    
379     if (!charset)
380     charset = name;
381    
382     int count = 13;
383     while (*charset)
384     if (*charset++ == '-' && !--count)
385     break;
386    
387     cs = codeset_from_name (charset);
388     }
389    
390     if (cs == CS_UNICODE)
391     cs = CS_UNICODE_16; // X11 can have a max. of 65536 chars per font
392    
393     encm = f->min_byte1 != 0 || f->max_byte1 != 0;
394     enc2b = encm || f->max_char_or_byte2 > 255;
395    
396     ascent = f->ascent;
397     descent = f->descent;
398     height = ascent + descent;
399    
400     prop = false;
401    
402     if (f->min_bounds.width == f->max_bounds.width)
403     width = f->min_bounds.width;
404     else if (f->per_char == NULL)
405     width = f->max_bounds.width;
406     else
407     {
408     prop = true;
409    
410     int N = f->max_char_or_byte2 - f->min_char_or_byte2;
411    
412     if (encm)
413     N += (f->max_byte1 - f->min_byte1)
414     * (f->max_char_or_byte2 - f->min_char_or_byte2 + 1);
415    
416     while (N)
417     {
418     if (f->per_char[N].width > width)
419     width = f->per_char[N].width;
420    
421     --N;
422     }
423     }
424    
425     if (cs == CS_UNKNOWN)
426     {
427     fprintf (stderr, "unable to deduce codeset, ignoring font '%s'\n", name);
428    
429     clear ();
430    
431     return false;
432     }
433    
434     return true;
435     }
436    
437     void
438     rxvt_font_x11::clear ()
439     {
440     if (f)
441     {
442     XFreeFont (DISPLAY, f);
443     f = 0;
444     }
445     }
446    
447     bool
448     rxvt_font_x11::has_codepoint (uint32_t unicode)
449     {
450     uint32_t ch = FROM_UNICODE (cs, unicode);
451    
452     if (ch == NOCHAR)
453     return false;
454    
455     /* check wether the character exists in _this_ font. horrible. */
456     XCharStruct *xcs;
457    
458     if (encm)
459     {
460     int byte1 = ch >> 8;
461     int byte2 = ch & 255;
462    
463     if (byte1 < f->min_byte1 || byte1 > f->max_byte1
464     || byte2 < f->min_char_or_byte2 || byte2 > f->max_char_or_byte2)
465     return false;
466    
467     if (!f->per_char)
468     return true;
469    
470     int D = f->max_char_or_byte2 - f->min_char_or_byte2 + 1;
471     int N = (byte1 - f->min_byte1) * D + byte2 - f->min_char_or_byte2;
472    
473     xcs = f->per_char + N;
474     }
475     else
476     {
477     if (ch < f->min_char_or_byte2 || ch > f->max_char_or_byte2)
478     return false;
479    
480     if (!f->per_char)
481     return true;
482    
483     xcs = f->per_char + (ch - f->min_char_or_byte2);
484     }
485    
486     if (xcs->lbearing == 0 && xcs->rbearing == 0 && xcs->width == 0
487     && xcs->ascent == 0 && xcs->descent == 0)
488     return false;
489    
490     return true;
491     }
492    
493     void
494     rxvt_font_x11::draw (int x, int y,
495     const text_t *text, int len,
496     int fg, int bg)
497     {
498     // this looks like a mess /.
499     // and it is a mess /.
500     // yet we are trying to be perfect /.
501     // but the result still isn't perfect /.
502    
503     bool slow = prop
504 pcg 1.2 || width != r->TermWin.fwidth
505     || height != r->TermWin.fheight;
506 pcg 1.1
507 pcg 1.2 int base = r->TermWin.fbase;
508 pcg 1.1
509     XGCValues v;
510 pcg 1.2 v.foreground = r->PixColors[fg];
511     v.background = r->PixColors[bg];
512 pcg 1.1 v.font = f->fid;
513    
514     if (enc2b)
515     {
516     const XChar2b *xc = enc_xchar2b (text, len, cs, slow);
517    
518     if (bg == Color_bg && !slow)
519     {
520     XChangeGC (DISPLAY, GC, GCForeground | GCBackground | GCFont, &v);
521     XDrawImageString16 (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
522     }
523     else
524     {
525 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
526 pcg 1.1
527     XChangeGC (DISPLAY, GC, GCForeground | GCFont, &v);
528    
529     if (slow)
530     {
531     do
532     {
533     if (xc->byte1 || xc->byte2)
534     XDrawString16 (DISPLAY, DRAWABLE, GC, x, y + base, xc, 1);
535    
536 pcg 1.2 x += r->TermWin.fwidth;
537 pcg 1.1 xc++; len--;
538     }
539     while (len);
540     }
541     else
542     XDrawString16 (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
543     }
544     }
545     else
546     {
547     const char *xc = enc_char (text, len, cs, slow);
548    
549     if (bg == Color_bg && !slow)
550     {
551     XChangeGC (DISPLAY, GC, GCForeground | GCBackground | GCFont, &v);
552     XDrawImageString (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
553     }
554     else
555     {
556 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
557 pcg 1.1
558     XChangeGC (DISPLAY, GC, GCForeground | GCFont, &v);
559    
560     if (slow)
561     {
562     do
563     {
564     if (*xc)
565     XDrawString (DISPLAY, DRAWABLE, GC, x, y + base, xc, 1);
566    
567 pcg 1.2 x += r->TermWin.fwidth;
568 pcg 1.1 xc++; len--;
569     }
570     while (len);
571     }
572     else
573     XDrawString (DISPLAY, DRAWABLE, GC, x, y + base, xc, len);
574     }
575     }
576     }
577    
578     /////////////////////////////////////////////////////////////////////////////
579    
580     #if XFT
581     #if 0
582     #define UNIBITS 21
583     //#define SWATHBITS (UNIBITS / 2 + 3) // minimum size for "full" tables
584     #define SWATHBITS 8
585     #endif
586    
587     struct rxvt_font_xft : rxvt_font {
588     #if 0
589     enum {
590     SWATHCOUNT = 1 << (21 - UNIBITS),
591     SWATHSIZE = 1 << (SWATHBITS - 5)
592     };
593     typedef uint32_t swath[SWATHSIZE];
594    
595     swath *cvr[SWATHCOUNT];
596     #endif
597    
598     #if 0
599     void gen_coverage_swath (unsigned int page);
600    
601     bool has_char (uint32_t ch)
602     {
603     unsigned int page = ch >> SWATHBITS;
604     unsigned int idx = ch & ((1 << SWATHBITS) - 1);
605    
606     if (page >= SWATHCOUNT)
607     return false;
608    
609     if (!cvr[page]) gen_coverage_swath (page);
610    
611     return cvr[page][idx >> 5] & (1 << (idx & 31));
612     }
613     #endif
614     rxvt_font_xft () { f = 0; d = 0; }
615    
616     void clear ();
617    
618     bool load (int maxheight);
619    
620     void draw (int x, int y,
621     const text_t *text, int len,
622     int fg, int bg);
623    
624     bool has_codepoint (uint32_t unicode);
625    
626     protected:
627     XftFont *f;
628     XftDraw *d;
629    
630     #if 0
631     virtual void populate_coverage_swath (uint32_t lo, uint32_t hi) = 0;
632     void set_swath (uint32_t ch)
633     {
634     cvr[ch >> SWATHBITS] |= 1 << (ch & ((1 << SWATHBITS) - 1));
635     }
636     #endif
637     };
638    
639     void
640     rxvt_font_xft::clear ()
641     {
642     if (f)
643     {
644 pcg 1.2 XftFontClose (DISPLAY, f);
645 pcg 1.1 f = 0;
646     }
647    
648     if (d)
649     {
650     XftDrawDestroy (d);
651     d = 0;
652     }
653    
654     #if 0
655     for (int i = 0; i < SWATHCOUNT; i++)
656     delete cvr[i];
657     #endif
658     }
659    
660     bool
661     rxvt_font_xft::load (int maxheight)
662     {
663     #if 0
664     for (int i = 0; i < SWATHCOUNT; i++)
665     cvr[i] = 0;
666     #endif
667    
668     clear ();
669    
670 pcg 1.2 f = XftFontOpenName (DISPLAY, DefaultScreen (DISPLAY), name);
671 pcg 1.1
672     if (!f)
673     return false;
674    
675     FT_Face face = XftLockFace (f);
676    
677     prop = !FT_IS_FIXED_WIDTH (face);
678    
679     int ftheight = 0;
680    
681     for (;;)
682     {
683     XGlyphInfo g1, g2;
684     FcChar8 c;
685    
686 pcg 1.2 c = 'i'; XftTextExtents8 (DISPLAY, f, &c, 1, &g1);
687     c = 'W'; XftTextExtents8 (DISPLAY, f, &c, 1, &g2);
688 pcg 1.1
689     prop = prop || g1.xOff != g2.xOff; // don't simply trust the font
690    
691     width = g2.xOff;
692     ascent = (face->size->metrics.ascender + 63) >> 6;
693     descent = (-face->size->metrics.descender + 63) >> 6;
694     height = ascent + descent;
695    
696     if (height <= maxheight || !maxheight)
697     break;
698    
699     if (ftheight)
700     {
701     // take smaller steps near the end
702     if (height > maxheight + 1) ftheight++;
703     if (height > maxheight + 2) ftheight++;
704     if (height > maxheight + 3) ftheight++;
705    
706     FT_Set_Pixel_Sizes (face, 0, ftheight -= height - maxheight);
707     }
708     else
709     FT_Set_Pixel_Sizes (face, 0, ftheight = maxheight);
710     }
711    
712     XftUnlockFace (f);
713    
714     return true;
715     }
716    
717     #if 0
718     void rxvt_font::gen_coverage_swath (unsigned int page)
719     {
720     cvr[page] = new swath;
721    
722     for (int i = 0; i < SWATHSIZE; i++)
723     cvr[page][i] = 0;
724    
725     populate_coverage_swath (cvr[page], page << SWATHBITS, ((page + 1) << SWATHBITS) - 1);
726     }
727     #endif
728    
729     bool
730     rxvt_font_xft::has_codepoint (uint32_t unicode)
731     {
732 pcg 1.2 return XftCharExists (DISPLAY, f, unicode);
733 pcg 1.1 }
734    
735     void
736     rxvt_font_xft::draw (int x, int y,
737     const text_t *text, int len,
738     int fg, int bg)
739     {
740     if (!d)
741 pcg 1.2 {
742     dR;
743     d = XftDrawCreate (DISPLAY, DRAWABLE, XVISUAL, XCMAP);
744     }
745 pcg 1.1
746     if (bg >= 0 && bg != Color_bg)
747 pcg 1.2 XftDrawRect (d, &r->PixColors[bg].c, x, y, r->TermWin.fwidth * len, r->TermWin.fheight);
748 pcg 1.1 else
749 pcg 1.2 clear_rect (x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
750 pcg 1.1
751 pcg 1.2 if (!prop && width == r->TermWin.fwidth)
752 pcg 1.1 {
753     if (sizeof (text_t) == sizeof (FcChar16))
754 pcg 1.2 XftDrawString16 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar16 *)text, len);
755 pcg 1.1 else
756 pcg 1.2 XftDrawString32 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar32 *)text, len);
757 pcg 1.1 }
758     else
759     {
760     while (len)
761     {
762     if (*text != NOCHAR && *text != ' ')
763     {
764     if (sizeof (text_t) == sizeof (FcChar16))
765 pcg 1.2 XftDrawString16 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar16 *)text, 1);
766 pcg 1.1 else
767 pcg 1.2 XftDrawString32 (d, &r->PixColors[fg].c, f, x, y + r->TermWin.fbase, (const FcChar32 *)text, 1);
768 pcg 1.1 }
769    
770 pcg 1.2 x += r->TermWin.fwidth;
771 pcg 1.1 text++;
772     len--;
773     }
774     }
775     }
776     #endif
777    
778     /////////////////////////////////////////////////////////////////////////////
779    
780 pcg 1.2 rxvt_fontset::rxvt_fontset (rxvt_t r)
781 pcg 1.1 #ifdef EXPLICIT_CONTEXT
782 pcg 1.2 : r(r)
783 pcg 1.1 #endif
784     {
785     clear ();
786     }
787    
788     rxvt_fontset::~rxvt_fontset ()
789     {
790     clear ();
791     }
792    
793     void
794     rxvt_fontset::clear ()
795     {
796     for (rxvt_font **i = fonts.begin (); i != fonts.end(); i++)
797     FONT_UNREF (*i);
798    
799     fonts.clear ();
800     base_id = 0;
801     height = 0x7fffffff;
802    
803     fallback = fallback_fonts;
804     }
805    
806     rxvt_font *
807     rxvt_fontset::new_font (const char *name, codeset cs)
808     {
809     rxvt_font *f;
810    
811     if (!name || !*name)
812     {
813     name = "";
814     f = new rxvt_font_default;
815     }
816     #if XFT
817     else if (!strncmp (name, "xft:", 4))
818     {
819     name += 4;
820     f = new rxvt_font_xft;
821     }
822     #endif
823     else if (!strncmp (name, "x:", 2))
824     {
825     name += 2;
826     f = new rxvt_font_x11;
827     }
828     else
829     f = new rxvt_font_x11;
830    
831 pcg 1.2 f->set_term (r);
832 pcg 1.1 f->set_name (strdup (name));
833    
834     f->cs = cs;
835     f->loaded = false;
836    
837     return f;
838     }
839    
840     /////////////////////////////////////////////////////////////////////////////
841    
842     void
843     rxvt_fontset::add_fonts (const char *desc)
844     {
845     if (desc)
846     {
847     char buf[512];
848     const char *end;
849    
850     do
851     {
852     while (*desc <= ' ') desc++;
853    
854     if (*desc == '[')
855     {
856     fprintf (stderr, "extra font parameters not yet supported, skipping.\n");
857    
858     const char *extra = desc++;
859    
860     desc = strchr (desc, ']');
861    
862     if (!desc)
863     {
864     fprintf (stderr, "ERROR: opening '[' without closing ']' in font specification.\n");
865     break;
866     }
867    
868     desc++;
869     while (*desc <= ' ') desc++;
870     }
871    
872     end = strchr (desc, ',');
873     if (!end)
874     end = desc + strlen (desc);
875    
876     if (end - desc < 511)
877     {
878     strncpy (buf, desc, end - desc);
879     buf[end - desc] = 0;
880    
881     fonts.push_back (new_font (buf, CS_UNICODE));
882     }
883    
884     desc = end + 1;
885     }
886     while (*end);
887     }
888     }
889    
890     bool
891     rxvt_fontset::realize_font (int i)
892     {
893     if (fonts[i]->loaded)
894     return true;
895    
896     if (fonts[i]->load (height))
897     return fonts[i]->loaded = true;
898    
899     delete fonts[i];
900     fonts.erase (fonts.begin () + i);
901    
902     return false;
903     }
904    
905     void
906     rxvt_fontset::populate (const char *desc)
907     {
908     clear ();
909    
910     fonts.push_back (new_font (0, CS_UNICODE));
911     realize_font (0);
912    
913     add_fonts (desc);
914    
915     if (!base_id)
916     base_id = 1;
917    
918     // we currently need a base-font, no matter what
919     if (fonts.size () <= base_id)
920     {
921     add_fonts ("fixed");
922     base_id = 1;
923     }
924    
925     if (fonts.size () <= base_id || !realize_font (base_id))
926     {
927     fprintf (stderr, "unable to load a base font, please provide one using -fn fontname\n");
928     exit (1);
929     }
930    
931     height = fonts[base_id]->height;
932    
933     /*add_fonts ("-efont-fixed-medium-r-normal-*-14-*-*-*-*-*-iso10646-1,"*/
934     }
935    
936     int
937     rxvt_fontset::find_font (uint32_t unicode)
938     {
939     for (int i = 0; i < fonts.size (); i++)
940     {
941     rxvt_font *f = fonts[i];
942    
943     if (!f->loaded)
944     {
945     if (FROM_UNICODE (f->cs, unicode) == NOCHAR)
946     goto next_font;
947    
948     if (!realize_font (i))
949     {
950     --i;
951     goto next_font;
952     }
953    
954     //printf ("added font %s for %04lx\n", f->name, unicode);
955     }
956    
957     if (f->has_codepoint (unicode))
958     return i;
959    
960     next_font:
961     if (i == fonts.size () - 1 && fallback->name)
962     {
963     fonts.push_back (new_font (fallback->name, fallback->cs));
964     fallback++;
965     }
966     }
967    
968     return 0; /* we must return SOME font */
969     }
970    
971    
972