Added ligature-boxdraw v0.9 patch
This commit is contained in:
		
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  | ||||
| include config.mk | ||||
|  | ||||
| SRC = st.c x.c boxdraw.c | ||||
| SRC = st.c x.c boxdraw.c hb.c | ||||
| OBJ = $(SRC:.c=.o) | ||||
|  | ||||
| all: options st | ||||
| @@ -22,8 +22,9 @@ 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 | ||||
| boxdraw.o: config.h st.h boxdraw_data.h | ||||
| hb.o: st.h | ||||
|  | ||||
| $(OBJ): config.h config.mk | ||||
|  | ||||
|   | ||||
| @@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config | ||||
| # includes and libs | ||||
| INCS = -I$(X11INC) \ | ||||
|        `$(PKG_CONFIG) --cflags fontconfig` \ | ||||
|        `$(PKG_CONFIG) --cflags freetype2` | ||||
|        `$(PKG_CONFIG) --cflags freetype2` \ | ||||
|        `$(PKG_CONFIG) --cflags harfbuzz` | ||||
| LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ | ||||
|        `$(PKG_CONFIG) --libs fontconfig` \ | ||||
|        `$(PKG_CONFIG) --libs freetype2` | ||||
|        `$(PKG_CONFIG) --libs freetype2` \ | ||||
|        `$(PKG_CONFIG) --libs harfbuzz` | ||||
|  | ||||
| # flags | ||||
| STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 | ||||
|   | ||||
							
								
								
									
										124
									
								
								hb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								hb.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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)); | ||||
| } | ||||
							
								
								
									
										14
									
								
								hb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								hb.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 *); | ||||
							
								
								
									
										3
									
								
								st.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								st.c
									
									
									
									
									
								
							| @@ -2655,7 +2655,8 @@ draw(void) | ||||
|  | ||||
| 	drawregion(0, 0, term.col, term.row); | ||||
| 	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(); | ||||
|   | ||||
							
								
								
									
										3
									
								
								st.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								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) | ||||
|   | ||||
							
								
								
									
										2
									
								
								win.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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); | ||||
|   | ||||
							
								
								
									
										290
									
								
								x.c
									
									
									
									
									
								
							
							
						
						
									
										290
									
								
								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 { | ||||
| @@ -141,6 +142,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, int); | ||||
| static void xdrawglyph(Glyph, int, int); | ||||
| @@ -757,7 +759,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 | ||||
| @@ -1062,6 +1064,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); | ||||
| @@ -1185,7 +1190,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); | ||||
| @@ -1241,6 +1246,22 @@ xinit(int cols, int rows) | ||||
| 	boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
| @@ -1255,126 +1276,158 @@ 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; | ||||
| 			} | ||||
| 			yp = winy + font->ascent; | ||||
| 		} | ||||
|  | ||||
| 		if (mode & ATTR_BOXDRAW) { | ||||
| 			/* minor shoehorning: boxdraw uses only this ushort */ | ||||
| 			glyphidx = boxdrawindex(&glyphs[i]); | ||||
| 		} else { | ||||
| 			/* 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; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* 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)); | ||||
| 		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); | ||||
| 			} | ||||
|  | ||||
| 			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; | ||||
| 			/* 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; | ||||
|  | ||||
| 			glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); | ||||
| 				if (glyphs[start + idx].mode & ATTR_WDUMMY) | ||||
| 					continue; | ||||
|  | ||||
| 			f = frclen; | ||||
| 			frclen++; | ||||
| 				/* 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); | ||||
| 				} | ||||
|  | ||||
| 			FcPatternDestroy(fcpattern); | ||||
| 			FcCharSetDestroy(fccharset); | ||||
| 				if (glyphs[start + code_idx].mode & ATTR_BOXDRAW) { | ||||
| 					/* minor shoehorning: boxdraw uses only this ushort */ | ||||
| 					specs[numspecs].font = font->match; | ||||
| 					specs[numspecs].glyph = boxdrawindex(&glyphs[start + code_idx]); | ||||
| 					specs[numspecs].x = xp; | ||||
| 					specs[numspecs].y = yp; | ||||
| 					numspecs++; | ||||
| 				} else 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++; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			/* Cleanup and get ready for next segment. */ | ||||
| 			hbcleanup(&shaped); | ||||
| 			start = i; | ||||
|  | ||||
| 			/* Determine font for glyph if different from previous glyph. */ | ||||
| 			if (prevmode != mode) { | ||||
| 				prevmode = mode; | ||||
| 				xresetfontsettings(mode, &font, &frcflags); | ||||
| 				yp = winy + font->ascent; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		specs[numspecs].font = frc[f].font; | ||||
| 		specs[numspecs].glyph = glyphidx; | ||||
| 		specs[numspecs].x = (short)xp; | ||||
| 		specs[numspecs].y = (short)yp; | ||||
| 		xp += runewidth; | ||||
| 		numspecs++; | ||||
| 	} | ||||
|  | ||||
| 	hbcleanup(&shaped); | ||||
| 	return numspecs; | ||||
| } | ||||
|  | ||||
| @@ -1522,14 +1575,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; | ||||
| @@ -1663,18 +1719,16 @@ xdrawline(Line line, int x1, int y1, int x2) | ||||
|        won't get truncated (#223) */ | ||||
| 	for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { | ||||
| 		specs = xw.specbuf; | ||||
| 		numspecs = numspecs_cached; | ||||
| 		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, dmode); | ||||
| 				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) { | ||||
| @@ -1683,8 +1737,10 @@ xdrawline(Line line, int x1, int y1, int x2) | ||||
| 			} | ||||
| 			i++; | ||||
| 		} | ||||
| 		if (i > 0) | ||||
| 			xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); | ||||
| 		 if (i > 0) { | ||||
|                  	numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); | ||||
|                 	xdrawglyphfontspecs(specs, base, numspecs, ox, y1); | ||||
|         	} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user