ltkx

GUI toolkit for X11 (old)
git clone git://lumidify.org/ltkx.git (fast, but not encrypted)
git clone https://lumidify.org/ltkx.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltkx.git (over tor)
Log | Files | Refs | README | LICENSE

text2.c (8342B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <stdint.h>
      4 #include <X11/Xlib.h>
      5 #include <X11/Xutil.h>
      6 #include "stb_truetype.h"
      7 #include <harfbuzz/hb.h>
      8 #include <harfbuzz/hb-ot.h>
      9 
     10 /* These unicode routines are taken from
     11  * https://github.com/JeffBezanson/cutef8 */
     12 
     13 /* is c the start of a utf8 sequence? */
     14 #define isutf(c) (((c)&0xC0)!=0x80)
     15 
     16 static const uint32_t offsetsFromUTF8[6] = {
     17     0x00000000UL, 0x00003080UL, 0x000E2080UL,
     18     0x03C82080UL, 0xFA082080UL, 0x82082080UL
     19 };
     20 
     21 /* next character without NUL character terminator */
     22 uint32_t u8_nextmemchar(const char *s, size_t *i)
     23 {
     24     uint32_t ch = 0;
     25     size_t sz = 0;
     26     do {
     27         ch <<= 6;
     28         ch += (unsigned char)s[(*i)++];
     29         sz++;
     30     } while (!isutf(s[*i]));
     31     ch -= offsetsFromUTF8[sz-1];
     32 
     33     return ch;
     34 }
     35 
     36 
     37 #define STB_TRUETYPE_IMPLEMENTATION
     38 #include "stb_truetype.h" /* http://nothings.org/stb/stb_truetype.h */
     39 
     40 stbtt_fontinfo ltk_load_font(const char *path)
     41 {
     42 	FILE *f;
     43 	long len;
     44 	char *contents;
     45 	stbtt_fontinfo info;
     46 	f = fopen(path, "rb");
     47 	fseek(f, 0, SEEK_END);
     48 	len = ftell(f);
     49 	fseek(f, 0, SEEK_SET);
     50 	contents = malloc(len + 1);
     51 	fread(contents, 1, len, f);
     52 	contents[len] = '\0';
     53 	fclose(f);
     54 	if (!stbtt_InitFont(&info, contents, 0))
     55 	{
     56 		fprintf(stderr, "Failed to load font %s\n", path);
     57 		exit(1);
     58 	}
     59 	return info;
     60 }
     61 
     62 char *ltk_load_file(const char *path, unsigned long *len)
     63 {
     64 	FILE *f;
     65 	char *contents;
     66 	f = fopen(path, "rb");
     67 	fseek(f, 0, SEEK_END);
     68 	*len = ftell(f);
     69 	fseek(f, 0, SEEK_SET);
     70 	contents = malloc(*len + 1);
     71 	fread(contents, 1, *len, f);
     72 	contents[*len] = '\0';
     73 	fclose(f);
     74 	return contents;
     75 }
     76 
     77 int ltk_text_width(uint8_t *text, stbtt_fontinfo fontinfo, int height)
     78 {
     79 	float scale = stbtt_ScaleForMappingEmToPixels(&fontinfo, height);
     80 	size_t i = 0;
     81 	int length = strlen(text);
     82 	if (length < 1) return 0;
     83 	int temp_x;
     84 	int kern_advance;
     85 	int width = 0;
     86 	uint32_t char1;
     87 	uint32_t char2;
     88 	char1 = u8_nextmemchar(text, &i);
     89 	while(i <= length)
     90 	{
     91 		stbtt_GetCodepointHMetrics(&fontinfo, char1, &temp_x, 0);
     92 		width += temp_x * scale;
     93 
     94 		char2 = u8_nextmemchar(text, &i);
     95 		if (!char2) break;
     96 		kern_advance = stbtt_GetCodepointKernAdvance(&fontinfo, char1, char2);
     97 		width += kern_advance * scale;
     98 		char1 = char2;
     99 	}
    100 
    101 	return width;
    102 }
    103 
    104 unsigned long ltk_blend_pixel(Display *display, Colormap colormap, XColor fg, XColor bg, double a)
    105 {
    106         XColor blended;
    107         if (a == 1.0)
    108                 return fg.pixel;
    109         else if (a == 0.0)
    110                 return bg.pixel;
    111         blended.red = (int)((fg.red - bg.red) * a + bg.red);
    112         blended.green = (int)((fg.green - bg.green) * a + bg.green);
    113         blended.blue = (int)((fg.blue - bg.blue) * a + bg.blue);
    114         XAllocColor(display, colormap, &blended);
    115 
    116         return blended.pixel;
    117 }
    118 
    119 Pixmap ltk_render_text(
    120 	Display *display,
    121 	Window window,
    122 	GC gc,
    123 	uint8_t *text,
    124 	stbtt_fontinfo fontinfo,
    125 	int height,
    126 	XColor fg,
    127 	XColor bg,
    128 	const char *font_,
    129 	Colormap colormap
    130 )
    131 {
    132 	hb_blob_t *blob;
    133 	hb_face_t *face;
    134 	size_t filelen = 0;
    135 	char *filedata = ltk_load_file(font_, &filelen);
    136 	blob = hb_blob_create(filedata, filelen, HB_MEMORY_MODE_READONLY, NULL, NULL);
    137 	face = hb_face_create(blob, 0);
    138 	hb_blob_destroy(blob);
    139 	hb_font_t *hbfont = hb_font_create(face);
    140 	hb_face_destroy(face);
    141 	hb_ot_font_set_funcs(hbfont);
    142 
    143 	hb_buffer_t *buf;
    144 	hb_glyph_info_t *ginf;
    145 	hb_glyph_position_t *gpos;
    146 	unsigned int len = 0;
    147 
    148 	buf = hb_buffer_create();
    149 	hb_buffer_set_flags(buf, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
    150 	hb_buffer_add_utf8(buf, text, -1, 0, -1);
    151 	hb_buffer_guess_segment_properties(buf);
    152 	hb_shape(hbfont, buf, NULL, 0);
    153 
    154 	ginf = hb_buffer_get_glyph_infos(buf, &len);
    155 	gpos = hb_buffer_get_glyph_positions(buf, &len);
    156 
    157 	XWindowAttributes attrs;
    158 	XGetWindowAttributes(display, window, &attrs);
    159 	int depth = attrs.depth;
    160 
    161 	int width = ltk_text_width(text, fontinfo, height) + 200;
    162 	float scale = stbtt_ScaleForMappingEmToPixels(&fontinfo, height);
    163 
    164 	int ascent, descent, line_gap;
    165 	stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &line_gap);
    166 	ascent *= scale;
    167 	descent *= scale;
    168 
    169 	Pixmap rendered = XCreatePixmap(display, window, width, height + 200, depth);
    170 	unsigned char *bitmap = calloc(width * (height + 200), sizeof(char));
    171 	int length = strlen(text);
    172 	if (length < 1)
    173 	{
    174 		printf("WARNING: ltk_render_text: length of text is less than 1.\n");
    175 		return XCreatePixmap(display, window, 0, 0, depth);
    176 	}
    177 	int ax, x = 0, y = 0, x1, y1, x2, y2, byte_offset, kern_advance;
    178 	double x_abs = 0, y_abs = 0;
    179 	unsigned char *b;
    180 	int w, h, xoff, yoff;
    181 	for (int i = 0; i < len; i++)
    182 	{
    183 		hb_glyph_info_t *gi = &ginf[i];
    184 		hb_glyph_position_t *gp = &gpos[i];
    185 		stbtt_GetGlyphBitmapBox(&fontinfo, gi->codepoint, scale, scale, &x1, &y1, &x2, &y2);
    186 		x = (int)(x_abs + (gp->x_offset * scale));
    187 		y = (int)((y_abs + 20) + (gp->y_offset * scale));
    188 		printf("%d\n", (int)(gp->y_offset * scale));
    189 		byte_offset = x + (y  * width);
    190 		b = stbtt_GetGlyphBitmap(&fontinfo, scale, scale, gi->codepoint, &w, &h, &xoff, &yoff);
    191 
    192 		for (int i = 0; i < h; i++)
    193 		{
    194 			for (int j = 0; j < w; j++)
    195 			{
    196 				bitmap[(y + i) * width + (x + j)] = bitmap[(y + i) * width + (x + j)] + b[i * w + j];
    197 				if (bitmap[(y + i) * width + (x + j)] > 255) bitmap[(y + i) * width + (x + j)] = 255;
    198 			}
    199 		}
    200 		free(b);
    201 
    202 		x_abs += (gp->x_advance * scale);
    203 		y_abs -= (gp->y_advance * scale);
    204 	}
    205 
    206                 XSetForeground(display, gc, bg.pixel);
    207                 for (int i = 0; i < height + 200; i++)
    208                 {
    209                         for (int j = 0; j < width; j++)
    210                         {
    211                                 /* Yay! Magic! */
    212                                 XSetForeground(display, gc, ltk_blend_pixel(display, colormap, fg, bg, (bitmap[i * width + j] / 255.0)));
    213                                 XDrawPoint(display, rendered, gc, j, i);
    214                         }
    215                 }
    216                 XSetForeground(display, gc, bg.pixel);
    217 
    218 	/* TODO: separate this into a separate function so that one function only creates
    219 	 * the bitmap and other functions to turn that into a pixmap with solid color
    220 	 * background, image background, etc.
    221 	 */
    222 	return rendered;
    223 }
    224 
    225 int main(int argc, char *argv[])
    226 {
    227     Display *display;
    228     int screen;
    229     Window window;
    230     GC gc;
    231 
    232     unsigned long black, white;
    233     Colormap colormap;
    234     display = XOpenDisplay((char *)0);
    235     screen = DefaultScreen(display);
    236     colormap = DefaultColormap(display, screen);
    237     black = BlackPixel(display, screen);
    238     white = WhitePixel(display, screen);
    239     window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, 1366, 512, 0, black, white);
    240     XSetStandardProperties(display, window, "Random Window", NULL, None, NULL, 0, NULL);
    241     XSelectInput(display, window, ExposureMask|ButtonPressMask|KeyPressMask);
    242     gc = XCreateGC(display, window, 0, 0);
    243     XSetBackground(display, gc, black);
    244     XSetForeground(display, gc, black);
    245     XClearWindow(display, window);
    246     XMapRaised(display, window);
    247     XColor c1, c2;
    248     XParseColor(display, colormap, "#FFFFFF", &c1);
    249     XParseColor(display, colormap, "#FF0000", &c2);
    250     XAllocColor(display, colormap, &c1);
    251     XAllocColor(display, colormap, &c2);
    252 
    253 //    stbtt_fontinfo fontinfo = ltk_load_font("GentiumPlus-R.ttf");
    254     stbtt_fontinfo fontinfo = ltk_load_font("NotoNastaliqUrdu-Regular.ttf");
    255     int width = ltk_text_width("ہمارے بارے میںdsfasffsfadsf", fontinfo, 200);
    256     Pixmap pix = ltk_render_text(display, window, gc, "ہمارے بارے میں", fontinfo, 100, c1, c2, "NotoNastaliqUrdu-Regular.ttf", colormap);
    257 //    Pixmap pix = ltk_render_text(display, window, gc, "Bob", fontinfo, 200, c1.pixel, c2.pixel, "GentiumPlus-R.ttf");
    258     XCopyArea(display, pix, window, gc, 0, 0, width, 200, 0, 0);
    259 
    260     XEvent event;
    261     KeySym key;
    262     char text[255];
    263 
    264     while(1)
    265     {
    266         XNextEvent(display, &event);
    267         if (event.type == KeyPress && XLookupString(&event.xkey, text, 255, &key, 0) == 1)
    268         {
    269             XCopyArea(display, pix, window, gc, 0, 0, width, 300, 0, 0);
    270             if (text[0] == 'q')
    271             {
    272                 XFreeGC(display, gc);
    273                 XFreeColormap(display, colormap);
    274                 XDestroyWindow(display, window);
    275                 XCloseDisplay(display);
    276                 exit(0);
    277             }
    278         }
    279     }
    280     
    281     return 0;
    282 }