aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--st.c383
1 files changed, 187 insertions, 196 deletions
diff --git a/st.c b/st.c
index 4add638..c2da66b 100644
--- a/st.c
+++ b/st.c
@@ -58,7 +58,6 @@ char *argv0;
58#define ESC_ARG_SIZ 16 58#define ESC_ARG_SIZ 16
59#define STR_BUF_SIZ ESC_BUF_SIZ 59#define STR_BUF_SIZ ESC_BUF_SIZ
60#define STR_ARG_SIZ ESC_ARG_SIZ 60#define STR_ARG_SIZ ESC_ARG_SIZ
61#define DRAW_BUF_SIZ 20*1024
62#define XK_ANY_MOD UINT_MAX 61#define XK_ANY_MOD UINT_MAX
63#define XK_NO_MOD 0 62#define XK_NO_MOD 0
64#define XK_SWITCH_MOD (1<<13) 63#define XK_SWITCH_MOD (1<<13)
@@ -87,18 +86,19 @@ char *argv0;
87 86
88 87
89enum glyph_attribute { 88enum glyph_attribute {
90 ATTR_NULL = 0, 89 ATTR_NULL = 0,
91 ATTR_BOLD = 1 << 0, 90 ATTR_BOLD = 1 << 0,
92 ATTR_FAINT = 1 << 1, 91 ATTR_FAINT = 1 << 1,
93 ATTR_ITALIC = 1 << 2, 92 ATTR_ITALIC = 1 << 2,
94 ATTR_UNDERLINE = 1 << 3, 93 ATTR_UNDERLINE = 1 << 3,
95 ATTR_BLINK = 1 << 4, 94 ATTR_BLINK = 1 << 4,
96 ATTR_REVERSE = 1 << 5, 95 ATTR_REVERSE = 1 << 5,
97 ATTR_INVISIBLE = 1 << 6, 96 ATTR_INVISIBLE = 1 << 6,
98 ATTR_STRUCK = 1 << 7, 97 ATTR_STRUCK = 1 << 7,
99 ATTR_WRAP = 1 << 8, 98 ATTR_WRAP = 1 << 8,
100 ATTR_WIDE = 1 << 9, 99 ATTR_WIDE = 1 << 9,
101 ATTR_WDUMMY = 1 << 10, 100 ATTR_WDUMMY = 1 << 10,
101 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
102}; 102};
103 103
104enum cursor_movement { 104enum cursor_movement {
@@ -232,6 +232,7 @@ typedef struct {
232 Line *line; /* screen */ 232 Line *line; /* screen */
233 Line *alt; /* alternate screen */ 233 Line *alt; /* alternate screen */
234 bool *dirty; /* dirtyness of lines */ 234 bool *dirty; /* dirtyness of lines */
235 XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */
235 TCursor c; /* cursor */ 236 TCursor c; /* cursor */
236 int top; /* top scroll limit */ 237 int top; /* top scroll limit */
237 int bot; /* bottom scroll limit */ 238 int bot; /* bottom scroll limit */
@@ -418,7 +419,8 @@ static void ttywrite(const char *, size_t);
418static void tstrsequence(uchar); 419static void tstrsequence(uchar);
419 420
420static inline ushort sixd_to_16bit(int); 421static inline ushort sixd_to_16bit(int);
421static void xdraws(char *, Glyph, int, int, int, int); 422static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
423static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
422static void xdrawglyph(Glyph, int, int); 424static void xdrawglyph(Glyph, int, int);
423static void xhints(void); 425static void xhints(void);
424static void xclear(int, int, int, int); 426static void xclear(int, int, int, int);
@@ -2819,6 +2821,9 @@ tresize(int col, int row) {
2819 free(term.alt[i]); 2821 free(term.alt[i]);
2820 } 2822 }
2821 2823
2824 /* resize to new width */
2825 term.specbuf = xrealloc(term.specbuf, col * sizeof(XftGlyphFontSpec));
2826
2822 /* resize to new height */ 2827 /* resize to new height */
2823 term.line = xrealloc(term.line, row * sizeof(Line)); 2828 term.line = xrealloc(term.line, row * sizeof(Line));
2824 term.alt = xrealloc(term.alt, row * sizeof(Line)); 2829 term.alt = xrealloc(term.alt, row * sizeof(Line));
@@ -3257,38 +3262,155 @@ xinit(void) {
3257 XSync(xw.dpy, False); 3262 XSync(xw.dpy, False);
3258} 3263}
3259 3264
3260void 3265int
3261xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { 3266xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
3262 int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, 3267{
3263 width = charlen * xw.cw, xp, i; 3268 float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp;
3264 int frcflags, charexists; 3269 ushort mode, prevmode = USHRT_MAX;
3265 int u8fl, u8fblen, u8cblen, doesexist;
3266 char *u8c, *u8fs;
3267 Rune unicodep;
3268 Font *font = &dc.font; 3270 Font *font = &dc.font;
3271 int frcflags = FRC_NORMAL;
3272 float runewidth = xw.cw;
3273 Rune rune;
3274 FT_UInt glyphidx;
3269 FcResult fcres; 3275 FcResult fcres;
3270 FcPattern *fcpattern, *fontpattern; 3276 FcPattern *fcpattern, *fontpattern;
3271 FcFontSet *fcsets[] = { NULL }; 3277 FcFontSet *fcsets[] = { NULL };
3272 FcCharSet *fccharset; 3278 FcCharSet *fccharset;
3279 int i, f, numspecs = 0;
3280
3281 for(i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
3282 /* Fetch rune and mode for current glyph. */
3283 rune = glyphs[i].u;
3284 mode = glyphs[i].mode;
3285
3286 /* Skip dummy wide-character spacing. */
3287 if(mode == ATTR_WDUMMY)
3288 continue;
3289
3290 /* Determine font for glyph if different from previous glyph. */
3291 if(prevmode != mode) {
3292 prevmode = mode;
3293 font = &dc.font;
3294 frcflags = FRC_NORMAL;
3295 runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
3296 if((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
3297 font = &dc.ibfont;
3298 frcflags = FRC_ITALICBOLD;
3299 } else if(mode & ATTR_ITALIC) {
3300 font = &dc.ifont;
3301 frcflags = FRC_ITALIC;
3302 } else if(mode & ATTR_BOLD) {
3303 font = &dc.bfont;
3304 frcflags = FRC_BOLD;
3305 }
3306 yp = winy + font->ascent;
3307 }
3308
3309 /* Lookup character index with default font. */
3310 glyphidx = XftCharIndex(xw.dpy, font->match, rune);
3311 if(glyphidx) {
3312 specs[numspecs].font = font->match;
3313 specs[numspecs].glyph = glyphidx;
3314 specs[numspecs].x = (short)xp;
3315 specs[numspecs].y = (short)yp;
3316 xp += runewidth;
3317 numspecs++;
3318 continue;
3319 }
3320
3321 /* Fallback on font cache, search the font cache for match. */
3322 for(f = 0; f < frclen; f++) {
3323 glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
3324 /* Everything correct. */
3325 if(glyphidx && frc[f].flags == frcflags)
3326 break;
3327 /* We got a default font for a not found glyph. */
3328 if(!glyphidx && frc[f].flags == frcflags
3329 && frc[f].unicodep == rune) {
3330 break;
3331 }
3332 }
3333
3334 /* Nothing was found. Use fontconfig to find matching font. */
3335 if(f >= frclen) {
3336 if(!font->set)
3337 font->set = FcFontSort(0, font->pattern,
3338 FcTrue, 0, &fcres);
3339 fcsets[0] = font->set;
3340
3341 /*
3342 * Nothing was found in the cache. Now use
3343 * some dozen of Fontconfig calls to get the
3344 * font for one single character.
3345 *
3346 * Xft and fontconfig are design failures.
3347 */
3348 fcpattern = FcPatternDuplicate(font->pattern);
3349 fccharset = FcCharSetCreate();
3350
3351 FcCharSetAddChar(fccharset, rune);
3352 FcPatternAddCharSet(fcpattern, FC_CHARSET,
3353 fccharset);
3354 FcPatternAddBool(fcpattern, FC_SCALABLE,
3355 FcTrue);
3356
3357 FcConfigSubstitute(0, fcpattern,
3358 FcMatchPattern);
3359 FcDefaultSubstitute(fcpattern);
3360
3361 fontpattern = FcFontSetMatch(0, fcsets, 1,
3362 fcpattern, &fcres);
3363
3364 /*
3365 * Overwrite or create the new cache entry.
3366 */
3367 if(frclen >= LEN(frc)) {
3368 frclen = LEN(frc) - 1;
3369 XftFontClose(xw.dpy, frc[frclen].font);
3370 frc[frclen].unicodep = 0;
3371 }
3372
3373 frc[frclen].font = XftFontOpenPattern(xw.dpy,
3374 fontpattern);
3375 frc[frclen].flags = frcflags;
3376 frc[frclen].unicodep = rune;
3377
3378 glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
3379
3380 f = frclen;
3381 frclen++;
3382
3383 FcPatternDestroy(fcpattern);
3384 FcCharSetDestroy(fccharset);
3385 }
3386
3387 specs[numspecs].font = frc[f].font;
3388 specs[numspecs].glyph = glyphidx;
3389 specs[numspecs].x = (short)xp;
3390 specs[numspecs].y = (short)(winy + frc[f].font->ascent);
3391 xp += runewidth;
3392 numspecs++;
3393 }
3394
3395 return numspecs;
3396}
3397
3398void
3399xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) {
3400 int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
3401 int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
3402 width = charlen * xw.cw;
3273 Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; 3403 Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
3274 XRenderColor colfg, colbg; 3404 XRenderColor colfg, colbg;
3275 XRectangle r; 3405 XRectangle r;
3276 int oneatatime;
3277 3406
3278 frcflags = FRC_NORMAL; 3407 /* Determine foreground and background colors based on mode. */
3279 3408 if(base.fg == defaultfg) {
3280 if(base.mode & ATTR_ITALIC) { 3409 if(base.mode & ATTR_ITALIC)
3281 if(base.fg == defaultfg)
3282 base.fg = defaultitalic; 3410 base.fg = defaultitalic;
3283 font = &dc.ifont; 3411 else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD))
3284 frcflags = FRC_ITALIC;
3285 } else if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) {
3286 if(base.fg == defaultfg)
3287 base.fg = defaultitalic; 3412 base.fg = defaultitalic;
3288 font = &dc.ibfont; 3413 else if(base.mode & ATTR_UNDERLINE)
3289 frcflags = FRC_ITALICBOLD;
3290 } else if(base.mode & ATTR_UNDERLINE) {
3291 if(base.fg == defaultfg)
3292 base.fg = defaultunderline; 3414 base.fg = defaultunderline;
3293 } 3415 }
3294 3416
@@ -3314,22 +3436,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
3314 bg = &dc.col[base.bg]; 3436 bg = &dc.col[base.bg];
3315 } 3437 }
3316 3438
3317 if(base.mode & ATTR_BOLD) { 3439 /* Change basic system colors [0-7] to bright system colors [8-15] */
3318 /* 3440 if((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
3319 * change basic system colors [0-7] 3441 fg = &dc.col[base.fg + 8];
3320 * to bright system colors [8-15]
3321 */
3322 if(BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
3323 fg = &dc.col[base.fg + 8];
3324
3325 if(base.mode & ATTR_ITALIC) {
3326 font = &dc.ibfont;
3327 frcflags = FRC_ITALICBOLD;
3328 } else {
3329 font = &dc.bfont;
3330 frcflags = FRC_BOLD;
3331 }
3332 }
3333 3442
3334 if(IS_SET(MODE_REVERSE)) { 3443 if(IS_SET(MODE_REVERSE)) {
3335 if(fg == &dc.col[defaultfg]) { 3444 if(fg == &dc.col[defaultfg]) {
@@ -3363,7 +3472,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
3363 bg = temp; 3472 bg = temp;
3364 } 3473 }
3365 3474
3366 if(base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) { 3475 if((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) {
3367 colfg.red = fg->color.red / 2; 3476 colfg.red = fg->color.red / 2;
3368 colfg.green = fg->color.green / 2; 3477 colfg.green = fg->color.green / 2;
3369 colfg.blue = fg->color.blue / 2; 3478 colfg.blue = fg->color.blue / 2;
@@ -3401,136 +3510,17 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
3401 r.width = width; 3510 r.width = width;
3402 XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); 3511 XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
3403 3512
3404 for(xp = winx; bytelen > 0;) { 3513 /* Render the glyphs. */
3405 /* 3514 XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
3406 * Search for the range in the to be printed string of glyphs
3407 * that are in the main font. Then print that range. If
3408 * some glyph is found that is not in the font, do the
3409 * fallback dance.
3410 */
3411 u8fs = s;
3412 u8fblen = 0;
3413 u8fl = 0;
3414 oneatatime = font->width != xw.cw;
3415 for(;;) {
3416 u8c = s;
3417 u8cblen = utf8decode(s, &unicodep, UTF_SIZ);
3418 s += u8cblen;
3419 bytelen -= u8cblen;
3420
3421 doesexist = XftCharExists(xw.dpy, font->match, unicodep);
3422 if(doesexist) {
3423 u8fl++;
3424 u8fblen += u8cblen;
3425 if(!oneatatime && bytelen > 0)
3426 continue;
3427 }
3428
3429 if(u8fl > 0) {
3430 XftDrawStringUtf8(xw.draw, fg,
3431 font->match, xp,
3432 winy + font->ascent,
3433 (FcChar8 *)u8fs,
3434 u8fblen);
3435 xp += xw.cw * u8fl;
3436 }
3437 break;
3438 }
3439 if(doesexist) {
3440 if(oneatatime)
3441 continue;
3442 break;
3443 }
3444
3445 /* Search the font cache. */
3446 for(i = 0; i < frclen; i++) {
3447 charexists = XftCharExists(xw.dpy, frc[i].font, unicodep);
3448 /* Everything correct. */
3449 if(charexists && frc[i].flags == frcflags)
3450 break;
3451 /* We got a default font for a not found glyph. */
3452 if(!charexists && frc[i].flags == frcflags \
3453 && frc[i].unicodep == unicodep) {
3454 break;
3455 }
3456 }
3457
3458 /* Nothing was found. */
3459 if(i >= frclen) {
3460 if(!font->set)
3461 font->set = FcFontSort(0, font->pattern,
3462 FcTrue, 0, &fcres);
3463 fcsets[0] = font->set;
3464
3465 /*
3466 * Nothing was found in the cache. Now use
3467 * some dozen of Fontconfig calls to get the
3468 * font for one single character.
3469 *
3470 * Xft and fontconfig are design failures.
3471 */
3472 fcpattern = FcPatternDuplicate(font->pattern);
3473 fccharset = FcCharSetCreate();
3474
3475 FcCharSetAddChar(fccharset, unicodep);
3476 FcPatternAddCharSet(fcpattern, FC_CHARSET,
3477 fccharset);
3478 FcPatternAddBool(fcpattern, FC_SCALABLE,
3479 FcTrue);
3480
3481 FcConfigSubstitute(0, fcpattern,
3482 FcMatchPattern);
3483 FcDefaultSubstitute(fcpattern);
3484
3485 fontpattern = FcFontSetMatch(0, fcsets, 1,
3486 fcpattern, &fcres);
3487
3488 /*
3489 * Overwrite or create the new cache entry.
3490 */
3491 if(frclen >= LEN(frc)) {
3492 frclen = LEN(frc) - 1;
3493 XftFontClose(xw.dpy, frc[frclen].font);
3494 frc[frclen].unicodep = 0;
3495 }
3496
3497 frc[frclen].font = XftFontOpenPattern(xw.dpy,
3498 fontpattern);
3499 frc[frclen].flags = frcflags;
3500 frc[frclen].unicodep = unicodep;
3501
3502 i = frclen;
3503 frclen++;
3504
3505 FcPatternDestroy(fcpattern);
3506 FcCharSetDestroy(fccharset);
3507 }
3508
3509 XftDrawStringUtf8(xw.draw, fg, frc[i].font,
3510 xp, winy + frc[i].font->ascent,
3511 (FcChar8 *)u8c, u8cblen);
3512
3513 xp += xw.cw * wcwidth(unicodep);
3514 }
3515
3516 /*
3517 * This is how the loop above actually should be. Why does the
3518 * application have to care about font details?
3519 *
3520 * I have to repeat: Xft and Fontconfig are design failures.
3521 */
3522 /*
3523 XftDrawStringUtf8(xw.draw, fg, font->set, winx,
3524 winy + font->ascent, (FcChar8 *)s, bytelen);
3525 */
3526 3515
3516 /* Render underline and strikethrough. */
3527 if(base.mode & ATTR_UNDERLINE) { 3517 if(base.mode & ATTR_UNDERLINE) {
3528 XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1, 3518 XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
3529 width, 1); 3519 width, 1);
3530 } 3520 }
3531 3521
3532 if(base.mode & ATTR_STRUCK) { 3522 if(base.mode & ATTR_STRUCK) {
3533 XftDrawRect(xw.draw, fg, winx, winy + 2 * font->ascent / 3, 3523 XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
3534 width, 1); 3524 width, 1);
3535 } 3525 }
3536 3526
@@ -3540,11 +3530,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
3540 3530
3541void 3531void
3542xdrawglyph(Glyph g, int x, int y) { 3532xdrawglyph(Glyph g, int x, int y) {
3543 static char buf[UTF_SIZ]; 3533 int numspecs;
3544 size_t len = utf8encode(g.u, buf); 3534 XftGlyphFontSpec spec;
3545 int width = g.mode & ATTR_WIDE ? 2 : 1; 3535 numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
3546 3536 xdrawglyphfontspecs(&spec, g, numspecs, x, y);
3547 xdraws(buf, g, x, y, width, len);
3548} 3537}
3549 3538
3550void 3539void
@@ -3658,9 +3647,9 @@ draw(void) {
3658 3647
3659void 3648void
3660drawregion(int x1, int y1, int x2, int y2) { 3649drawregion(int x1, int y1, int x2, int y2) {
3661 int ic, ib, x, y, ox; 3650 int i, x, y, ox, numspecs;
3662 Glyph base, new; 3651 Glyph base, new;
3663 char buf[DRAW_BUF_SIZ]; 3652 XftGlyphFontSpec* specs;
3664 bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); 3653 bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
3665 3654
3666 if(!(xw.state & WIN_VISIBLE)) 3655 if(!(xw.state & WIN_VISIBLE))
@@ -3672,29 +3661,31 @@ drawregion(int x1, int y1, int x2, int y2) {
3672 3661
3673 xtermclear(0, y, term.col, y); 3662 xtermclear(0, y, term.col, y);
3674 term.dirty[y] = 0; 3663 term.dirty[y] = 0;
3675 base = term.line[y][0]; 3664
3676 ic = ib = ox = 0; 3665 specs = term.specbuf;
3677 for(x = x1; x < x2; x++) { 3666 numspecs = xmakeglyphfontspecs(specs, &term.line[y][0], x2 - x1, x1, y);
3667
3668 i = ox = 0;
3669 for(x = x1; x < x2 && i < numspecs; x++) {
3678 new = term.line[y][x]; 3670 new = term.line[y][x];
3679 if(new.mode == ATTR_WDUMMY) 3671 if(new.mode == ATTR_WDUMMY)
3680 continue; 3672 continue;
3681 if(ena_sel && selected(x, y)) 3673 if(ena_sel && selected(x, y))
3682 new.mode ^= ATTR_REVERSE; 3674 new.mode ^= ATTR_REVERSE;
3683 if(ib > 0 && (ATTRCMP(base, new) 3675 if(i > 0 && ATTRCMP(base, new)) {
3684 || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { 3676 xdrawglyphfontspecs(specs, base, i, ox, y);
3685 xdraws(buf, base, ox, y, ic, ib); 3677 specs += i;
3686 ic = ib = 0; 3678 numspecs -= i;
3679 i = 0;
3687 } 3680 }
3688 if(ib == 0) { 3681 if(i == 0) {
3689 ox = x; 3682 ox = x;
3690 base = new; 3683 base = new;
3691 } 3684 }
3692 3685 i++;
3693 ib += utf8encode(new.u, buf+ib);
3694 ic += (new.mode & ATTR_WIDE)? 2 : 1;
3695 } 3686 }
3696 if(ib > 0) 3687 if(i > 0)
3697 xdraws(buf, base, ox, y, ic, ib); 3688 xdrawglyphfontspecs(specs, base, i, ox, y);
3698 } 3689 }
3699 xdrawcursor(); 3690 xdrawcursor();
3700} 3691}