cursor: add cursor.pcf and extraction program
This commit is contained in:
parent
9ce9336c57
commit
7fafa994a4
531
cursor/convert_font.c
Normal file
531
cursor/convert_font.c
Normal file
|
@ -0,0 +1,531 @@
|
|||
/*
|
||||
* Copyright © 2012 Philipp Brüschweiler
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS 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 <assert.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* From http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c */
|
||||
static const char cursor_licence[] =
|
||||
"/*\n"
|
||||
"* Copyright 1999 SuSE, Inc.\n"
|
||||
"*\n"
|
||||
"* Permission to use, copy, modify, distribute, and sell this software and its\n"
|
||||
"* documentation for any purpose is hereby granted without fee, provided that\n"
|
||||
"* the above copyright notice appear in all copies and that both that\n"
|
||||
"* copyright notice and this permission notice appear in supporting\n"
|
||||
"* documentation, and that the name of SuSE not be used in advertising or\n"
|
||||
"* publicity pertaining to distribution of the software without specific,\n"
|
||||
"* written prior permission. SuSE makes no representations about the\n"
|
||||
"* suitability of this software for any purpose. It is provided \"as is\"\n"
|
||||
"* without express or implied warranty.\n"
|
||||
"*\n"
|
||||
"* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL\n"
|
||||
"* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE\n"
|
||||
"* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n"
|
||||
"* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n"
|
||||
"* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n"
|
||||
"* CONNECTION WITH THE USE OR PERFORMANCE OF THIS 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.c", "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));
|
||||
|
||||
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();
|
||||
}
|
BIN
cursor/cursor.pcf
Normal file
BIN
cursor/cursor.pcf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user