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 }