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