Home | History | Annotate | Download | only in cursor
      1 /*
      2  * Copyright  2012 Philipp Brschweiler
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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 
    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