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 }