text.c (7891B)
1 #include <X11/Xlib.h> 2 #include <X11/Xutil.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <stdint.h> 6 #include "stb_truetype.h" 7 #include <graphite2/Segment.h> 8 9 /* These unicode routines are taken from 10 * https://github.com/JeffBezanson/cutef8 */ 11 12 /* is c the start of a utf8 sequence? */ 13 #define isutf(c) (((c)&0xC0)!=0x80) 14 15 static const uint32_t offsetsFromUTF8[6] = { 16 0x00000000UL, 0x00003080UL, 0x000E2080UL, 17 0x03C82080UL, 0xFA082080UL, 0x82082080UL 18 }; 19 20 /* next character without NUL character terminator */ 21 uint32_t u8_nextmemchar(const char *s, size_t *i) 22 { 23 uint32_t ch = 0; 24 size_t sz = 0; 25 do { 26 ch <<= 6; 27 ch += (unsigned char)s[(*i)++]; 28 sz++; 29 } while (!isutf(s[*i])); 30 ch -= offsetsFromUTF8[sz-1]; 31 32 return ch; 33 } 34 35 36 #define STB_TRUETYPE_IMPLEMENTATION 37 #include "stb_truetype.h" /* http://nothings.org/stb/stb_truetype.h */ 38 39 stbtt_fontinfo ltk_load_font(const char *path) 40 { 41 FILE *f; 42 long len; 43 char *contents; 44 stbtt_fontinfo info; 45 f = fopen(path, "rb"); 46 fseek(f, 0, SEEK_END); 47 len = ftell(f); 48 fseek(f, 0, SEEK_SET); 49 contents = malloc(len + 1); 50 fread(contents, 1, len, f); 51 contents[len] = '\0'; 52 fclose(f); 53 if (!stbtt_InitFont(&info, contents, 0)) 54 { 55 fprintf(stderr, "Failed to load font %s\n", path); 56 exit(1); 57 } 58 return info; 59 } 60 61 int ltk_text_width(uint8_t *text, stbtt_fontinfo fontinfo, int height) 62 { 63 float scale = stbtt_ScaleForPixelHeight(&fontinfo, height); 64 size_t i = 0; 65 int length = strlen(text); 66 if (length < 1) return 0; 67 int temp_x; 68 int kern_advance; 69 int width = 0; 70 uint32_t char1; 71 uint32_t char2; 72 char1 = u8_nextmemchar(text, &i); 73 while(i <= length) 74 { 75 stbtt_GetCodepointHMetrics(&fontinfo, char1, &temp_x, 0); 76 width += temp_x * scale; 77 78 char2 = u8_nextmemchar(text, &i); 79 if (!char2) break; 80 kern_advance = stbtt_GetCodepointKernAdvance(&fontinfo, char1, char2); 81 width += kern_advance * scale; 82 char1 = char2; 83 } 84 85 return width; 86 } 87 88 Pixmap ltk_render_text( 89 Display *display, 90 Window window, 91 GC gc, 92 uint8_t *text, 93 stbtt_fontinfo fontinfo, 94 int height, 95 unsigned long fg, 96 unsigned long bg, 97 const char *font_ 98 ) 99 { 100 int rtl = 1; /*are we rendering right to left? probably not */ 101 int pointsize = 24; /*point size in points */ 102 int dpi = 96; /*work with this many dots per inch */ 103 char *pError; /*location of faulty utf-8 */ 104 gr_font *font = NULL; 105 size_t numCodePoints = 0; 106 gr_segment *seg = NULL; 107 const gr_slot *s; 108 gr_face *face = gr_make_file_face(font_, 0); 109 if (!face) return 1; 110 //font = gr_make_font(pointsize * dpi / 72.0f, face); 111 font = gr_make_font(pointsize * dpi / 72.0f, face); 112 if (!font) return 2; 113 numCodePoints = gr_count_unicode_characters(gr_utf8, text, NULL, (const void **)(&pError)); 114 if (pError) return 3; 115 seg = gr_make_seg(font, face, 0, 0, gr_utf8, text, numCodePoints, rtl); 116 if (!seg) return 3; 117 for (s = gr_seg_first_slot(seg); s; s = gr_slot_next_in_segment(s)) 118 printf("%d(%f,%f) ", gr_slot_gid(s), gr_slot_origin_X(s), gr_slot_origin_Y(s)); 119 //printf("\n%f\n", gr_seg_advance_X(seg)); 120 121 XWindowAttributes attrs; 122 XGetWindowAttributes(display, window, &attrs); 123 int depth = attrs.depth; 124 125 // int width = ltk_text_width(text, fontinfo, height); 126 int width = (int)gr_seg_advance_X(seg) + 100; 127 unsigned char *bitmap = calloc(sizeof(char), width * (height + 200)); 128 //float scale = stbtt_ScaleForPixelHeight(&fontinfo, pointsize * dpi / 72.0f); 129 float scale = stbtt_ScaleForMappingEmToPixels(&fontinfo, pointsize * dpi / 72.0f); 130 131 int ascent, descent, line_gap; 132 stbtt_GetFontVMetrics(&fontinfo, &ascent, &descent, &line_gap); 133 ascent *= scale; 134 descent *= scale; 135 136 size_t i = 0; 137 int length = strlen(text); 138 if (length < 1) 139 { 140 printf("WARNING: ltk_render_text: length of text is less than 1.\n"); 141 return XCreatePixmap(display, window, 0, 0, depth); 142 } 143 uint32_t char1, char2; 144 char1 = u8_nextmemchar(text, &i); 145 int ax, lsb, x = 0, y = 0, x1, y1, x2, y2, byte_offset, kern_advance; 146 int w, h, xoff, yoff; 147 int y_abs = 0; 148 // while (i <= length) 149 unsigned char *b; 150 for (s = gr_seg_first_slot(seg); s; s = gr_slot_next_in_segment(s)) 151 { 152 stbtt_GetGlyphBitmapBox(&fontinfo, gr_slot_gid(s), scale, scale, &x1, &y1, &x2, &y2); 153 //stbtt_MakeGlyphBitmap(&fontinfo, bitmap + byte_offset, x2 - x1, y2 - y1, width, scale, scale, gr_slot_gid(s)); 154 b = stbtt_GetGlyphBitmap(&fontinfo, scale, scale, gr_slot_gid(s), &w, &h, &xoff, &yoff); 155 x = (int)(50 + xoff + gr_slot_origin_X(s)); 156 y = (int)(200 + yoff - gr_slot_origin_Y(s)); 157 for (int i = 0; i < h; i++) 158 { 159 for (int j = 0; j < w; j++) 160 { 161 byte_offset = (y + i) * width + x + j; 162 bitmap[byte_offset] = bitmap[byte_offset] + b[i * w + j]; 163 if (bitmap[byte_offset] > 255) bitmap[byte_offset] = 255; 164 } 165 } 166 free(b); 167 } 168 gr_seg_destroy(seg); 169 gr_font_destroy(font); 170 gr_face_destroy(face); 171 172 /* TODO: separate this into a separate function so that one function only creates 173 * the bitmap and other functions to turn that into a pixmap with solid color 174 * background, image background, etc. 175 */ 176 Pixmap rendered = XCreatePixmap(display, window, width, height + 200, depth); 177 XSetForeground(display, gc, bg); 178 for (int i = 0; i < (height + 200); i++) 179 { 180 for (int j = 0; j < width; j++) 181 { 182 /* Yay! Magic! */ 183 XSetForeground(display, gc, (bitmap[i * width + j] / 255.0) * fg + (1 - bitmap[i * width + j] / 255.0) * bg); 184 XDrawPoint(display, rendered, gc, j, i); 185 } 186 } 187 XSetForeground(display, gc, bg); 188 return rendered; 189 } 190 191 int main(int argc, char *argv[]) 192 { 193 Display *display; 194 int screen; 195 Window window; 196 GC gc; 197 198 unsigned long black, white; 199 Colormap colormap; 200 display = XOpenDisplay((char *)0); 201 screen = DefaultScreen(display); 202 colormap = DefaultColormap(display, screen); 203 black = BlackPixel(display, screen); 204 white = WhitePixel(display, screen); 205 window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, 1366, 512, 0, black, white); 206 XSetStandardProperties(display, window, "Random Window", NULL, None, NULL, 0, NULL); 207 XSelectInput(display, window, ExposureMask|ButtonPressMask|KeyPressMask); 208 gc = XCreateGC(display, window, 0, 0); 209 XSetBackground(display, gc, black); 210 XSetForeground(display, gc, black); 211 XClearWindow(display, window); 212 XMapRaised(display, window); 213 XColor c1, c2; 214 XParseColor(display, colormap, "#FFFFFF", &c1); 215 XParseColor(display, colormap, "#FF0000", &c2); 216 XAllocColor(display, colormap, &c1); 217 XAllocColor(display, colormap, &c2); 218 219 stbtt_fontinfo fontinfo = ltk_load_font("Awami_beta3.ttf"); 220 int width = ltk_text_width("ہمارے بارے میںffsafdsfasfasf", fontinfo, 100); 221 Pixmap pix = ltk_render_text(display, window, gc, "ہمارے بارے میں", fontinfo, 64, c1.pixel, c2.pixel, "Awami_beta3.ttf"); 222 // Pixmap pix = ltk_render_text(display, window, gc, "Bob", fontinfo, 64, c1.pixel, c2.pixel, "GentiumPlus-R.ttf"); 223 XCopyArea(display, pix, window, gc, 0, 0, width, 64, 0, 0); 224 225 XEvent event; 226 KeySym key; 227 char text[255]; 228 229 while(1) 230 { 231 XNextEvent(display, &event); 232 if (event.type == KeyPress && XLookupString(&event.xkey, text, 255, &key, 0) == 1) 233 { 234 XCopyArea(display, pix, window, gc, 0, 0, width, 300, 0, 0); 235 if (text[0] == 'q') 236 { 237 XFreeGC(display, gc); 238 XFreeColormap(display, colormap); 239 XDestroyWindow(display, window); 240 XCloseDisplay(display); 241 exit(0); 242 } 243 } 244 } 245 246 return 0; 247 }