1 #include "cfg.h"
2 
3 #if defined(G) && defined(HAVE_FREETYPE)
4 
5 #include "links.h"
6 
7 #include <ft2build.h>
8 #include FT_FREETYPE_H
9 #ifdef FT_BITMAP_H
10 #include FT_BITMAP_H
11 #endif
12 
13 #ifdef FT_LOAD_TARGET_LCD
14 #define select_lcd(x, y)	(!display_optimize ? (x) : (y))
15 #define ret_if_lcd		do { } while (0)
16 #else
17 #define select_lcd(x, y)	(x)
18 #define ret_if_lcd		if (display_optimize) return -1
19 #endif
20 
21 struct freetype_face {
22 	unsigned char *path;
23 	FT_Face face;
24 	float baseline;
25 	int allocated;
26 };
27 
28 struct freetype_face faces[FF_SHAPES];
29 
30 static int ft_initialized = 0;
31 static FT_Library library;
32 
33 struct lru_entry **freetype_cache = NULL;
34 
35 struct metric_cache_entry {
36 	struct freetype_face *face;
37 	int char_number;
38 	int y;
39 	unsigned char flags;
40 	int x;
41 };
42 
43 #define sizeof_freetype_metric_cache	65536
44 static struct metric_cache_entry *freetype_metric_cache = NULL;
45 
freetype_flags_to_face(int fflags)46 struct freetype_face *freetype_flags_to_face(int fflags)
47 {
48 	fflags &= FF_SHAPES - 1;
49 	if (faces[fflags].path)
50 		return &faces[fflags];
51 	return NULL;
52 }
53 
cleanup_state(struct freetype_face * face)54 static void cleanup_state(struct freetype_face *face)
55 {
56 	if (face->path) {
57 		mem_free(face->path);
58 		FT_Done_Face(face->face);
59 	}
60 	memset(face, 0, sizeof(struct freetype_face));
61 	memset(freetype_metric_cache, 0, sizeof_freetype_metric_cache * sizeof(struct metric_cache_entry));
62 }
63 
calculate_baseline(struct freetype_face * face)64 static void calculate_baseline(struct freetype_face *face)
65 {
66 	float val;
67 	int h = face->face->height;
68 	int asc = face->face->ascender;
69 	int desc = -face->face->descender;
70 	int ad = asc + desc;
71 	if (ad > h)
72 		h = ad;
73 	if (!h)
74 		h = 1;
75 	val = (desc + (float)(h - ad) / 2) / h;
76 	/*fprintf(stderr, "calculat_baseline: %f %f\n", val, 1 / val);*/
77 	face->baseline = val;
78 }
79 
freetype_setup_font(struct freetype_face * face,unsigned char * path)80 static void freetype_setup_font(struct freetype_face *face, unsigned char *path)
81 {
82 	unsigned char *idx_ptr;
83 	long idx;
84 
85 	if (!ft_initialized)
86 		return;
87 
88 	if (!freetype_cache)
89 		freetype_cache = mem_calloc(sizeof_freetype_cache * sizeof(struct lru_entry *));
90 
91 	if (!freetype_metric_cache)
92 		freetype_metric_cache = mem_calloc(sizeof_freetype_metric_cache * sizeof(struct metric_cache_entry));
93 
94 	cleanup_state(face);
95 
96 	if (!path || !*path)
97 		return;
98 
99 	face->path = stracpy(path);
100 	idx = 0;
101 
102 	idx_ptr = cast_uchar strrchr(cast_const_char face->path, '@');
103 	if (idx_ptr && idx_ptr != face->path && idx_ptr[-1] == ' ' && idx_ptr[1]) {
104 		char *end;
105 		idx = strtol(cast_const_char (idx_ptr + 1), &end, 10);
106 		if (!*end) {
107 			idx_ptr[-1] = 0;
108 		} else {
109 			idx = 0;
110 		}
111 
112 	}
113 
114 	if (FT_New_Face(library, cast_const_char path, idx, &face->face)) {
115 		mem_free(face->path);
116 		face->path = NULL;
117 		return;
118 	}
119 
120 	calculate_baseline(face);
121 
122 	/*fprintf(stderr, "%d %d %d", face->face->height, face->face->ascender, face->face->descender);*/
123 }
124 
freetype_get_font(unsigned char * path)125 struct freetype_face *freetype_get_font(unsigned char *path)
126 {
127 	struct freetype_face *face = mem_calloc(sizeof(struct freetype_face));
128 	freetype_setup_font(face, path);
129 	if (!face->path) {
130 		mem_free(face);
131 		return NULL;
132 	}
133 	face->allocated = 1;
134 	return face;
135 }
136 
freetype_free_font(struct freetype_face * face)137 void freetype_free_font(struct freetype_face *face)
138 {
139 	if (face->allocated) {
140 		cleanup_state(face);
141 		mem_free(face);
142 	}
143 }
144 
freetype_get_allocated_font_name(struct style * st)145 unsigned char *freetype_get_allocated_font_name(struct style *st)
146 {
147 	if (st->ft_face && st->ft_face->allocated)
148 		return stracpy(st->ft_face->path);
149 	return NULL;
150 }
151 
get_baseline(struct freetype_face * face,int y)152 static inline int get_baseline(struct freetype_face *face, int y)
153 {
154 	return (int)(y * face->baseline + 0.5F);
155 }
156 
freetype_load_metric(struct style * st,int char_number,int * xp,int y)157 static int freetype_load_metric(struct style *st, int char_number, int *xp, int y)
158 {
159 	FT_Face face = st->ft_face->face;
160 	FT_GlyphSlot slot = face->glyph;
161 	FT_Error err;
162 	FT_UInt glyph_index;
163 	int baseline = get_baseline(st->ft_face, y);
164 
165 	ret_if_lcd;
166 
167 	if ((err = FT_Set_Pixel_Sizes(face, 0, y - baseline))) {
168 		/*error("FT_Set_Pixel_Sizes failed: %d", err);*/
169 		return -1;
170 	}
171 
172 	glyph_index = FT_Get_Char_Index(face, char_number);
173 	if (!glyph_index) {
174 		/*fprintf(stderr, "missing glyph: %d\n", char_number);*/
175 		return -1;
176 	}
177 
178 	if ((err = FT_Load_Glyph(face, glyph_index, select_lcd(FT_LOAD_TARGET_NORMAL, FT_LOAD_TARGET_LCD)))) {
179 		error("FT_Load_Glyph failed: %d", err);
180 		return -1;
181 	}
182 
183 	slot = face->glyph;
184 
185 	*xp = (int)(slot->advance.x >> 6);
186 
187 	if (*xp <= 0)
188 		*xp = 1;
189 
190 	return 0;
191 }
192 
freetype_load_metric_cached(struct style * st,int char_number,int * xp,int y)193 int freetype_load_metric_cached(struct style *st, int char_number, int *xp, int y)
194 {
195 	int cache_slot;
196 	struct metric_cache_entry *entry;
197 
198 	cache_slot = (char_number + y + (y << 12)) & (sizeof_freetype_metric_cache - 1);
199 	entry = &freetype_metric_cache[cache_slot];
200 
201 	if (entry->face == st->ft_face && entry->char_number == char_number && entry->y == y && entry->flags == st->flags) {
202 		*xp = entry->x;
203 		return 0;
204 	}
205 
206 	if (freetype_load_metric(st, char_number, xp, y))
207 		return -1;
208 
209 	entry->face = st->ft_face;
210 	entry->char_number = char_number;
211 	entry->y = y;
212 	entry->flags = st->flags;
213 	entry->x = *xp;
214 
215 	return 0;
216 }
217 
freetype_type_character(struct style * st,int char_number,unsigned char ** dest,int * xp,int y)218 int freetype_type_character(struct style *st, int char_number, unsigned char **dest, int *xp, int y)
219 {
220 	FT_Face face;
221 	FT_GlyphSlot slot;
222 	FT_Bitmap *bitmap;
223 #ifdef FT_BITMAP_H
224 	FT_Bitmap converted_bitmap;
225 #endif
226 	FT_Error err;
227 	int j, x, ox;
228 	int start_x, start_y;
229 	int len_x, len_y;
230 	int offset_x, offset_y;
231 	unsigned char *s, *d;
232 	int baseline;
233 
234 	face = st->ft_face->face;
235 	slot = face->glyph;
236 	baseline = get_baseline(st->ft_face, y);
237 
238 	ret_if_lcd;
239 
240 	if (freetype_load_metric(st, char_number, xp, y))
241 		return -1;
242 
243 	ox = *xp;
244 	*xp = compute_width(*xp, y, st->height);
245 	if (ox != *xp) {
246 		FT_Matrix ft;
247 		FT_UInt glyph_index;
248 		ft.xx = 0x10000 * *xp / ox;
249 		ft.yy = 0x10000;
250 		ft.xy = 0;
251 		ft.yx = 0;
252 		FT_Set_Transform(face, &ft, NULL);
253 		glyph_index = FT_Get_Char_Index(face, char_number);
254 		if (!glyph_index) {
255 			/*fprintf(stderr, "missing glyph: %d\n", char_number);*/
256 			return -1;
257 		}
258 		if ((err = FT_Load_Glyph(face, glyph_index, select_lcd(FT_LOAD_TARGET_NORMAL, FT_LOAD_TARGET_LCD)))) {
259 			error("FT_Load_Glyph failed: %d", err);
260 			return -1;
261 		}
262 		ft.xx = 0x10000;
263 		ft.yy = 0x10000;
264 		ft.xy = 0;
265 		ft.yx = 0;
266 		FT_Set_Transform(face, &ft, NULL);
267 	}
268 
269 	slot = face->glyph;
270 	if ((err = FT_Render_Glyph(slot, select_lcd(FT_RENDER_MODE_NORMAL, FT_RENDER_MODE_LCD)))) {
271 		/*error("FT_Render_Glyph failed: %d", err);*/
272 		return -1;
273 	}
274 
275 	if (slot->bitmap.pixel_mode == select_lcd(FT_PIXEL_MODE_GRAY, FT_PIXEL_MODE_LCD)) {
276 		bitmap = &slot->bitmap;
277 	} else {
278 #ifdef FT_BITMAP_H
279 		FT_Bitmap_New(&converted_bitmap);
280 		if (FT_Bitmap_Convert(library, &slot->bitmap, &converted_bitmap, 1)) {
281 			FT_Bitmap_Done(library, &converted_bitmap);
282 			error("FT_Bitmap_Convert failed");
283 			return -1;
284 		}
285 		bitmap = &converted_bitmap;
286 #else
287 		return -1;
288 #endif
289 	}
290 
291 	if (display_optimize)
292 		*xp *= 3;
293 
294 	x = *xp;
295 	offset_x = -slot->bitmap_left;
296 	offset_y = -y + baseline + slot->bitmap_top;
297 
298 	if (offset_x >= 0) {
299 		if (offset_x >= (int)bitmap->width) {
300 			start_x = len_x = 0;
301 		} else if (offset_x + x >= (int)bitmap->width) {
302 			start_x = offset_x;
303 			len_x = (int)bitmap->width - offset_x;
304 		} else {
305 			start_x = offset_x;
306 			len_x = x;
307 		}
308 	} else {
309 		if (offset_x + x <= 0) {
310 			start_x = len_x = 0;
311 		} else if (offset_x + x <= (int)bitmap->width) {
312 			start_x = 0;
313 			len_x = x + offset_x;
314 		} else {
315 			start_x = 0;
316 			len_x = (int)bitmap->width;
317 		}
318 	}
319 	if (offset_y >= 0) {
320 		if (offset_y >= (int)bitmap->rows) {
321 			start_y = len_y = 0;
322 		} else if (offset_y + y >= (int)bitmap->rows) {
323 			start_y = offset_y;
324 			len_y = (int)bitmap->rows - offset_y;
325 		} else {
326 			start_y = offset_y;
327 			len_y = y;
328 		}
329 	} else {
330 		if (offset_y + y <= 0) {
331 			start_y = len_y = 0;
332 		} else if (offset_y + y <= (int)bitmap->rows) {
333 			start_y = 0;
334 			len_y = y + offset_y;
335 		} else {
336 			start_y = 0;
337 			len_y = (int)bitmap->rows;
338 		}
339 	}
340 
341 #if 0
342 	fprintf(stderr, "advance: x = %ld, y = %ld\n", slot->advance.x >> 6, slot->advance.y >> 6);
343 	fprintf(stderr, "%d x %d\n", bitmap->width, bitmap->rows);
344 	fprintf(stderr, "x/y: %d %d, start_x/start_y %d %d, len_x/len_y %d %d\n", x, y, start_x, start_y, len_x, len_y);
345 	fprintf(stderr, "bitmap_left, bitmap_top %d - %d\n", slot->bitmap_left, slot->bitmap_top);
346 	fprintf(stderr, "\n");
347 #endif
348 
349 	if ((unsigned)x * (unsigned)y / (unsigned)y != (unsigned)x ||
350 	    (unsigned)x * (unsigned)y > MAXINT) overalloc();
351 	*dest = mem_calloc(x * y);
352 
353 	s = bitmap->buffer + bitmap->pitch * start_y + start_x;
354 	d = *dest + (offset_y > 0 ? 0 : x * -offset_y) + (offset_x > 0 ? 0 : -offset_x);
355 	for (j = 0; j < len_y; j++) {
356 		memcpy(d, s, len_x);
357 		s += bitmap->pitch;
358 		d += x;
359 	}
360 
361 #ifdef FT_BITMAP_H
362 	if (bitmap == &converted_bitmap)
363 		FT_Bitmap_Done(library, &converted_bitmap);
364 #endif
365 
366 	return 0;
367 }
368 
369 
freetype_init(void)370 void freetype_init(void)
371 {
372 	FT_Error err;
373 
374 	memset(&faces, 0, sizeof faces);
375 	if ((err = FT_Init_FreeType(&library))) {
376 		error("FT_Init_FreeType failed: %d", err);
377 		return;
378 	}
379 	ft_initialized = 1;
380 
381 	freetype_reload();
382 }
383 
freetype_reload(void)384 void freetype_reload(void)
385 {
386 	freetype_setup_font(&faces[0], font_file);
387 	freetype_setup_font(&faces[FF_BOLD], font_file_b);
388 	freetype_setup_font(&faces[FF_MONOSPACED], font_file_m);
389 	freetype_setup_font(&faces[FF_MONOSPACED | FF_BOLD], font_file_m_b);
390 
391 #ifdef USE_ITALIC
392 	freetype_setup_font(&faces[FF_ITALIC], font_file_i);
393 	freetype_setup_font(&faces[FF_ITALIC | FF_BOLD], font_file_i_b);
394 	freetype_setup_font(&faces[FF_ITALIC | FF_MONOSPACED], font_file_i_m);
395 	freetype_setup_font(&faces[FF_ITALIC | FF_MONOSPACED | FF_BOLD], font_file_i_m_b);
396 #endif
397 }
398 
freetype_done(void)399 void freetype_done(void)
400 {
401 	FT_Error err;
402 	int i;
403 
404 	for (i = 0; i < FF_SHAPES; i++)
405 		freetype_setup_font(&faces[i], NULL);
406 
407 	if (freetype_cache)
408 		mem_free(freetype_cache), freetype_cache = NULL;
409 	if (freetype_metric_cache)
410 		mem_free(freetype_metric_cache), freetype_metric_cache = NULL;
411 
412 	if (ft_initialized) {
413 		if ((err = FT_Done_FreeType(library)))
414 			error("FT_Done_FreeType failed: %d", err);
415 		ft_initialized = 0;
416 	}
417 }
418 
419 
add_freetype_version(unsigned char ** s,int * l)420 void add_freetype_version(unsigned char **s, int *l)
421 {
422 #ifdef HAVE_FT_LIBRARY_VERSION
423 	FT_Int v1, v2, v3;
424 	int initialized = ft_initialized;
425 
426 	if (!initialized) {
427 		freetype_init();
428 	}
429 
430 	FT_Library_Version(library, &v1, &v2, &v3);
431 
432 	if (!initialized) {
433 		freetype_done();
434 	}
435 
436 	add_to_str(s, l, cast_uchar "FreeType ");
437 	add_num_to_str(s, l, v1);
438 	add_chr_to_str(s, l, '.');
439 	add_num_to_str(s, l, v2);
440 	add_chr_to_str(s, l, '.');
441 	add_num_to_str(s, l, v3);
442 #else
443 	add_to_str(s, l, cast_uchar "FreeType ");
444 	add_num_to_str(s, l, FREETYPE_MAJOR);
445 	add_chr_to_str(s, l, '.');
446 	add_num_to_str(s, l, FREETYPE_MINOR);
447 #ifdef FREETYPE_PATCH
448 	add_chr_to_str(s, l, '.');
449 	add_num_to_str(s, l, FREETYPE_PATCH);
450 #endif
451 #endif
452 }
453 
454 #endif
455