aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsuigin <suigin@national.shitposting.agency>2015-05-05 20:24:00 -0700
committerRoberto E. Vargas Caballero <k0ga@shike2.com>2015-05-07 12:03:44 +0200
commitae1923d27533ff46400d93765e971558201ca1ee (patch)
treeae7c6d6c1ff8a86f8ebf23fe00f331905a30267c
parent38af006b5e4a36c77f25affbb3f7e28899db75ed (diff)
downloadst-patched-ae1923d27533ff46400d93765e971558201ca1ee.tar.bz2
st-patched-ae1923d27533ff46400d93765e971558201ca1ee.tar.xz
st-patched-ae1923d27533ff46400d93765e971558201ca1ee.zip
Clean up xdraws and optimize glyph drawing with non-unit kerning values
I have another patch here for review that optimizes the performance of glyph drawing, primarily when using non-unit kerning values, and fixes a few other minor issues. It's dependent on the earlier patch from me that stores unicode codepoints in a Rune type, typedef'd to uint_least32_t. This patch is a pretty big change to xdraws so your scrutiny is appreciated. First, some performance numbers. I used Yu-Jie Lin termfps.sh shell script to benchmark before and after, and you can find it in the attachments. On my Kaveri A10 7850k machine, I get the following results: Before Patch ============ 1) Font: "Liberation Mono:pixelsize=12:antialias=false:autohint=false" cwscale: 1.0, chscale: 1.0 For 273x83 100 frames. Elapsed time : 1.553 Frames/second: 64.352 Chars /second: 1,458,159 2) Font: "Inconsolata:pixelsize=14:antialias=true:autohint=true" cwscale: 1.001, chscale: 1.001 For 239x73 100 frames. Elapsed time : 159.286 Frames/second: 0.627 Chars /second: 10,953 After Patch =========== 3) Font: "Liberation Mono:pixelsize=12:antialias=false:autohint=false" cwscale: 1.0, chscale: 1.0 For 273x83 100 frames. Elapsed time : 1.544 Frames/second: 64.728 Chars /second: 1,466,690 4) Font: "Inconsolata:pixelsize=14:antialias=true:autohint=true" cwscale: 1.001, chscale: 1.001 For 239x73 100 frames. Elapsed time : 1.955 Frames/second: 51.146 Chars /second: 892,361 As you can see, while the improvements for fonts with unit-kerning is marginal, there's a huge ~81x performance increase with the patch when using kerning values other than 1.0. So what does the patch do? The `xdraws' function would render each glyph one at a time if non-unit kerning values were configured, and this was the primary cause of the slow down. Xft provides a handful of functions which allow you to render multiple characters or glyphs at time, each with a unique <x,y> position, so it was simply a matter of massaging the data into a format that would allow us to use one of these functions. I've split `xdraws' up into two functions. In the first pass with `xmakeglyphfontspecs' it will iterate over all of the glyphs in a given row and it will build up an array of corresponding XftGlyphFontSpec records. Much of the old logic for resolving fonts for glyphs using Xft and fontconfig went into this function. The second pass is done with `xrenderglyphfontspecs' which contains the old logic for determining colors, clearing the background, and finally rendering the array of XftGlyphFontSpec records. There's a couple of other things that have been improved by this patch. For instance, the UTF-32 codepoints in the Line's were being re-encoded back into UTF-8 strings to be passed to `xdraws' which in turn would then decode back to UTF-32 to verify that the Font contained a matching glyph for the code point. Next, the UTF-8 string was being passed to `XftDrawStringUtf8' which internally mallocs a scratch buffer and decodes back to UTF-32 and does the lookup of the glyphs all over again. This patch gets rid of all of this redundant round-trip encoding and decoding of characters to be rendered and only looks up the glyph index once (per font) during the font resolution phase. So this is probably what's responsible for the marginal improvements seen when kerning values are kept to 1.0. I imagine there are other performance improvements here too, not seen in the above benchmarks, if the user has lots of non-ASCII code plane characters on the screen, or several different fonts are being utilized during screen redraw. Anyway, if you see any problems, please let me know and I can fix them.
-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}