summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <craigmartinjennings@gmail.com>2023-07-23 15:46:52 -0500
committerCraig Jennings <craigmartinjennings@gmail.com>2023-07-23 15:46:52 -0500
commit99caf899b0bbb45442e6228573ffb7eb0599889b (patch)
treec84095fc51812852bc8ecb4aafc811b40b57eb17
parent6abfd950d48aba250a868317e91eef0a26163a9a (diff)
moving ligatures patch diff to patches_applied directory
-rw-r--r--st-ligatures-alpha-scrollback-20230105-0.9.diff610
1 files changed, 0 insertions, 610 deletions
diff --git a/st-ligatures-alpha-scrollback-20230105-0.9.diff b/st-ligatures-alpha-scrollback-20230105-0.9.diff
deleted file mode 100644
index 435e3b4..0000000
--- a/st-ligatures-alpha-scrollback-20230105-0.9.diff
+++ /dev/null
@@ -1,610 +0,0 @@
-diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
---- a/Makefile
-+++ b/Makefile
-@@ -4,7 +4,7 @@
-
- include config.mk
-
--SRC = st.c x.c
-+SRC = st.c x.c hb.c
- OBJ = $(SRC:.c=.o)
-
- all: options st
-@@ -22,7 +22,8 @@ config.h:
- $(CC) $(STCFLAGS) -c $<
-
- st.o: config.h st.h win.h
--x.o: arg.h config.h st.h win.h
-+x.o: arg.h config.h st.h win.h hb.h
-+hb.o: st.h
-
- $(OBJ): config.h config.mk
-
-diff --git a/config.mk b/config.mk
-index 47c615e..d7439a3 100644
---- a/config.mk
-+++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
- # includes and libs
- INCS = -I$(X11INC) \
- `$(PKG_CONFIG) --cflags fontconfig` \
-- `$(PKG_CONFIG) --cflags freetype2`
--LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
-+ `$(PKG_CONFIG) --cflags freetype2` \
-+ `$(PKG_CONFIG) --cflags harfbuzz`
-+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \
- `$(PKG_CONFIG) --libs fontconfig` \
-- `$(PKG_CONFIG) --libs freetype2`
-+ `$(PKG_CONFIG) --libs freetype2` \
-+ `$(PKG_CONFIG) --libs harfbuzz`
-
- # flags
- STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
-diff --git a/hb.c b/hb.c
-new file mode 100644
-index 0000000..528c040
---- /dev/null
-+++ b/hb.c
-@@ -0,0 +1,124 @@
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <math.h>
-+#include <X11/Xft/Xft.h>
-+#include <X11/cursorfont.h>
-+#include <hb.h>
-+#include <hb-ft.h>
-+
-+#include "st.h"
-+#include "hb.h"
-+
-+#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
-+#define BUFFER_STEP 256
-+
-+hb_font_t *hbfindfont(XftFont *match);
-+
-+typedef struct {
-+ XftFont *match;
-+ hb_font_t *font;
-+} HbFontMatch;
-+
-+typedef struct {
-+ size_t capacity;
-+ HbFontMatch *fonts;
-+} HbFontCache;
-+
-+static HbFontCache hbfontcache = { 0, NULL };
-+
-+typedef struct {
-+ size_t capacity;
-+ Rune *runes;
-+} RuneBuffer;
-+
-+static RuneBuffer hbrunebuffer = { 0, NULL };
-+
-+/*
-+ * Poplulate the array with a list of font features, wrapped in FEATURE macro,
-+ * e. g.
-+ * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
-+ */
-+hb_feature_t features[] = { };
-+
-+void
-+hbunloadfonts()
-+{
-+ for (int i = 0; i < hbfontcache.capacity; i++) {
-+ hb_font_destroy(hbfontcache.fonts[i].font);
-+ XftUnlockFace(hbfontcache.fonts[i].match);
-+ }
-+
-+ if (hbfontcache.fonts != NULL) {
-+ free(hbfontcache.fonts);
-+ hbfontcache.fonts = NULL;
-+ }
-+ hbfontcache.capacity = 0;
-+}
-+
-+hb_font_t *
-+hbfindfont(XftFont *match)
-+{
-+ for (int i = 0; i < hbfontcache.capacity; i++) {
-+ if (hbfontcache.fonts[i].match == match)
-+ return hbfontcache.fonts[i].font;
-+ }
-+
-+ /* Font not found in cache, caching it now. */
-+ hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMatch) * (hbfontcache.capacity + 1));
-+ FT_Face face = XftLockFace(match);
-+ hb_font_t *font = hb_ft_font_create(face, NULL);
-+ if (font == NULL)
-+ die("Failed to load Harfbuzz font.");
-+
-+ hbfontcache.fonts[hbfontcache.capacity].match = match;
-+ hbfontcache.fonts[hbfontcache.capacity].font = font;
-+ hbfontcache.capacity += 1;
-+
-+ return font;
-+}
-+
-+void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) {
-+ ushort mode = USHRT_MAX;
-+ unsigned int glyph_count;
-+ int rune_idx, glyph_idx, end = start + length;
-+
-+ hb_font_t *font = hbfindfont(xfont);
-+ if (font == NULL)
-+ return;
-+
-+ hb_buffer_t *buffer = hb_buffer_create();
-+ hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
-+
-+ /* Resize the buffer if required length is larger. */
-+ if (hbrunebuffer.capacity < length) {
-+ hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BUFFER_STEP;
-+ hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrunebuffer.capacity * sizeof(Rune));
-+ }
-+
-+ /* Fill buffer with codepoints. */
-+ for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_idx++, rune_idx++) {
-+ hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u;
-+ mode = glyphs[glyph_idx].mode;
-+ if (mode & ATTR_WDUMMY)
-+ hbrunebuffer.runes[rune_idx] = 0x0020;
-+ }
-+ hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length);
-+
-+ /* Shape the segment. */
-+ hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t));
-+
-+ /* Get new glyph info. */
-+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
-+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count);
-+
-+ /* Fill the output. */
-+ data->buffer = buffer;
-+ data->glyphs = info;
-+ data->positions = pos;
-+ data->count = glyph_count;
-+}
-+
-+void hbcleanup(HbTransformData *data) {
-+ hb_buffer_destroy(data->buffer);
-+ memset(data, 0, sizeof(HbTransformData));
-+}
-diff --git a/hb.h b/hb.h
-new file mode 100644
-index 0000000..88de9bd
---- /dev/null
-+++ b/hb.h
-@@ -0,0 +1,14 @@
-+#include <X11/Xft/Xft.h>
-+#include <hb.h>
-+#include <hb-ft.h>
-+
-+typedef struct {
-+ hb_buffer_t *buffer;
-+ hb_glyph_info_t *glyphs;
-+ hb_glyph_position_t *positions;
-+ unsigned int count;
-+} HbTransformData;
-+
-+void hbunloadfonts();
-+void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
-+void hbcleanup(HbTransformData *);
-diff --git a/st.c b/st.c
-index 79ee9ba..454771d 100644
---- a/st.c
-+++ b/st.c
-@@ -2711,7 +2711,9 @@ draw(void)
- drawregion(0, 0, term.col, term.row);
- if (term.scr == 0)
- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
-- term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
-+ term.ocx, term.ocy, term.line[term.ocy][term.ocx],
-+ term.line[term.ocy], term.col);
-+
- term.ocx = cx;
- term.ocy = term.c.y;
- xfinishdraw();
-diff --git a/st.h b/st.h
-index 78762a2..01eea49 100644
---- a/st.h
-+++ b/st.h
-@@ -11,7 +11,8 @@
- #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
- #define DEFAULT(a, b) (a) = (a) ? (a) : (b)
- #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
--#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
-+#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP)) != ((b).mode & (~ATTR_WRAP)) || \
-+ (a).fg != (b).fg || \
- (a).bg != (b).bg)
- #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
- (t1.tv_nsec-t2.tv_nsec)/1E6)
-diff --git a/win.h b/win.h
-index 6de960d..94679e4 100644
---- a/win.h
-+++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
-
- void xbell(void);
- void xclipcopy(void);
--void xdrawcursor(int, int, Glyph, int, int, Glyph);
-+void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
- void xdrawline(Line, int, int, int);
- void xfinishdraw(void);
- void xloadcols(void);
-diff --git a/x.c b/x.c
-index 27e81d1..5d19ed7 100644
---- a/x.c
-+++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
- #include "arg.h"
- #include "st.h"
- #include "win.h"
-+#include "hb.h"
-
- /* types used in config.h */
- typedef struct {
-@@ -142,6 +143,7 @@ typedef struct {
- } DC;
-
- static inline ushort sixd_to_16bit(int);
-+static void xresetfontsettings(ushort mode, Font **font, int *frcflags);
- static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
- static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
- static void xdrawglyph(Glyph, int, int);
-@@ -759,7 +761,7 @@ xresize(int col, int row)
- xclear(0, 0, win.w, win.h);
-
- /* resize to new width */
-- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec));
-+ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4);
- }
-
- ushort
-@@ -1071,6 +1073,9 @@ xunloadfont(Font *f)
- void
- xunloadfonts(void)
- {
-+ /* Clear Harfbuzz font cache. */
-+ hbunloadfonts();
-+
- /* Free the loaded fonts in the font cache. */
- while (frclen > 0)
- XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1202,7 +1207,7 @@ xinit(int cols, int rows)
- XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
-
- /* font spec buffer */
-- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec));
-+ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4);
-
- /* Xft rendering context */
- xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1256,6 +1261,22 @@ xinit(int cols, int rows)
- xsel.xtarget = XA_STRING;
- }
-
-+void
-+xresetfontsettings(ushort mode, Font **font, int *frcflags)
-+{
-+ *font = &dc.font;
-+ if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
-+ *font = &dc.ibfont;
-+ *frcflags = FRC_ITALICBOLD;
-+ } else if (mode & ATTR_ITALIC) {
-+ *font = &dc.ifont;
-+ *frcflags = FRC_ITALIC;
-+ } else if (mode & ATTR_BOLD) {
-+ *font = &dc.bfont;
-+ *frcflags = FRC_BOLD;
-+ }
-+}
-+
- int
- xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
- {
-@@ -1270,119 +1291,148 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
- FcPattern *fcpattern, *fontpattern;
- FcFontSet *fcsets[] = { NULL };
- FcCharSet *fccharset;
-- int i, f, numspecs = 0;
-+ int i, f, length = 0, start = 0, numspecs = 0;
-+ float cluster_xp = xp, cluster_yp = yp;
-+ HbTransformData shaped = { 0 };
-+
-+ /* Initial values. */
-+ mode = prevmode = glyphs[0].mode;
-+ xresetfontsettings(mode, &font, &frcflags);
-
- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
-- /* Fetch rune and mode for current glyph. */
-- rune = glyphs[i].u;
- mode = glyphs[i].mode;
-
- /* Skip dummy wide-character spacing. */
-- if (mode == ATTR_WDUMMY)
-+ if (mode & ATTR_WDUMMY && i < (len - 1))
- continue;
-
-- /* Determine font for glyph if different from previous glyph. */
-- if (prevmode != mode) {
-- prevmode = mode;
-- font = &dc.font;
-- frcflags = FRC_NORMAL;
-- runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
-- if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
-- font = &dc.ibfont;
-- frcflags = FRC_ITALICBOLD;
-- } else if (mode & ATTR_ITALIC) {
-- font = &dc.ifont;
-- frcflags = FRC_ITALIC;
-- } else if (mode & ATTR_BOLD) {
-- font = &dc.bfont;
-- frcflags = FRC_BOLD;
-+ if (
-+ prevmode != mode
-+ || ATTRCMP(glyphs[start], glyphs[i])
-+ || selected(x + i, y) != selected(x + start, y)
-+ || i == (len - 1)
-+ ) {
-+ /* Handle 1-character wide segments and end of line */
-+ length = i - start;
-+ if (i == start) {
-+ length = 1;
-+ } else if (i == (len - 1)) {
-+ length = (i - start + 1);
- }
-- yp = winy + font->ascent;
-- }
--
-- /* Lookup character index with default font. */
-- glyphidx = XftCharIndex(xw.dpy, font->match, rune);
-- if (glyphidx) {
-- specs[numspecs].font = font->match;
-- specs[numspecs].glyph = glyphidx;
-- specs[numspecs].x = (short)xp;
-- specs[numspecs].y = (short)yp;
-- xp += runewidth;
-- numspecs++;
-- continue;
-- }
-
-- /* Fallback on font cache, search the font cache for match. */
-- for (f = 0; f < frclen; f++) {
-- glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
-- /* Everything correct. */
-- if (glyphidx && frc[f].flags == frcflags)
-- break;
-- /* We got a default font for a not found glyph. */
-- if (!glyphidx && frc[f].flags == frcflags
-- && frc[f].unicodep == rune) {
-- break;
-+ /* Shape the segment. */
-+ hbtransform(&shaped, font->match, glyphs, start, length);
-+ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+ cluster_xp = xp; cluster_yp = yp;
-+ for (int code_idx = 0; code_idx < shaped.count; code_idx++) {
-+ int idx = shaped.glyphs[code_idx].cluster;
-+
-+ if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+ continue;
-+
-+ /* Advance the drawing cursor if we've moved to a new cluster */
-+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) {
-+ xp += runewidth;
-+ cluster_xp = xp;
-+ cluster_yp = yp;
-+ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+ }
-+
-+ if (shaped.glyphs[code_idx].codepoint != 0) {
-+ /* If symbol is found, put it into the specs. */
-+ specs[numspecs].font = font->match;
-+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint;
-+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.);
-+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.);
-+ cluster_xp += shaped.positions[code_idx].x_advance / 64.;
-+ cluster_yp += shaped.positions[code_idx].y_advance / 64.;
-+ numspecs++;
-+ } else {
-+ /* If it's not found, try to fetch it through the font cache. */
-+ rune = glyphs[start + idx].u;
-+ for (f = 0; f < frclen; f++) {
-+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
-+ /* Everything correct. */
-+ if (glyphidx && frc[f].flags == frcflags)
-+ break;
-+ /* We got a default font for a not found glyph. */
-+ if (!glyphidx && frc[f].flags == frcflags
-+ && frc[f].unicodep == rune) {
-+ break;
-+ }
-+ }
-+
-+ /* Nothing was found. Use fontconfig to find matching font. */
-+ if (f >= frclen) {
-+ if (!font->set)
-+ font->set = FcFontSort(0, font->pattern,
-+ 1, 0, &fcres);
-+ fcsets[0] = font->set;
-+
-+ /*
-+ * Nothing was found in the cache. Now use
-+ * some dozen of Fontconfig calls to get the
-+ * font for one single character.
-+ *
-+ * Xft and fontconfig are design failures.
-+ */
-+ fcpattern = FcPatternDuplicate(font->pattern);
-+ fccharset = FcCharSetCreate();
-+
-+ FcCharSetAddChar(fccharset, rune);
-+ FcPatternAddCharSet(fcpattern, FC_CHARSET,
-+ fccharset);
-+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
-+
-+ FcConfigSubstitute(0, fcpattern,
-+ FcMatchPattern);
-+ FcDefaultSubstitute(fcpattern);
-+
-+ fontpattern = FcFontSetMatch(0, fcsets, 1,
-+ fcpattern, &fcres);
-+
-+ /* Allocate memory for the new cache entry. */
-+ if (frclen >= frccap) {
-+ frccap += 16;
-+ frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+ }
-+
-+ frc[frclen].font = XftFontOpenPattern(xw.dpy,
-+ fontpattern);
-+ if (!frc[frclen].font)
-+ die("XftFontOpenPattern failed seeking fallback font: %s\n",
-+ strerror(errno));
-+ frc[frclen].flags = frcflags;
-+ frc[frclen].unicodep = rune;
-+
-+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
-+
-+ f = frclen;
-+ frclen++;
-+
-+ FcPatternDestroy(fcpattern);
-+ FcCharSetDestroy(fccharset);
-+ }
-+
-+ specs[numspecs].font = frc[f].font;
-+ specs[numspecs].glyph = glyphidx;
-+ specs[numspecs].x = (short)xp;
-+ specs[numspecs].y = (short)yp;
-+ numspecs++;
-+ }
- }
-- }
--
-- /* Nothing was found. Use fontconfig to find matching font. */
-- if (f >= frclen) {
-- if (!font->set)
-- font->set = FcFontSort(0, font->pattern,
-- 1, 0, &fcres);
-- fcsets[0] = font->set;
-
-- /*
-- * Nothing was found in the cache. Now use
-- * some dozen of Fontconfig calls to get the
-- * font for one single character.
-- *
-- * Xft and fontconfig are design failures.
-- */
-- fcpattern = FcPatternDuplicate(font->pattern);
-- fccharset = FcCharSetCreate();
--
-- FcCharSetAddChar(fccharset, rune);
-- FcPatternAddCharSet(fcpattern, FC_CHARSET,
-- fccharset);
-- FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
-+ /* Cleanup and get ready for next segment. */
-+ hbcleanup(&shaped);
-+ start = i;
-
-- FcConfigSubstitute(0, fcpattern,
-- FcMatchPattern);
-- FcDefaultSubstitute(fcpattern);
--
-- fontpattern = FcFontSetMatch(0, fcsets, 1,
-- fcpattern, &fcres);
--
-- /* Allocate memory for the new cache entry. */
-- if (frclen >= frccap) {
-- frccap += 16;
-- frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+ /* Determine font for glyph if different from previous glyph. */
-+ if (prevmode != mode) {
-+ prevmode = mode;
-+ xresetfontsettings(mode, &font, &frcflags);
-+ yp = winy + font->ascent;
- }
--
-- frc[frclen].font = XftFontOpenPattern(xw.dpy,
-- fontpattern);
-- if (!frc[frclen].font)
-- die("XftFontOpenPattern failed seeking fallback font: %s\n",
-- strerror(errno));
-- frc[frclen].flags = frcflags;
-- frc[frclen].unicodep = rune;
--
-- glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
--
-- f = frclen;
-- frclen++;
--
-- FcPatternDestroy(fcpattern);
-- FcCharSetDestroy(fccharset);
- }
--
-- specs[numspecs].font = frc[f].font;
-- specs[numspecs].glyph = glyphidx;
-- specs[numspecs].x = (short)xp;
-- specs[numspecs].y = (short)yp;
-- xp += runewidth;
-- numspecs++;
- }
-
- return numspecs;
-@@ -1534,14 +1584,17 @@ xdrawglyph(Glyph g, int x, int y)
- }
-
- void
--xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
-+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
- {
- Color drawcol;
-
- /* remove the old cursor */
- if (selected(ox, oy))
- og.mode ^= ATTR_REVERSE;
-- xdrawglyph(og, ox, oy);
-+
-+ /* Redraw the line where cursor was previously.
-+ * It will restore the ligatures broken by the cursor. */
-+ xdrawline(line, 0, oy, len);
-
- if (IS_SET(MODE_HIDE))
- return;
-@@ -1669,18 +1722,16 @@ xdrawline(Line line, int x1, int y1, int x2)
- Glyph base, new;
- XftGlyphFontSpec *specs = xw.specbuf;
-
-- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
- i = ox = 0;
-- for (x = x1; x < x2 && i < numspecs; x++) {
-+ for (x = x1; x < x2; x++) {
- new = line[x];
- if (new.mode == ATTR_WDUMMY)
- continue;
- if (selected(x, y1))
- new.mode ^= ATTR_REVERSE;
-- if (i > 0 && ATTRCMP(base, new)) {
-- xdrawglyphfontspecs(specs, base, i, ox, y1);
-- specs += i;
-- numspecs -= i;
-+ if ((i > 0) && ATTRCMP(base, new)) {
-+ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1);
-+ xdrawglyphfontspecs(specs, base, numspecs, ox, y1);
- i = 0;
- }
- if (i == 0) {
-@@ -1689,8 +1740,10 @@ xdrawline(Line line, int x1, int y1, int x2)
- }
- i++;
- }
-- if (i > 0)
-- xdrawglyphfontspecs(specs, base, i, ox, y1);
-+ if (i > 0) {
-+ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1);
-+ xdrawglyphfontspecs(specs, base, numspecs, ox, y1);
-+ }
- }
-
- void