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