1 /*
2  * Copyright © 2012 Philipp Brüschweiler
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 /*
27  * This is a small, hacky tool to extract cursors from a .pcf file.
28  * The information about the file format has been gathered from
29  * http://fontforge.org/pcf-format.html
30  */
31 
32 #include <assert.h>
33 #include <fcntl.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/mman.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 
42 #define min(a, b) ((a) < (b) ? (a) : (b))
43 #define max(a, b) ((a) > (b) ? (a) : (b))
44 
45 struct glyph {
46 	char *name;
47 	int16_t left_bearing, right_bearing, ascent, descent;
48 
49 	int16_t width, height;
50 	int16_t hotx, hoty;
51 
52 	int32_t data_format;
53 	char *data;
54 };
55 
56 static struct {
57 	int count;
58 	struct glyph *glyphs;
59 } extracted_font = {0, NULL};
60 
61 #define PCF_PROPERTIES		    (1<<0)
62 #define PCF_ACCELERATORS	    (1<<1)
63 #define PCF_METRICS		    (1<<2)
64 #define PCF_BITMAPS		    (1<<3)
65 #define PCF_INK_METRICS		    (1<<4)
66 #define	PCF_BDF_ENCODINGS	    (1<<5)
67 #define PCF_SWIDTHS		    (1<<6)
68 #define PCF_GLYPH_NAMES		    (1<<7)
69 #define PCF_BDF_ACCELERATORS	    (1<<8)
70 
71 #define PCF_DEFAULT_FORMAT	0x00000000
72 #define PCF_INKBOUNDS		0x00000200
73 #define PCF_ACCEL_W_INKBOUNDS	0x00000100
74 #define PCF_COMPRESSED_METRICS	0x00000100
75 
76 #define	PCF_FORMAT_MASK		0xffffff00
77 
78 struct pcf_header {
79 	char header[4];
80 	int32_t table_count;
81 	struct toc_entry {
82 		int32_t type;
83 		int32_t format;
84 		int32_t size;
85 		int32_t offset;
86 	} tables[0];
87 };
88 
89 struct compressed_metrics {
90 	uint8_t left_sided_bearing;
91 	uint8_t right_side_bearing;
92 	uint8_t character_width;
93 	uint8_t character_ascent;
94 	uint8_t character_descent;
95 };
96 
97 struct uncompressed_metrics {
98 	int16_t left_sided_bearing;
99 	int16_t right_side_bearing;
100 	int16_t character_width;
101 	int16_t character_ascent;
102 	int16_t character_descent;
103 	uint16_t character_attributes;
104 };
105 
106 struct metrics {
107 	int32_t format;
108 	union {
109 		struct {
110 			int16_t count;
111 			struct compressed_metrics compressed_metrics[0];
112 		} compressed;
113 		struct {
114 			int32_t count;
115 			struct uncompressed_metrics uncompressed_metrics[0];
116 		} uncompressed;
117 	};
118 };
119 
120 struct glyph_names {
121 	int32_t format;
122 	int32_t glyph_count;
123 	int32_t offsets[0];
124 };
125 
126 struct bitmaps {
127 	int32_t format;
128 	int32_t glyph_count;
129 	int32_t offsets[0];
130 };
131 
132 static void
handle_compressed_metrics(int32_t count,struct compressed_metrics * m)133 handle_compressed_metrics(int32_t count, struct compressed_metrics *m)
134 {
135 	printf("metrics count: %d\n", count);
136 	extracted_font.count = count;
137 	extracted_font.glyphs = calloc(count, sizeof(struct glyph));
138 
139 	int i;
140 	for (i = 0; i < count; ++i) {
141 		struct glyph *glyph = &extracted_font.glyphs[i];
142 		glyph->left_bearing =
143 			((int16_t) m[i].left_sided_bearing) - 0x80;
144 		glyph->right_bearing =
145 			((int16_t) m[i].right_side_bearing) - 0x80;
146 		glyph->width = ((int16_t) m[i].character_width) - 0x80;
147 		glyph->ascent = ((int16_t) m[i].character_ascent) - 0x80;
148 		glyph->descent = ((int16_t) m[i].character_descent) - 0x80;
149 
150 		/* computed stuff */
151 		glyph->height = glyph->ascent + glyph->descent;
152 
153 		glyph->hotx = -glyph->left_bearing;
154 		glyph->hoty = glyph->ascent;
155 	}
156 }
157 
158 static void
handle_metrics(void * metricbuf)159 handle_metrics(void *metricbuf)
160 {
161 	struct metrics *metrics = metricbuf;
162 	printf("metric format: %x\n", metrics->format);
163 
164 	if ((metrics->format & PCF_FORMAT_MASK) == PCF_DEFAULT_FORMAT) {
165 		printf("todo...\n");
166 	} else if ((metrics->format & PCF_FORMAT_MASK) ==
167 		   PCF_COMPRESSED_METRICS) {
168 		handle_compressed_metrics(
169 		    metrics->compressed.count,
170 		    &metrics->compressed.compressed_metrics[0]);
171 	} else {
172 		printf("incompatible format\n");
173 		abort();
174 	}
175 }
176 
177 static void
handle_glyph_names(struct glyph_names * names)178 handle_glyph_names(struct glyph_names *names)
179 {
180 	printf("glyph count %d\n", names->glyph_count);
181 
182 	if (names->glyph_count != extracted_font.count) {
183 		abort();
184 	}
185 
186 	printf("glyph names format %x\n", names->format);
187 
188 	void *names_start = ((void*) names) + sizeof(struct glyph_names)
189 		+ (names->glyph_count + 1) * sizeof(int32_t);
190 
191 	int i;
192 	for (i = 0; i < names->glyph_count; ++i) {
193 		int32_t start = names->offsets[i];
194 		int32_t end = names->offsets[i+1];
195 		char *name = names_start + start;
196 		extracted_font.glyphs[i].name = calloc(1, end - start + 1);
197 		memcpy(extracted_font.glyphs[i].name, name, end - start);
198 	}
199 }
200 
201 static void
handle_bitmaps(struct bitmaps * bitmaps)202 handle_bitmaps(struct bitmaps *bitmaps)
203 {
204 	printf("bitmaps count %d\n", bitmaps->glyph_count);
205 
206 	if (bitmaps->glyph_count != extracted_font.count) {
207 		abort();
208 	}
209 
210 	printf("format %x\n", bitmaps->format);
211 
212 	if (bitmaps->format != 2) {
213 		printf("format not yet supported\n");
214 		abort();
215 	}
216 
217 	void *bitmaps_start = ((void*) bitmaps) + sizeof(struct bitmaps)
218 		+ (bitmaps->glyph_count + 4) * sizeof(int32_t);
219 
220 	int i;
221 	for (i = 0; i < bitmaps->glyph_count; ++i) {
222 		int32_t offset = bitmaps->offsets[i];
223 		struct glyph *glyph = &extracted_font.glyphs[i];
224 		glyph->data_format = bitmaps->format;
225 
226 		glyph->data = bitmaps_start + offset;
227 	}
228 }
229 
230 static void
handle_pcf(void * fontbuf)231 handle_pcf(void *fontbuf)
232 {
233 	struct pcf_header *header = fontbuf;
234 	printf("tablecount %d\n", header->table_count);
235 
236 	int i;
237 	for (i = 0; i < header->table_count; ++i) {
238 		struct toc_entry *entry = &header->tables[i];
239 		printf("type: %d\n", entry->type);
240 		if (entry->type == PCF_METRICS) {
241 			handle_metrics(fontbuf + entry->offset);
242 		} else if (entry->type == PCF_GLYPH_NAMES) {
243 			handle_glyph_names(fontbuf + entry->offset);
244 		} else if (entry->type == PCF_BITMAPS) {
245 			handle_bitmaps(fontbuf + entry->offset);
246 		}
247 	}
248 }
249 
250 static char
get_glyph_pixel(struct glyph * glyph,int x,int y)251 get_glyph_pixel(struct glyph *glyph, int x, int y)
252 {
253 	int absx = glyph->hotx + x;
254 	int absy = glyph->hoty + y;
255 
256 	if (absx < 0 || absx >= glyph->width ||
257 	    absy < 0 || absy >= glyph->height)
258 		return 0;
259 
260 	int stride = (glyph->width + 31) / 32 * 4;
261 	unsigned char block = glyph->data[absy * stride + (absx/8)];
262 	int idx = absx % 8;
263 	return (block >> idx) & 1;
264 }
265 
266 static struct {
267 	uint32_t *data;
268 	size_t capacity, size;
269 } data_buffer;
270 
271 static void
init_data_buffer()272 init_data_buffer()
273 {
274 	data_buffer.data = malloc(sizeof(uint32_t) * 10);
275 	data_buffer.capacity = 10;
276 	data_buffer.size = 0;
277 }
278 
279 static void
add_pixel(uint32_t pixel)280 add_pixel(uint32_t pixel)
281 {
282 	if (data_buffer.size == data_buffer.capacity) {
283 		data_buffer.capacity *= 2;
284 		data_buffer.data =
285 			realloc(data_buffer.data,
286 				sizeof(uint32_t) * data_buffer.capacity);
287 	}
288 	data_buffer.data[data_buffer.size++] = pixel;
289 }
290 
291 struct reconstructed_glyph {
292 	int32_t width, height;
293 	int32_t hotspot_x, hotspot_y;
294 	size_t offset;
295 	char *name;
296 };
297 
298 static void
reconstruct_glyph(struct glyph * cursor,struct glyph * mask,char * name,struct reconstructed_glyph * glyph)299 reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name,
300 		  struct reconstructed_glyph *glyph)
301 {
302 	int minx = min(-cursor->hotx, -mask->hotx);
303 	int maxx = max(cursor->right_bearing, mask->right_bearing);
304 
305 	int miny = min(-cursor->hoty, -mask->hoty);
306 	int maxy = max(cursor->height - cursor->hoty,
307 		       mask->height - mask->hoty);
308 
309 	int width = maxx - minx;
310 	int height = maxy - miny;
311 
312 	glyph->name = strdup(name);
313 	glyph->width = width;
314 	glyph->height = height;
315 	glyph->hotspot_x = -minx;
316 	glyph->hotspot_y = -miny;
317 	glyph->offset = data_buffer.size;
318 
319 	int x, y;
320 	for (y = miny; y < maxy; ++y) {
321 		for (x = minx; x < maxx; ++x) {
322 			char alpha = get_glyph_pixel(mask, x, y);
323 			if (alpha) {
324 				char color = get_glyph_pixel(cursor, x, y);
325 				if (color)
326 					add_pixel(0xff000000);
327 				else
328 					add_pixel(0xffffffff);
329 			} else {
330 				add_pixel(0);
331 			}
332 		}
333 	}
334 }
335 
336 /*
337  * Originally from
338  * http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c
339  * Changed to the MIT "Expat" style license for Wayland..
340  */
341 static const char cursor_licence[] =
342 	"/*\n"
343 	"* Copyright 1999 SuSE, Inc.\n"
344 	"*\n"
345 	"* Permission is hereby granted, free of charge, to any person obtaining\n"
346 	"* a copy of this software and associated documentation files (the\n"
347 	"* \"Software\"), to deal in the Software without restriction, including\n"
348 	"* without limitation the rights to use, copy, modify, merge, publish,\n"
349 	"* distribute, sublicense, and/or sell copies of the Software, and to\n"
350 	"* permit persons to whom the Software is furnished to do so, subject to\n"
351 	"* the following conditions:\n"
352 	"*\n"
353 	"* The above copyright notice and this permission notice (including the\n"
354 	"* next paragraph) shall be included in all copies or substantial\n"
355 	"* portions of the Software.\n"
356 	"*\n"
357 	"* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
358 	"* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
359 	"* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
360 	"* NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
361 	"* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
362 	"* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
363 	"* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
364 	"* SOFTWARE.\n"
365 	"*\n"
366 	"* Author:  Keith Packard, SuSE, Inc.\n"
367 	"*/\n";
368 
369 static void
write_output_file(struct reconstructed_glyph * glyphs,int n)370 write_output_file(struct reconstructed_glyph *glyphs, int n)
371 {
372 	int i, j, counter, size;
373 	FILE *file = fopen("cursor-data.h", "w");
374 	uint32_t *data;
375 
376 	fprintf(file, "%s\n", cursor_licence);
377 
378 	fprintf(file, "static uint32_t cursor_data[] = {\n\t");
379 
380 	counter = 0;
381 	for (i = 0; i < n; ++i) {
382 		data = data_buffer.data + glyphs[i].offset;
383 		size = glyphs[i].width * glyphs[i].height;
384 
385 		for (j = 0; j < size; ++j) {
386 			fprintf(file, "0x%08x, ", data[j]);
387 			if (++counter % 6 == 0)
388 				fprintf(file, "\n\t");
389 		}
390 	}
391 	fprintf(file, "\n};\n\n");
392 
393 	fprintf(file,
394 		"static struct {\n"
395 		"\tchar *name;\n"
396 		"\tint width, height;\n"
397 		"\tint hotspot_x, hotspot_y;\n"
398 		"\tsize_t offset;\n"
399 		"} cursor_metadata[] = {\n");
400 
401 	for (i = 0; i < n; ++i)
402 		fprintf(file, "\t{ \"%s\", %d, %d, %d, %d, %zu },\n",
403 			glyphs[i].name,
404 			glyphs[i].width, glyphs[i].height,
405 			glyphs[i].hotspot_x, glyphs[i].hotspot_y,
406 			glyphs[i].offset);
407 
408 	fprintf(file, "};");
409 
410 	fclose(file);
411 }
412 
413 struct glyph *
find_mask_glyph(char * name)414 find_mask_glyph(char *name)
415 {
416 	const char mask[] = "_mask";
417 	const int masklen = strlen(mask);
418 
419 	int len = strlen(name);
420 	int i;
421 	for (i = 0; i < extracted_font.count; ++i) {
422 		struct glyph *g = &extracted_font.glyphs[i];
423 		int l2 = strlen(g->name);
424 		if ((l2 == len + masklen) &&
425 		    (memcmp(g->name, name, len) == 0) &&
426 		    (memcmp(g->name + len, mask, masklen) == 0)) {
427 			return g;
428 		}
429 	}
430 	return NULL;
431 }
432 
433 static void
output_all_cursors()434 output_all_cursors()
435 {
436 	int i, j;
437 	struct reconstructed_glyph *glyphs =
438 		malloc(sizeof(struct reconstructed_glyph) *
439 		       extracted_font.count/2);
440 	j = 0;
441 
442 	for (i = 0; i < extracted_font.count; ++i) {
443 		struct glyph *g = &extracted_font.glyphs[i];
444 		if (strstr(g->name, "_mask"))
445 			continue;
446 
447 		struct glyph *mask = find_mask_glyph(g->name);
448 
449 		reconstruct_glyph(g, mask, g->name, &glyphs[j]);
450 		j++;
451 	}
452 
453 	write_output_file(glyphs, extracted_font.count/2);
454 }
455 
456 static void
find_cursor_and_mask(const char * name,struct glyph ** cursor,struct glyph ** mask)457 find_cursor_and_mask(const char *name,
458 		     struct glyph **cursor,
459 		     struct glyph **mask)
460 {
461 	int i;
462 	char mask_name[100];
463 	sprintf(mask_name, "%s_mask", name);
464 
465 	*cursor = *mask = NULL;
466 
467 	for (i = 0; i < extracted_font.count && (!*mask || !*cursor); ++i) {
468 		struct glyph *g = &extracted_font.glyphs[i];
469 		if (!strcmp(name, g->name))
470 			*cursor = g;
471 		else if (!strcmp(mask_name, g->name))
472 			*mask = g;
473 	}
474 }
475 
476 static struct {
477 	char *target_name, *source_name;
478 } interesting_cursors[] = {
479 	{ "bottom_left_corner", "bottom_left_corner" },
480 	{ "bottom_right_corner", "bottom_right_corner" },
481 	{ "bottom_side", "bottom_side" },
482 	{ "grabbing", "fleur" },
483 	{ "left_ptr", "left_ptr" },
484 	{ "left_side", "left_side" },
485 	{ "right_side", "right_side" },
486 	{ "top_left_corner", "top_left_corner" },
487 	{ "top_right_corner", "top_right_corner" },
488 	{ "top_side", "top_side" },
489 	{ "xterm", "xterm" },
490 	{ "hand1", "hand1" },
491 	{ "watch", "watch" }
492 };
493 
494 static void
output_interesting_cursors()495 output_interesting_cursors()
496 {
497 	int i;
498 	int n = sizeof(interesting_cursors) / sizeof(interesting_cursors[0]);
499 	struct reconstructed_glyph *glyphs =
500 		malloc(n * sizeof(*glyphs));
501 
502 	for (i = 0; i < n; ++i) {
503 		struct glyph *cursor, *mask;
504 		find_cursor_and_mask(interesting_cursors[i].source_name,
505 				     &cursor, &mask);
506 		if (!cursor) {
507 			printf("no cursor for %s\n",
508 			       interesting_cursors[i].source_name);
509 			abort();
510 		}
511 		if (!mask) {
512 			printf("no mask for %s\n",
513 			       interesting_cursors[i].source_name);
514 			abort();
515 		}
516 		reconstruct_glyph(cursor, mask,
517 				  interesting_cursors[i].target_name,
518 				  &glyphs[i]);
519 	}
520 
521 	write_output_file(glyphs, n);
522 }
523 
main()524 int main()
525 {
526 	const char filename[] = "cursor.pcf";
527 
528 	int fd = open(filename, O_RDONLY);
529 	struct stat filestat;
530 
531 	fstat(fd, &filestat);
532 
533 	void *fontbuf = mmap(NULL, filestat.st_size, PROT_READ,
534 			     MAP_PRIVATE, fd, 0);
535 
536 	handle_pcf(fontbuf);
537 
538 	init_data_buffer();
539 
540 	//output_all_cursors();
541 	output_interesting_cursors();
542 }
543