17
17
* You should have received a copy of the GNU General Public License
18
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
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
20
*---------------------------------------------------------------------*/
22
22
#include "../config.h"
24
25
#include "rxvtutil.h"
25
26
#include "rxvtfont.h"
29
30
#include <inttypes.h>
31
#define DISPLAY r->display->display
32
#define TGC r->TermWin.gc
32
#define MAX_OVERLAP_ROMAN (8 + 2) // max. character width in 8ths of the base width
33
#define MAX_OVERLAP_ITALIC (8 + 3) // max. overlap for italic fonts
34
#define MAX_OVERLAP (4 + 1) // max. character width in 4ths of the base width
35
#define OVERLAP_OK(w,wcw,prop) ((w) <= ( \
36
(prop)->slant >= rxvt_fontprop::italic \
37
? ((prop)->width * (wcw) * MAX_OVERLAP_ITALIC + 7) >> 3 \
38
: ((prop)->width * (wcw) * MAX_OVERLAP_ROMAN + 7) >> 3 \
36
41
const struct rxvt_fallback_font {
61
66
{ CS_ISO8859_16, "-*-*-*-r-*--*-*-*-*-c-*-iso8859-16" },
64
{ CS_KOI8_U, "xft::spacing=100:lang=ru:antialias=false" },
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" },
69
{ CS_KOI8_U, "xft::lang=ru" },
71
{ CS_ISO8859_5, "xft::lang=ru" },
72
{ CS_ISO8859_6, "xft::lang=ar" },
73
{ CS_ISO8859_7, "xft::lang=el" },
74
{ CS_ISO8859_8, "xft::lang=he" },
75
{ CS_ISO8859_9, "xft::lang=tr" },
76
{ CS_ISO8859_10, "xft::lang=se" },
77
{ CS_ISO8859_11, "xft::lang=th" },
95
100
{ CS_GBK_0, "xft:AR PL KaitiM GB" },
96
101
{ CS_GBK_0, "xft:AR PL SungtiL GB" },
97
{ CS_GBK_0, "xft::spacing=100:lang=zh" },
102
{ CS_GBK_0, "xft::lang=zh" },
98
103
{ CS_BIG5_EXT, "xft:AR PL Mingti2L Big5" },
99
104
{ CS_BIG5_EXT, "xft:AR PL KaitiM Big5" },
100
105
{ CS_GB2312_1980_0, "xft:AR PL KaitiM GB" },
101
106
{ CS_GB2312_1980_0, "xft:AR PL SungtiL GB" },
102
{ CS_GB2312_1980_0, "xft::spacing=100:lang=zh" },
107
{ CS_GB2312_1980_0, "xft::lang=zh" },
104
109
{ CS_GBK_0, "-*-*-*-*-*-*-*-*-*-*-c-*-gbk*-0" },
105
110
{ CS_BIG5, "-*-*-*-*-*-*-*-*-*-*-c-*-big5-0" },
122
127
{ CS_KSC5601_1987_0, "-*-*-*-*-*-*-*-*-*-*-c-*-ksc5601*" },
124
129
{ CS_KSC5601_1987_0, "xft:Baekmuk Gulim:antialias=false" },
125
{ CS_KSC5601_1987_0, "xft::spacing=100:lang=ko:antialias=false" },
130
{ CS_KSC5601_1987_0, "xft::lang=ko:antialias=false" },
129
// generic font fallback
130
134
{ CS_UNICODE, "-*-lucidatypewriter-*-*-*-*-*-*-*-*-m-*-iso10646-1" },
131
{ CS_UNICODE, "-*-unifont-*-*-*-*-*-*-*-*-c-*-iso10646-1" },
132
{ CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1" },
133
{ CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
135
//{ CS_UNICODE, "-*-unifont-*-*-*-*-*-*-*-*-c-*-iso10646-1" }, // this gem of a font has actual dotted circles within the combining character glyphs.
135
{ CS_UNICODE, "xft:Bitstream Vera Sans Mono:antialias=false:autohint=true"},
136
{ CS_UNICODE, "xft:Courier New:antialias=false:autohint=true" },
137
{ CS_UNICODE, "xft:Andale Mono:antialias=false" },
138
{ CS_UNICODE, "xft:Arial Unicode MS:antialias=false" },
137
{ CS_UNICODE, "xft:Bitstream Vera Sans Mono:antialias=false:autohint=true" },
138
{ CS_UNICODE, "xft:Courier New:antialias=false:autohint=true" },
139
{ CS_UNICODE, "xft:Andale Mono:antialias=false:autohint=false" },
140
{ CS_UNICODE, "xft:Arial Unicode MS:antialias=false:autohint=false" },
140
// FreeMono is usually uglier than x fonts, so try last only.
142
// FreeMono is usually uglier than x fonts, so try after the others
141
143
{ CS_UNICODE, "xft:FreeMono:autohint=true" },
146
// generic font fallback, put this last, as many iso10646 fonts have extents
147
// specified for all glyphs in the range they cover, but most are simply empty
148
//{ CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-c-*-iso10646-1" },
149
//{ CS_UNICODE, "-*-*-*-r-*-*-*-*-*-*-m-*-iso10646-1" },
144
150
{ CS_UNKNOWN, 0 }
155
161
#define NUM_EXTENT_TEST_CHARS (sizeof (extent_test_chars) / sizeof (extent_test_chars[0]))
157
/////////////////////////////////////////////////////////////////////////////
160
rxvt_drawable::~rxvt_drawable ()
163
XftDrawDestroy (xftdrawable);
166
rxvt_drawable::operator XftDraw *()
169
xftdrawable = XftDrawCreate (display->display, drawable, display->visual, display->cmap);
175
/////////////////////////////////////////////////////////////////////////////
177
static void *enc_buf;
178
static uint32_t enc_len;
181
get_enc_buf (uint32_t len)
186
enc_buf = malloc (len);
163
#define dTermDisplay Display *disp = term->dpy
164
#define dTermGC GC gc = term->gc
166
/////////////////////////////////////////////////////////////////////////////
193
168
static const char *
194
169
enc_char (const text_t *text, uint32_t len, codeset cs, bool &zero)
196
uint8_t *buf = (uint8_t *)get_enc_buf (len);
171
uint8_t *buf = rxvt_temp_buf<uint8_t> (len);
250
rxvt_font::clear_rect (rxvt_drawable &d, int x, int y, int w, int h, int color)
232
rxvt_font::clear_rect (rxvt_drawable &d, int x, int y, int w, int h, int color) const
252
if (color == Color_bg)
253
XClearArea (d.display->display, d, x, y, w, h, FALSE);
237
if (color < 0 || color == Color_bg)
238
XClearArea (disp, d, x, y, w, h, false);
257
XftDrawRect (d, &r->pix_colors[color].c, x, y, w, h);
242
XftDrawRect (d, &term->pix_colors[color].c, x, y, w, h);
259
XSetForeground (d.display->display, TGC, r->pix_colors[color]);
260
XFillRectangle (d.display->display, d, TGC, x, y, w, h);
244
XSetForeground (disp, gc, term->pix_colors[color]);
245
XFillRectangle (disp, d, gc, x, y, w, h);
250
/////////////////////////////////////////////////////////////////////////////
265
252
#include "table/linedraw.h"
267
254
struct rxvt_font_default : rxvt_font {
408
398
gcv.ts_x_origin = x;
409
399
gcv.ts_y_origin = y;
411
XChangeGC (disp, TGC,
412
402
GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
416
XFillRectangle (disp, d, TGC, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
406
XFillRectangle (disp, d, gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
420
410
XFreePixmap (disp, gcv.stipple);
422
412
gcv.fill_style = FillSolid;
423
XChangeGC (disp, TGC, GCFillStyle, &gcv);
413
XChangeGC (disp, gc, GCFillStyle, &gcv);
427
XDrawArc (disp, d, TGC,
417
XDrawArc (disp, d, gc,
428
418
x1 - W/2, y1 - H/2, W-1, H-1,
429
419
(a - 1) * 90*64, (b - 1) * 90*64);
496
487
bool enc2b, encm;
498
char *get_property (XFontStruct *f, const char *property, const char *repl) const;
489
char *get_property (XFontStruct *f, Atom property, const char *repl) const;
499
490
bool set_properties (rxvt_fontprop &p, int height, const char *weight, const char *slant, int avgwidth);
500
491
bool set_properties (rxvt_fontprop &p, XFontStruct *f);
501
492
bool set_properties (rxvt_fontprop &p, const char *name);
505
rxvt_font_x11::get_property (XFontStruct *f, const char *property, const char *repl) const
496
rxvt_font_x11::get_property (XFontStruct *f, Atom property, const char *repl) const
507
498
unsigned long value;
509
if (XGetFontProperty (f, XInternAtom (DISPLAY, property, 0), &value))
510
return XGetAtomName (DISPLAY, value);
500
if (XGetFontProperty (f, property, &value))
501
return XGetAtomName (term->dpy, value);
512
503
return rxvt_strdup (repl);
537
531
unsigned long height;
540
if (!XGetFontProperty (f, XInternAtom (DISPLAY, "PIXEL_SIZE", 0), &height))
534
if (!XGetFontProperty (f, XInternAtom (term->dpy, "PIXEL_SIZE", 0), &height))
543
537
height = f->ascent + f->descent;
546
540
unsigned long avgwidth;
547
if (!XGetFontProperty (f, XInternAtom (DISPLAY, "AVERAGE_WIDTH", 0), &avgwidth))
541
if (!XGetFontProperty (f, term->xa [XA_AVERAGE_WIDTH], &avgwidth))
550
char *weight = get_property (f, "WEIGHT_NAME", "medium");
551
char *slant = get_property (f, "SLANT", "r");
544
char *weight = get_property (f, term->xa [XA_WEIGHT_NAME], "medium");
545
char *slant = get_property (f, term->xa [XA_SLANT], "r");
553
547
set_properties (p, height, weight, slant, avgwidth);
552
p.ascent = f->ascent;
562
558
rxvt_font_x11::set_properties (rxvt_fontprop &p, const char *name)
565
562
const char *comp[13];
974
971
if (bg == Color_bg && !slow)
976
v.background = r->pix_colors[bg];
977
XChangeGC (d.display->display, TGC, GCForeground | GCBackground | GCFont, &v);
978
XDrawImageString16 (d.display->display, d, TGC, x, y + base, xc, len);
973
v.background = term->pix_colors[bg];
974
XChangeGC (disp, gc, GCForeground | GCBackground | GCFont, &v);
975
XDrawImageString16 (disp, d, gc, x, y + base, xc, len);
982
clear_rect (d, x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
979
clear_rect (d, x, y, term->fwidth * len, term->fheight, bg);
984
XChangeGC (d.display->display, TGC, GCForeground | GCFont, &v);
981
XChangeGC (disp, gc, GCForeground | GCFont, &v);
990
987
if (xc->byte1 || xc->byte2)
991
XDrawString16 (d.display->display, d, TGC, x, y + base, xc, 1);
988
XDrawString16 (disp, d, gc, x, y + base, xc, 1);
993
x += r->TermWin.fwidth;
999
XDrawString16 (d.display->display, d, TGC, x, y + base, xc, len);
996
XDrawString16 (disp, d, gc, x, y + base, xc, len);
1006
1003
if (bg == Color_bg && !slow)
1008
v.background = r->pix_colors[bg];
1009
XChangeGC (d.display->display, TGC, GCForeground | GCBackground | GCFont, &v);
1010
XDrawImageString (d.display->display, d, TGC, x, y + base, xc, len);
1005
v.background = term->pix_colors[bg];
1006
XChangeGC (disp, gc, GCForeground | GCBackground | GCFont, &v);
1007
XDrawImageString (disp, d, gc, x, y + base, xc, len);
1014
clear_rect (d, x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
1011
clear_rect (d, x, y, term->fwidth * len, term->fheight, bg);
1016
XChangeGC (d.display->display, TGC, GCForeground | GCFont, &v);
1013
XChangeGC (disp, gc, GCForeground | GCFont, &v);
1023
XDrawString (d.display->display, d, TGC, x, y + base, xc, 1);
1020
XDrawString (disp, d, gc, x, y + base, xc, 1);
1025
x += r->TermWin.fwidth;
1031
XDrawString (d.display->display, d, TGC, x, y + base, xc, len);
1028
XDrawString (disp, d, gc, x, y + base, xc, len);
1230
1244
// check character against base font bounding box
1231
1245
FcChar32 ch = unicode;
1233
XftTextExtents32 (DISPLAY, f, &ch, 1, &g);
1236
int wcw = wcwidth (unicode);
1237
if (wcw > 0) w /= wcw;
1239
careful = w > prop->width;
1240
if (careful && w > prop->width * MAX_OVERLAP >> 2)
1247
XftTextExtents32 (term->dpy, f, &ch, 1, &g);
1249
int w = g.width - g.x;
1250
int wcw = max (WCWIDTH (unicode), 1);
1252
careful = g.x > 0 || w > prop->width * wcw;
1254
if (careful && !OVERLAP_OK (w, wcw, prop))
1257
// this weeds out _totally_ broken fonts, or glyphs
1258
if (!OVERLAP_OK (g.xOff, wcw, prop))
1248
1266
const text_t *text, int len,
1249
1267
int fg, int bg)
1251
clear_rect (d, x, y, r->TermWin.fwidth * len, r->TermWin.fheight, bg);
1253
int base = ascent; // should be fbase, but that is incorrect
1255
1269
XGlyphInfo extents;
1256
FcChar32 *enc = (FcChar32 *) get_enc_buf (len * sizeof (FcChar32));
1270
XftGlyphSpec *enc = (XftGlyphSpec *)rxvt_temp_buf (len * sizeof (XftGlyphSpec));
1271
XftGlyphSpec *ep = enc;
1276
int w = term->fwidth * len;
1277
int h = term->fheight;
1279
bool buffered = bg >= 0 // we don't use a transparent bg
1280
#ifndef FORCE_UNBUFFERED_XFT
1281
# if defined(XPM_BACKGROUND) || defined(TRANSPARENT)
1282
|| !term->am_transparent // we aren't transparent
1283
|| term->am_pixmap_trans // we have a pixmap
1288
// cut trailing spaces
1289
while (len && text [len - 1] == ' ')
1292
int x_ = buffered ? 0 : x;
1293
int y_ = buffered ? 0 : y;
1263
int cwidth = r->TermWin.fwidth;
1297
int cwidth = term->fwidth;
1264
1298
FcChar32 fc = *text++; len--;
1267
1300
while (len && *text == NOCHAR)
1268
text++, len--, cwidth += r->TermWin.fwidth;
1301
text++, len--, cwidth += term->fwidth;
1270
gl = XftCharIndex (d.display->display, f, fc);
1271
XftGlyphExtents (d.display->display, f, &gl, 1, &extents);
1273
if (extents.xOff != cwidth && ep != enc)
1275
if (xoff > ewidth) xoff = ewidth;
1276
XftDrawGlyphs (d, &r->pix_colors[fg].c, f,
1277
x + (ewidth - xoff >> 1),
1278
y + base, enc, ep - enc);
1286
if (fc == ' ' && ep == enc) // skip leading spaces
1303
if (fc != ' ') // skip spaces
1305
FT_UInt glyph = XftCharIndex (disp, f, fc);
1306
XftGlyphExtents (disp, f, &glyph, 1, &extents);
1309
ep->x = x_ + (cwidth - extents.xOff >> 1);
1310
ep->y = y_ + ascent;
1312
if (extents.xOff == 0)
1313
ep->x = x_ + cwidth;
1325
rxvt_drawable &d2 = d.screen->scratch_drawable (w, h);
1330
else if (bg < 0 && term->am_pixmap_trans)
1331
XCopyArea (disp, term->pixmap, d2, gc,
1332
x + term->window_vt_x, y + term->window_vt_y,
1335
#ifdef XPM_BACKGROUND
1336
else if (bg < 0 && term->bgPixmap.pixmap)
1340
gcv.fill_style = FillTiled;
1341
gcv.tile = term->pixmap;
1342
gcv.ts_x_origin = -x;
1343
gcv.ts_y_origin = -y;
1345
GC gc2 = XCreateGC (disp, d2,
1346
GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle,
1349
XFillRectangle (disp, d2, gc2, 0, 0, w, h);
1351
XFreeGC (disp, gc2);
1355
XftDrawRect (d2, &term->pix_colors[bg].c, 0, 0, w, h);
1357
XftDrawGlyphSpec (d2, &term->pix_colors[fg].c, f, enc, ep - enc);
1358
XCopyArea (disp, d2, d, gc, 0, 0, w, h, x, y);
1296
xoff += extents.xOff;
1361
clear_rect (d, x, y, w, h, bg);
1302
if (xoff > ewidth) xoff = ewidth;
1303
XftDrawGlyphs (d, &r->pix_colors[fg].c, f,
1304
x + (ewidth - xoff >> 1),
1305
y + base, enc, ep - enc);
1365
clear_rect (d, x, y, w, h, bg);
1366
XftDrawGlyphSpec (d, &term->pix_colors[fg].c, f, enc, ep - enc);
1310
1372
/////////////////////////////////////////////////////////////////////////////
1312
rxvt_fontset::rxvt_fontset (rxvt_t r)
1313
: r (r), fontdesc (0)
1374
rxvt_fontset::rxvt_fontset (rxvt_term *term)
1375
: fontdesc (0), term (term)