commit fed8a9c

Michael Forney  ·  2014-01-18 03:15:55 +0000 UTC
parent 7f585a1
Add fonts from the xserver
5 files changed,  +534, -2
+2, -0
1@@ -12,4 +12,6 @@ protocol/xserver-server-protocol.h
2 /libswc/libswc.a
3 /libswc/libswc.so*
4 /launch/swc-launch
5+/cursor/convert_font
6+/cursor/cursor_data.h
7 
+2, -2
 1@@ -8,7 +8,7 @@ VERSION_MINOR   := 0
 2 VERSION         := $(VERSION_MAJOR).$(VERSION_MINOR)
 3 
 4 TARGETS         := swc.pc
 5-SUBDIRS         := launch libswc protocol
 6+SUBDIRS         := launch libswc protocol cursor
 7 CLEAN_FILES     := $(TARGETS)
 8 
 9 include config.mk
10@@ -27,7 +27,7 @@ define check_deps
11     @$(PKG_CONFIG) --exists --print-errors $2
12 endef
13 
14-FINAL_CFLAGS = $(CFLAGS) -fvisibility=hidden
15+FINAL_CFLAGS = $(CFLAGS) -fvisibility=hidden -std=gnu99
16 FINAL_CPPFLAGS = $(CPPFLAGS)
17 
18 # Warning/error flags
+514, -0
  1@@ -0,0 +1,514 @@
  2+/*
  3+ * Copyright © 2012 Philipp Brüschweiler
  4+ *
  5+ * Permission to use, copy, modify, distribute, and sell this software and its
  6+ * documentation for any purpose is hereby granted without fee, provided that
  7+ * the above copyright notice appear in all copies and that both that copyright
  8+ * notice and this permission notice appear in supporting documentation, and
  9+ * that the name of the copyright holders not be used in advertising or
 10+ * publicity pertaining to distribution of the software without specific,
 11+ * written prior permission.  The copyright holders make no representations
 12+ * about the suitability of this software for any purpose.  It is provided "as
 13+ * is" without express or implied warranty.
 14+ *
 15+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 16+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 17+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 18+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 19+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 20+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 21+ * OF THIS SOFTWARE.
 22+ */
 23+
 24+/*
 25+ * This is a small, hacky tool to extract cursors from a .pcf file.
 26+ * The information about the file format has been gathered from
 27+ * http://fontforge.org/pcf-format.html
 28+ */
 29+
 30+#include <assert.h>
 31+#include <fcntl.h>
 32+#include <stdint.h>
 33+#include <stdio.h>
 34+#include <stdlib.h>
 35+#include <string.h>
 36+#include <sys/mman.h>
 37+#include <sys/types.h>
 38+#include <sys/stat.h>
 39+
 40+#define min(a, b) ((a) < (b) ? (a) : (b))
 41+#define max(a, b) ((a) > (b) ? (a) : (b))
 42+
 43+struct glyph {
 44+	char *name;
 45+	int16_t left_bearing, right_bearing, ascent, descent;
 46+
 47+	int16_t width, height;
 48+	int16_t hotx, hoty;
 49+
 50+	int32_t data_format;
 51+	char *data;
 52+};
 53+
 54+static struct {
 55+	int count;
 56+	struct glyph *glyphs;
 57+} extracted_font = {0, NULL};
 58+
 59+#define PCF_PROPERTIES		    (1<<0)
 60+#define PCF_ACCELERATORS	    (1<<1)
 61+#define PCF_METRICS		    (1<<2)
 62+#define PCF_BITMAPS		    (1<<3)
 63+#define PCF_INK_METRICS		    (1<<4)
 64+#define PCF_BDF_ENCODINGS	    (1<<5)
 65+#define PCF_SWIDTHS		    (1<<6)
 66+#define PCF_GLYPH_NAMES		    (1<<7)
 67+#define PCF_BDF_ACCELERATORS	    (1<<8)
 68+
 69+#define PCF_DEFAULT_FORMAT	0x00000000
 70+#define PCF_INKBOUNDS		0x00000200
 71+#define PCF_ACCEL_W_INKBOUNDS	0x00000100
 72+#define PCF_COMPRESSED_METRICS	0x00000100
 73+
 74+#define PCF_FORMAT_MASK		0xffffff00
 75+
 76+struct pcf_header {
 77+	char header[4];
 78+	int32_t table_count;
 79+	struct toc_entry {
 80+		int32_t type;
 81+		int32_t format;
 82+		int32_t size;
 83+		int32_t offset;
 84+	} tables[0];
 85+};
 86+
 87+struct compressed_metrics {
 88+	uint8_t left_sided_bearing;
 89+	uint8_t right_side_bearing;
 90+	uint8_t character_width;
 91+	uint8_t character_ascent;
 92+	uint8_t character_descent;
 93+};
 94+
 95+struct uncompressed_metrics {
 96+	int16_t left_sided_bearing;
 97+	int16_t right_side_bearing;
 98+	int16_t character_width;
 99+	int16_t character_ascent;
100+	int16_t character_descent;
101+	uint16_t character_attributes;
102+};
103+
104+struct metrics {
105+	int32_t format;
106+	union {
107+		struct {
108+			int16_t count;
109+			struct compressed_metrics compressed_metrics[0];
110+		} compressed;
111+		struct {
112+			int32_t count;
113+			struct uncompressed_metrics uncompressed_metrics[0];
114+		} uncompressed;
115+	};
116+};
117+
118+struct glyph_names {
119+	int32_t format;
120+	int32_t glyph_count;
121+	int32_t offsets[0];
122+};
123+
124+struct bitmaps {
125+	int32_t format;
126+	int32_t glyph_count;
127+	int32_t offsets[0];
128+};
129+
130+static void
131+handle_compressed_metrics(int32_t count, struct compressed_metrics *m)
132+{
133+	fprintf(stderr, "metrics count: %d\n", count);
134+	extracted_font.count = count;
135+	extracted_font.glyphs = calloc(count, sizeof(struct glyph));
136+
137+	int i;
138+	for (i = 0; i < count; ++i) {
139+		struct glyph *glyph = &extracted_font.glyphs[i];
140+		glyph->left_bearing =
141+			((int16_t) m[i].left_sided_bearing) - 0x80;
142+		glyph->right_bearing =
143+			((int16_t) m[i].right_side_bearing) - 0x80;
144+		glyph->width = ((int16_t) m[i].character_width) - 0x80;
145+		glyph->ascent = ((int16_t) m[i].character_ascent) - 0x80;
146+		glyph->descent = ((int16_t) m[i].character_descent) - 0x80;
147+
148+		/* computed stuff */
149+		glyph->height = glyph->ascent + glyph->descent;
150+
151+		glyph->hotx = -glyph->left_bearing;
152+		glyph->hoty = glyph->ascent;
153+	}
154+}
155+
156+static void
157+handle_metrics(void *metricbuf)
158+{
159+	struct metrics *metrics = metricbuf;
160+	fprintf(stderr, "metric format: %x\n", metrics->format);
161+
162+	if ((metrics->format & PCF_FORMAT_MASK) == PCF_DEFAULT_FORMAT) {
163+		fprintf(stderr, "todo...\n");
164+	} else if ((metrics->format & PCF_FORMAT_MASK) ==
165+		   PCF_COMPRESSED_METRICS) {
166+		handle_compressed_metrics(
167+		    metrics->compressed.count,
168+		    &metrics->compressed.compressed_metrics[0]);
169+	} else {
170+		fprintf(stderr, "incompatible format\n");
171+		abort();
172+	}
173+}
174+
175+static void
176+handle_glyph_names(struct glyph_names *names)
177+{
178+	fprintf(stderr, "glyph count %d\n", names->glyph_count);
179+
180+	if (names->glyph_count != extracted_font.count) {
181+		abort();
182+	}
183+
184+	fprintf(stderr, "glyph names format %x\n", names->format);
185+
186+	char *names_start = ((char *) names) + sizeof(struct glyph_names)
187+		+ (names->glyph_count + 1) * sizeof(int32_t);
188+
189+	int i;
190+	for (i = 0; i < names->glyph_count; ++i) {
191+		int32_t start = names->offsets[i];
192+		int32_t end = names->offsets[i+1];
193+		char *name = names_start + start;
194+		extracted_font.glyphs[i].name = calloc(1, end - start + 1);
195+		memcpy(extracted_font.glyphs[i].name, name, end - start);
196+	}
197+}
198+
199+static void
200+handle_bitmaps(struct bitmaps *bitmaps)
201+{
202+	fprintf(stderr, "bitmaps count %d\n", bitmaps->glyph_count);
203+
204+	if (bitmaps->glyph_count != extracted_font.count) {
205+		abort();
206+	}
207+
208+	fprintf(stderr, "format %x\n", bitmaps->format);
209+
210+	if (bitmaps->format != 2) {
211+		fprintf(stderr, "format not yet supported\n");
212+		abort();
213+	}
214+
215+	char *bitmaps_start = ((char*) bitmaps) + sizeof(struct bitmaps)
216+		+ (bitmaps->glyph_count + 4) * sizeof(int32_t);
217+
218+	for (unsigned i = 0; i < bitmaps->glyph_count; ++i) {
219+		int32_t offset = bitmaps->offsets[i];
220+		struct glyph *glyph = &extracted_font.glyphs[i];
221+		glyph->data_format = bitmaps->format;
222+
223+		glyph->data = bitmaps_start + offset;
224+	}
225+}
226+
227+static void
228+handle_pcf(void *fontbuf)
229+{
230+	struct pcf_header *header = fontbuf;
231+	fprintf(stderr, "tablecount %d\n", header->table_count);
232+
233+	for (unsigned i = 0; i < header->table_count; ++i) {
234+		struct toc_entry *entry = &header->tables[i];
235+		fprintf(stderr, "type: %d\n", entry->type);
236+		if (entry->type == PCF_METRICS) {
237+			handle_metrics((void *)((uintptr_t) fontbuf + entry->offset));
238+		} else if (entry->type == PCF_GLYPH_NAMES) {
239+			handle_glyph_names((void *)((uintptr_t) fontbuf + entry->offset));
240+		} else if (entry->type == PCF_BITMAPS) {
241+			handle_bitmaps((void *)((uintptr_t) fontbuf + entry->offset));
242+		}
243+	}
244+}
245+
246+static char
247+get_glyph_pixel(struct glyph *glyph, int x, int y)
248+{
249+	int absx = glyph->hotx + x;
250+	int absy = glyph->hoty + y;
251+
252+	if (absx < 0 || absx >= glyph->width ||
253+	    absy < 0 || absy >= glyph->height)
254+		return 0;
255+
256+	int stride = (glyph->width + 31) / 32 * 4;
257+	unsigned char block = glyph->data[absy * stride + (absx/8)];
258+	int idx = absx % 8;
259+	return (block >> idx) & 1;
260+}
261+
262+static struct {
263+	uint32_t *data;
264+	size_t capacity, size;
265+} data_buffer;
266+
267+static void
268+init_data_buffer()
269+{
270+	data_buffer.data = malloc(sizeof(uint32_t) * 10);
271+	data_buffer.capacity = 10;
272+	data_buffer.size = 0;
273+}
274+
275+static void
276+add_pixel(uint32_t pixel)
277+{
278+	if (data_buffer.size == data_buffer.capacity) {
279+		data_buffer.capacity *= 2;
280+		data_buffer.data =
281+			realloc(data_buffer.data,
282+				sizeof(uint32_t) * data_buffer.capacity);
283+	}
284+	data_buffer.data[data_buffer.size++] = pixel;
285+}
286+
287+struct reconstructed_glyph {
288+	int32_t width, height;
289+	int32_t hotspot_x, hotspot_y;
290+	size_t offset;
291+	char *name;
292+};
293+
294+static void
295+reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name,
296+		  struct reconstructed_glyph *glyph)
297+{
298+	int minx = min(-cursor->hotx, -mask->hotx);
299+	int maxx = max(cursor->right_bearing, mask->right_bearing);
300+
301+	int miny = min(-cursor->hoty, -mask->hoty);
302+	int maxy = max(cursor->height - cursor->hoty,
303+		       mask->height - mask->hoty);
304+
305+	int width = maxx - minx;
306+	int height = maxy - miny;
307+
308+	glyph->name = strdup(name);
309+	glyph->width = width;
310+	glyph->height = height;
311+	glyph->hotspot_x = -minx;
312+	glyph->hotspot_y = -miny;
313+	glyph->offset = data_buffer.size;
314+
315+	int x, y;
316+	for (y = miny; y < maxy; ++y) {
317+		for (x = minx; x < maxx; ++x) {
318+			char alpha = get_glyph_pixel(mask, x, y);
319+			if (alpha) {
320+				char color = get_glyph_pixel(cursor, x, y);
321+				if (color)
322+					add_pixel(0xff000000);
323+				else
324+					add_pixel(0xffffffff);
325+			} else {
326+				add_pixel(0);
327+			}
328+		}
329+	}
330+}
331+
332+/* From http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c */
333+static const char cursor_licence[] =
334+	"/*\n"
335+ 	"* Copyright 1999 SuSE, Inc.\n"
336+ 	"*\n"
337+ 	"* Permission to use, copy, modify, distribute, and sell this software and its\n"
338+ 	"* documentation for any purpose is hereby granted without fee, provided that\n"
339+ 	"* the above copyright notice appear in all copies and that both that\n"
340+ 	"* copyright notice and this permission notice appear in supporting\n"
341+ 	"* documentation, and that the name of SuSE not be used in advertising or\n"
342+ 	"* publicity pertaining to distribution of the software without specific,\n"
343+ 	"* written prior permission.  SuSE makes no representations about the\n"
344+ 	"* suitability of this software for any purpose.  It is provided \"as is\"\n"
345+ 	"* without express or implied warranty.\n"
346+ 	"*\n"
347+ 	"* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL\n"
348+ 	"* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE\n"
349+ 	"* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n"
350+ 	"* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\n"
351+ 	"* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n"
352+ 	"* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
353+ 	"*\n"
354+ 	"* Author:  Keith Packard, SuSE, Inc.\n"
355+ 	"*/\n";
356+
357+static void
358+write_output_file(FILE *file, struct reconstructed_glyph *glyphs, int n)
359+{
360+	int i, j, counter, size;
361+	uint32_t *data;
362+
363+	fprintf(file, "%s\n", cursor_licence);
364+
365+	fprintf(file, "static uint32_t cursor_data[] = {\n\t");
366+
367+	counter = 0;
368+	for (i = 0; i < n; ++i) {
369+		data = data_buffer.data + glyphs[i].offset;
370+		size = glyphs[i].width * glyphs[i].height;
371+
372+		for (j = 0; j < size; ++j) {
373+			fprintf(file, "0x%08x, ", data[j]);
374+			if (++counter % 6 == 0)
375+				fprintf(file, "\n\t");
376+		}
377+	}
378+	fprintf(file, "\n};\n\n");
379+
380+	fputs("enum cursor_type {\n", file);
381+
382+	for (i = 0; i < n; ++i)
383+		fprintf(file, "\tcursor_%s,\n", glyphs[i].name);
384+
385+	fputs("};\n\n", file);
386+
387+	fprintf(file,
388+		"static struct cursor {\n"
389+		"\tint width, height;\n"
390+		"\tint hotspot_x, hotspot_y;\n"
391+		"\tsize_t offset;\n"
392+		"} cursor_metadata[] = {\n");
393+
394+	for (i = 0; i < n; ++i)
395+		fprintf(file, "\t{ %d, %d, %d, %d, %zu }, /* %s */\n",
396+			glyphs[i].width, glyphs[i].height,
397+			glyphs[i].hotspot_x, glyphs[i].hotspot_y,
398+			glyphs[i].offset, glyphs[i].name);
399+
400+	fputs("};\n", file);
401+}
402+
403+struct glyph *
404+find_mask_glyph(char *name)
405+{
406+	const char mask[] = "_mask";
407+	const int masklen = strlen(mask);
408+
409+	int len = strlen(name);
410+	int i;
411+	for (i = 0; i < extracted_font.count; ++i) {
412+		struct glyph *g = &extracted_font.glyphs[i];
413+		int l2 = strlen(g->name);
414+		if ((l2 == len + masklen) &&
415+		    (memcmp(g->name, name, len) == 0) &&
416+		    (memcmp(g->name + len, mask, masklen) == 0)) {
417+			return g;
418+		}
419+	}
420+	return NULL;
421+}
422+
423+static void
424+find_cursor_and_mask(const char *name,
425+		     struct glyph **cursor,
426+		     struct glyph **mask)
427+{
428+	int i;
429+	char mask_name[100];
430+	sprintf(mask_name, "%s_mask", name);
431+
432+	*cursor = *mask = NULL;
433+
434+	for (i = 0; i < extracted_font.count && (!*mask || !*cursor); ++i) {
435+		struct glyph *g = &extracted_font.glyphs[i];
436+		if (!strcmp(name, g->name))
437+			*cursor = g;
438+		else if (!strcmp(mask_name, g->name))
439+			*mask = g;
440+	}
441+}
442+
443+static struct {
444+	char *target_name, *source_name;
445+} interesting_cursors[] = {
446+	{ "bottom_left_corner", "bottom_left_corner" },
447+	{ "bottom_right_corner", "bottom_right_corner" },
448+	{ "bottom_side", "bottom_side" },
449+	{ "grabbing", "fleur" },
450+	{ "left_ptr", "left_ptr" },
451+	{ "left_side", "left_side" },
452+	{ "right_side", "right_side" },
453+	{ "top_left_corner", "top_left_corner" },
454+	{ "top_right_corner", "top_right_corner" },
455+	{ "top_side", "top_side" },
456+	{ "xterm", "xterm" },
457+	{ "hand1", "hand1" },
458+	{ "watch", "watch" }
459+};
460+
461+static void
462+output_interesting_cursors(FILE *file)
463+{
464+	int i;
465+	int n = sizeof(interesting_cursors) / sizeof(interesting_cursors[0]);
466+	struct reconstructed_glyph *glyphs =
467+		malloc(n * sizeof(*glyphs));
468+
469+	for (i = 0; i < n; ++i) {
470+		struct glyph *cursor, *mask;
471+		find_cursor_and_mask(interesting_cursors[i].source_name,
472+				     &cursor, &mask);
473+		if (!cursor) {
474+			fprintf(stderr, "no cursor for %s\n",
475+			       interesting_cursors[i].source_name);
476+			abort();
477+		}
478+		if (!mask) {
479+			fprintf(stderr, "no mask for %s\n",
480+			       interesting_cursors[i].source_name);
481+			abort();
482+		}
483+		reconstruct_glyph(cursor, mask,
484+				  interesting_cursors[i].target_name,
485+				  &glyphs[i]);
486+	}
487+
488+	write_output_file(file, glyphs, n);
489+}
490+
491+int main(int argc, char *argv[])
492+{
493+	if (argc != 3) {
494+		fprintf(stderr, "Usage: %s input.pcf output.h\n", argv[0]);
495+		return EXIT_FAILURE;
496+	}
497+
498+	int fd = open(argv[1], O_RDONLY);
499+	struct stat filestat;
500+
501+	fstat(fd, &filestat);
502+
503+	void *fontbuf = mmap(NULL, filestat.st_size, PROT_READ,
504+			     MAP_PRIVATE, fd, 0);
505+
506+	handle_pcf(fontbuf);
507+
508+	init_data_buffer();
509+
510+	FILE *file = fopen(argv[2], "w");
511+	output_interesting_cursors(file);
512+	fclose(file);
513+
514+	return EXIT_SUCCESS;
515+}
+0, -0
+16, -0
 1@@ -0,0 +1,16 @@
 2+# swc: cursor/local.mk
 3+
 4+dir := cursor
 5+
 6+$(dir)_TARGETS := $(dir)/convert_font $(dir)/cursor_data.h
 7+
 8+$(dir)/convert_font: $(dir)/convert_font.o
 9+	$(link)
10+
11+$(dir)/cursor_data.h: $(dir)/cursor.pcf $(dir)/convert_font
12+	$(call quiet,GEN,$(dir)/convert_font) $< $@ 2> /dev/null
13+
14+CLEAN_FILES += $(dir)/convert_font.o
15+
16+include common.mk
17+