URI: 
       text2.c - ltkx - GUI toolkit for X11 (old)
  HTML git clone git://lumidify.org/ltkx.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/ltkx.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltkx.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR 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 }