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