| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- /*
- * Copyright © 2012 Philipp Brüschweiler
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- /*
- * This is a small, hacky tool to extract cursors from a .pcf file.
- * The information about the file format has been gathered from
- * http://fontforge.org/pcf-format.html
- */
- #include <fcntl.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #define min(a, b) ((a) < (b) ? (a) : (b))
- #define max(a, b) ((a) > (b) ? (a) : (b))
- struct glyph {
- char *name;
- int16_t left_bearing, right_bearing, ascent, descent;
- int16_t width, height;
- int16_t hotx, hoty;
- int32_t data_format;
- char *data;
- };
- static struct {
- int count;
- struct glyph *glyphs;
- } extracted_font = {0, NULL};
- #define PCF_PROPERTIES (1<<0)
- #define PCF_ACCELERATORS (1<<1)
- #define PCF_METRICS (1<<2)
- #define PCF_BITMAPS (1<<3)
- #define PCF_INK_METRICS (1<<4)
- #define PCF_BDF_ENCODINGS (1<<5)
- #define PCF_SWIDTHS (1<<6)
- #define PCF_GLYPH_NAMES (1<<7)
- #define PCF_BDF_ACCELERATORS (1<<8)
- #define PCF_DEFAULT_FORMAT 0x00000000
- #define PCF_INKBOUNDS 0x00000200
- #define PCF_ACCEL_W_INKBOUNDS 0x00000100
- #define PCF_COMPRESSED_METRICS 0x00000100
- #define PCF_FORMAT_MASK 0xffffff00
- struct pcf_header {
- char header[4];
- int32_t table_count;
- struct toc_entry {
- int32_t type;
- int32_t format;
- int32_t size;
- int32_t offset;
- } tables[0];
- };
- struct compressed_metrics {
- uint8_t left_sided_bearing;
- uint8_t right_side_bearing;
- uint8_t character_width;
- uint8_t character_ascent;
- uint8_t character_descent;
- };
- struct uncompressed_metrics {
- int16_t left_sided_bearing;
- int16_t right_side_bearing;
- int16_t character_width;
- int16_t character_ascent;
- int16_t character_descent;
- uint16_t character_attributes;
- };
- struct metrics {
- int32_t format;
- union {
- struct {
- int16_t count;
- struct compressed_metrics compressed_metrics[0];
- } compressed;
- struct {
- int32_t count;
- struct uncompressed_metrics uncompressed_metrics[0];
- } uncompressed;
- };
- };
- struct glyph_names {
- int32_t format;
- int32_t glyph_count;
- int32_t offsets[0];
- };
- struct bitmaps {
- int32_t format;
- int32_t glyph_count;
- int32_t offsets[0];
- };
- static void
- handle_compressed_metrics(int32_t count, struct compressed_metrics *m)
- {
- printf("metrics count: %d\n", count);
- extracted_font.count = count;
- extracted_font.glyphs = calloc(count, sizeof(struct glyph));
- int i;
- for (i = 0; i < count; ++i) {
- struct glyph *glyph = &extracted_font.glyphs[i];
- glyph->left_bearing =
- ((int16_t) m[i].left_sided_bearing) - 0x80;
- glyph->right_bearing =
- ((int16_t) m[i].right_side_bearing) - 0x80;
- glyph->width = ((int16_t) m[i].character_width) - 0x80;
- glyph->ascent = ((int16_t) m[i].character_ascent) - 0x80;
- glyph->descent = ((int16_t) m[i].character_descent) - 0x80;
- /* computed stuff */
- glyph->height = glyph->ascent + glyph->descent;
- glyph->hotx = -glyph->left_bearing;
- glyph->hoty = glyph->ascent;
- }
- }
- static void
- handle_metrics(void *metricbuf)
- {
- struct metrics *metrics = metricbuf;
- printf("metric format: %x\n", metrics->format);
- if ((metrics->format & PCF_FORMAT_MASK) == PCF_DEFAULT_FORMAT) {
- printf("todo...\n");
- } else if ((metrics->format & PCF_FORMAT_MASK) ==
- PCF_COMPRESSED_METRICS) {
- handle_compressed_metrics(
- metrics->compressed.count,
- &metrics->compressed.compressed_metrics[0]);
- } else {
- printf("incompatible format\n");
- abort();
- }
- }
- static void
- handle_glyph_names(struct glyph_names *names)
- {
- printf("glyph count %d\n", names->glyph_count);
- if (names->glyph_count != extracted_font.count) {
- abort();
- }
- printf("glyph names format %x\n", names->format);
- void *names_start = ((void*) names) + sizeof(struct glyph_names)
- + (names->glyph_count + 1) * sizeof(int32_t);
- int i;
- for (i = 0; i < names->glyph_count; ++i) {
- int32_t start = names->offsets[i];
- int32_t end = names->offsets[i+1];
- char *name = names_start + start;
- extracted_font.glyphs[i].name = calloc(1, end - start + 1);
- memcpy(extracted_font.glyphs[i].name, name, end - start);
- }
- }
- static void
- handle_bitmaps(struct bitmaps *bitmaps)
- {
- printf("bitmaps count %d\n", bitmaps->glyph_count);
- if (bitmaps->glyph_count != extracted_font.count) {
- abort();
- }
- printf("format %x\n", bitmaps->format);
- if (bitmaps->format != 2) {
- printf("format not yet supported\n");
- abort();
- }
- void *bitmaps_start = ((void*) bitmaps) + sizeof(struct bitmaps)
- + (bitmaps->glyph_count + 4) * sizeof(int32_t);
- int i;
- for (i = 0; i < bitmaps->glyph_count; ++i) {
- int32_t offset = bitmaps->offsets[i];
- struct glyph *glyph = &extracted_font.glyphs[i];
- glyph->data_format = bitmaps->format;
- glyph->data = bitmaps_start + offset;
- }
- }
- static void
- handle_pcf(void *fontbuf)
- {
- struct pcf_header *header = fontbuf;
- printf("tablecount %d\n", header->table_count);
- int i;
- for (i = 0; i < header->table_count; ++i) {
- struct toc_entry *entry = &header->tables[i];
- printf("type: %d\n", entry->type);
- if (entry->type == PCF_METRICS) {
- handle_metrics(fontbuf + entry->offset);
- } else if (entry->type == PCF_GLYPH_NAMES) {
- handle_glyph_names(fontbuf + entry->offset);
- } else if (entry->type == PCF_BITMAPS) {
- handle_bitmaps(fontbuf + entry->offset);
- }
- }
- }
- static char
- get_glyph_pixel(struct glyph *glyph, int x, int y)
- {
- int absx = glyph->hotx + x;
- int absy = glyph->hoty + y;
- if (absx < 0 || absx >= glyph->width ||
- absy < 0 || absy >= glyph->height)
- return 0;
- int stride = (glyph->width + 31) / 32 * 4;
- unsigned char block = glyph->data[absy * stride + (absx/8)];
- int idx = absx % 8;
- return (block >> idx) & 1;
- }
- static struct {
- uint32_t *data;
- size_t capacity, size;
- } data_buffer;
- static void
- init_data_buffer()
- {
- data_buffer.data = malloc(sizeof(uint32_t) * 10);
- data_buffer.capacity = 10;
- data_buffer.size = 0;
- }
- static void
- add_pixel(uint32_t pixel)
- {
- if (data_buffer.size == data_buffer.capacity) {
- data_buffer.capacity *= 2;
- data_buffer.data =
- realloc(data_buffer.data,
- sizeof(uint32_t) * data_buffer.capacity);
- }
- data_buffer.data[data_buffer.size++] = pixel;
- }
- struct reconstructed_glyph {
- int32_t width, height;
- int32_t hotspot_x, hotspot_y;
- size_t offset;
- char *name;
- };
- static void
- reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name,
- struct reconstructed_glyph *glyph)
- {
- int minx = min(-cursor->hotx, -mask->hotx);
- int maxx = max(cursor->right_bearing, mask->right_bearing);
- int miny = min(-cursor->hoty, -mask->hoty);
- int maxy = max(cursor->height - cursor->hoty,
- mask->height - mask->hoty);
- int width = maxx - minx;
- int height = maxy - miny;
- glyph->name = strdup(name);
- glyph->width = width;
- glyph->height = height;
- glyph->hotspot_x = -minx;
- glyph->hotspot_y = -miny;
- glyph->offset = data_buffer.size;
- int x, y;
- for (y = miny; y < maxy; ++y) {
- for (x = minx; x < maxx; ++x) {
- char alpha = get_glyph_pixel(mask, x, y);
- if (alpha) {
- char color = get_glyph_pixel(cursor, x, y);
- if (color)
- add_pixel(0xff000000);
- else
- add_pixel(0xffffffff);
- } else {
- add_pixel(0);
- }
- }
- }
- }
- /*
- * Originally from
- * http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c
- * Changed to the MIT "Expat" style license for Wayland..
- */
- static const char cursor_licence[] =
- "/*\n"
- "* Copyright 1999 SuSE, Inc.\n"
- "*\n"
- "* Permission is hereby granted, free of charge, to any person obtaining\n"
- "* a copy of this software and associated documentation files (the\n"
- "* \"Software\"), to deal in the Software without restriction, including\n"
- "* without limitation the rights to use, copy, modify, merge, publish,\n"
- "* distribute, sublicense, and/or sell copies of the Software, and to\n"
- "* permit persons to whom the Software is furnished to do so, subject to\n"
- "* the following conditions:\n"
- "*\n"
- "* The above copyright notice and this permission notice (including the\n"
- "* next paragraph) shall be included in all copies or substantial\n"
- "* portions of the Software.\n"
- "*\n"
- "* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
- "* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
- "* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
- "* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
- "* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
- "* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
- "* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
- "* SOFTWARE.\n"
- "*\n"
- "* Author: Keith Packard, SuSE, Inc.\n"
- "*/\n";
- static void
- write_output_file(struct reconstructed_glyph *glyphs, int n)
- {
- int i, j, counter, size;
- FILE *file = fopen("cursor-data.h", "w");
- uint32_t *data;
- fprintf(file, "%s\n", cursor_licence);
- fprintf(file, "static uint32_t cursor_data[] = {\n\t");
- counter = 0;
- for (i = 0; i < n; ++i) {
- data = data_buffer.data + glyphs[i].offset;
- size = glyphs[i].width * glyphs[i].height;
- for (j = 0; j < size; ++j) {
- fprintf(file, "0x%08x, ", data[j]);
- if (++counter % 6 == 0)
- fprintf(file, "\n\t");
- }
- }
- fprintf(file, "\n};\n\n");
- fprintf(file,
- "static struct {\n"
- "\tchar *name;\n"
- "\tint width, height;\n"
- "\tint hotspot_x, hotspot_y;\n"
- "\tsize_t offset;\n"
- "} cursor_metadata[] = {\n");
- for (i = 0; i < n; ++i)
- fprintf(file, "\t{ \"%s\", %d, %d, %d, %d, %zu },\n",
- glyphs[i].name,
- glyphs[i].width, glyphs[i].height,
- glyphs[i].hotspot_x, glyphs[i].hotspot_y,
- glyphs[i].offset);
- fprintf(file, "};");
- fclose(file);
- }
- struct glyph *
- find_mask_glyph(char *name)
- {
- const char mask[] = "_mask";
- const int masklen = strlen(mask);
- int len = strlen(name);
- int i;
- for (i = 0; i < extracted_font.count; ++i) {
- struct glyph *g = &extracted_font.glyphs[i];
- int l2 = strlen(g->name);
- if ((l2 == len + masklen) &&
- (memcmp(g->name, name, len) == 0) &&
- (memcmp(g->name + len, mask, masklen) == 0)) {
- return g;
- }
- }
- return NULL;
- }
- static void
- output_all_cursors()
- {
- int i, j;
- struct reconstructed_glyph *glyphs =
- malloc(sizeof(struct reconstructed_glyph) *
- extracted_font.count/2);
- j = 0;
- for (i = 0; i < extracted_font.count; ++i) {
- struct glyph *g = &extracted_font.glyphs[i];
- if (strstr(g->name, "_mask"))
- continue;
- struct glyph *mask = find_mask_glyph(g->name);
- reconstruct_glyph(g, mask, g->name, &glyphs[j]);
- j++;
- }
- write_output_file(glyphs, extracted_font.count/2);
- }
- static void
- find_cursor_and_mask(const char *name,
- struct glyph **cursor,
- struct glyph **mask)
- {
- int i;
- char mask_name[100];
- sprintf(mask_name, "%s_mask", name);
- *cursor = *mask = NULL;
- for (i = 0; i < extracted_font.count && (!*mask || !*cursor); ++i) {
- struct glyph *g = &extracted_font.glyphs[i];
- if (!strcmp(name, g->name))
- *cursor = g;
- else if (!strcmp(mask_name, g->name))
- *mask = g;
- }
- }
- static struct {
- char *target_name, *source_name;
- } interesting_cursors[] = {
- { "bottom_left_corner", "bottom_left_corner" },
- { "bottom_right_corner", "bottom_right_corner" },
- { "bottom_side", "bottom_side" },
- { "grabbing", "fleur" },
- { "left_ptr", "left_ptr" },
- { "left_side", "left_side" },
- { "right_side", "right_side" },
- { "top_left_corner", "top_left_corner" },
- { "top_right_corner", "top_right_corner" },
- { "top_side", "top_side" },
- { "xterm", "xterm" },
- { "hand1", "hand1" },
- { "watch", "watch" }
- };
- static void
- output_interesting_cursors()
- {
- int i;
- int n = sizeof(interesting_cursors) / sizeof(interesting_cursors[0]);
- struct reconstructed_glyph *glyphs =
- malloc(n * sizeof(*glyphs));
- if (!glyphs) {
- printf("reconstructed_glyph malloc failed\n");
- abort();
- }
- for (i = 0; i < n; ++i) {
- struct glyph *cursor, *mask;
- find_cursor_and_mask(interesting_cursors[i].source_name,
- &cursor, &mask);
- if (!cursor) {
- printf("no cursor for %s\n",
- interesting_cursors[i].source_name);
- abort();
- }
- if (!mask) {
- printf("no mask for %s\n",
- interesting_cursors[i].source_name);
- abort();
- }
- reconstruct_glyph(cursor, mask,
- interesting_cursors[i].target_name,
- &glyphs[i]);
- }
- write_output_file(glyphs, n);
- }
- int main()
- {
- const char filename[] = "cursor.pcf";
- int fd = open(filename, O_RDONLY);
- struct stat filestat;
- fstat(fd, &filestat);
- void *fontbuf = mmap(NULL, filestat.st_size, PROT_READ,
- MAP_PRIVATE, fd, 0);
- handle_pcf(fontbuf);
- init_data_buffer();
- //output_all_cursors();
- output_interesting_cursors();
- }
|