[PATCH v2 2/2] cursor: add cursor.pcf and extraction program

Philipp Brüschweiler blei42 at gmail.com
Thu Sep 6 09:54:02 PDT 2012


---
 cursor/convert_font.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++
 cursor/cursor.pcf     | Bin 0 -> 14208 bytes
 2 Dateien geändert, 531 Zeilen hinzugefügt(+)
 create mode 100644 cursor/convert_font.c
 create mode 100644 cursor/cursor.pcf

diff --git a/cursor/convert_font.c b/cursor/convert_font.c
new file mode 100644
index 0000000..f297125
--- /dev/null
+++ b/cursor/convert_font.c
@@ -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();
+}
diff --git a/cursor/cursor.pcf b/cursor/cursor.pcf
new file mode 100644
index 0000000000000000000000000000000000000000..812fcc54fdf1ad92f7016e69fe6c2dd9f7437b62
GIT binary patch
literal 14208
zcmeI3dvILUeaC;o#u%`JjCqK}Sn{L95J=1;AizN~m||0c4VVB4Ag!gfts+_SO0s1m
ztkrYZFWD-zB at 8KU$aEOUbUc$x$7MWa6H;hWQka$uq+!Z>pv2QqB%W4^(Dw5^_nzIW
zMRr}<{Fj~i+;h(F{Lbrle&^hC at 0Ci{*0oGGvl2J~-h^}*SGpb=$($+~;q)nHFDVRl
zUR!APDw!2wdKq~?Jm0K3Ot(<U=mloUFn#!Bv-KB|K+o5|>WUyvmiv{QLO>a_%hCEO
zVaZiomP(?m<%-+~w<&Tn)cQ!1A~}AW6q%`uSvOp_a at Ae8uDD_OYFoWN-Wso%zpimh
z%lg*&6|qFTqJ2YrLtT5*ns_2!Z>v_WxOsKWZ7aTcz5U_Jn^#+1d!n^DVRu~bO5b|@
zZ7XlOef5f!H(McEb7wShm)%*jJkY-7_NB{e?pU#Gwd=CR>wl$0W`X+pZcgLMag|w0
zk)Ou(v;8zjkJ#4q&_H_2_Mz1F*6yL?V4`QJd(Q*?L)*JM2Zna^6k=rb_H*g$-<nd1
zG$oRQL%X}X_6!a7P<D4Wxr06A?(QacuxCq(S~}9y(vccUr-`N0RGJ*TKSdklrczEu
z4|;cR-Ohz#+f($#T~a}>)HN3?T(+z6Aou?Mq5l4 at 149D?T>4W~I*>+|N|8*b6O3q&
zE_?H_Jq5kO$P0a82tB(s)ZN<#DdsM1s=!^6d+2>~FTJO`=>d0fLvR<@I5F&!Mz3o-
zdRS;6g at sb-<PLh(wbL8InFQJPZe%-pHg^--)I*HM`**raP_s<expSy{cjqqZ+tfX@
zr at Os}3pUu*hjDiGVblJ8Y&tN|$;i|9YvfxrmmQi*W at aEoeW^5Uq*AmIPKE11!3Nl+
zYmg?Bdmrc<+LNRz*G6w24fXYR?;YyxW8{7P8<WH~b`wLdYcG1PL at MnX-=t)_E(M!z
zW#rr4Wi!?tqz65Nn!)YP>xd0#&Y7~*USjFJ*b3VZVl`*KFjnwRJS?dSoDU^;(C6-*
z^d%Ye1)C;!VAJlM^q^-Kxjlo7Jh_8*yLZy@?J0M8pl?Si)!Dxzoz_}=BwRw3gdMOS
zMxcx}vK(4qA7tQ7m_wnv;URb#X0X at Y1by%mcpK)h*WC?|!pm^RiRi#CcmZZiBMrOY
zA7J`PX3HQ62Vo2<**rU7AG`#{##ad~upi!r3)$$_!}s82m~krgKpz~0F{qqDJ#YX<
zp_2Ws1NOrREczTfBkY4Ll$~aFC+vlnU at DtTHFUrM7==nUrCQhv2jDO)I-S126L1(R
zW}^f9APW^|kcKoIfDhoZGr4cT_aO^&&N5pK55dcD#@W~jc0mTL%xnpC!ozS7UWG9z
zJBK{zfCKOWEdD(9g8gt97JY#}!V_>97R at 0IPrz$%#<|Qn^ua+GgUjZcwZZq{ZCF^&
z{SJ1)K^TK270BQrcmZb2qa4)3_ux&KGvDk7*zU{N>Tco(mYJPYX?EHYv+`@qu2Egs
zdz85!!H0z6k||F*(sgA<NROITjhS_gn~is&SA{-$Bj^joB~zYsq^mNgQPvg%bs0Jt
zkiOc<&|Vf=XuDE=Tw?Y)K;-VjmL)<RMtw=@&BAC^(2neo1=lupbyDaWC})k}R_<(&
zBh*h}SrOkPtu9HPqwQikkc)Bp<6%fnrZOt4Iuwr*ZBxT8u0v^2+ at 8`&<XOU5tWkI8
zRmH4l8AJJ5qME1QGEU{^DJL!&c{j{qO;W~_Bky{AKZ;~NU!lsp{y>4(@WWhJ0iPF@
zNyp0-(zIg%d&dImTtJ@}V7teW*TEaik=Id}s|rBO$--<HV+~gVeHmr~hZ)Z>io at u6
zq?aFaE{HqdqU_X*+1H>HDxeyYFa};np>Nl1x+AQeBlsOuLJMRe17i`STik9n)lP=&
zxty`DV(i&ahrncWp?!TaUSR)_O-C8z2xFHYNH1!0#WU1(Ed2N~Dt`=$$D_Jw&ORYL
zvD)mz8nZK3nf>Apv)fn0?Zn|s;vXVAk-SgPDM8ouF-Q1+U@>hAzdpu at 3%~X*Wh at tC
zSFh*85p={Tofl*1iE(Twa at f;z1i$k7KFq2ddfJcX&Smew|Fq{tkxY4hzf_qlWk$=9
zRnbmYfZy}9?|CHi`O;Mxl~rADG3T={HT&s8vn?=dKI;U39Y^P9tXa>0aIgBu%Yyyb
z&#!cjTxs^J&1V1E#9TD9FRV3tzm at UQ&Tqb2;NvTZx0}7#NnTfg{7m=SX|<g5?=*Yw
z2G(bFzzKxn5#--s&R>CV-4)0rcjKV^7=0Me1r*QyvE(XWjSVNGi~96aI9a}AS{ua_
zx36 at uj!$1ZkNxl#vm4Ln{(mO-WX>(CI43>BeMa>wR9bT7OHcYLx0d;8`jy%J*n1Op
zZREaQ^9lDm$|UKxLZu~FzVxK8a>_p%8t>8aB+t;V$%u}7vV1SArhF}S)3}y%mRmL}
z7*AIhmGe`m at ky?H=}BMZvV_``<TKi%{t3T(ej|QFpVe=LN=rW39 at atqejOLz_q<#>
zTECO6Tfcr4`h4jsUBdk)N{qCK$`p5XR1t>w_5Ex59L3AMp2EfSP5omj+uzWx_9Drm
zNTxjLNLP6y;P<5By-0bYcx>9cR7QF32D6xO36wMc;LlD;=A#-a&@YAQl$i=_kw(De
zfjY7czhVqJD~-aqYzSG(YEBPO_E8w5Pzs0!<*SJlwe1d8oZ*vGX&Wj~DFw`HBtPBu
zHRy(ItNkSHX4E$48 at +?6q|6-9d5x~Pwq=hYD*QG+IFt2v5}AHZ6_-qT(uvOL`>ZeR
zb5*qWI_(aBEkJR}lqVfOukSL at k7=}=XOxqv>m1rgt?*OgJjS(<GXiytQhsCs`!i*Z
z&_{PaN2iKG<gil?b>Sm3#u*#VFotjxMur*p^Nb&rEOyp8PVt}6_H$(vs|rwDGUZ7}
zx{7C{Pup3L4;((5wRSaSs5^>e%9D<CT{+6yT)=)MFL0k=4rRM8#$E-}Gzp}2AJlwC
z=^*V4L;t2k+Y0;Z`>k-ioI0onlQ<Z at TMr85pR<|sJJ?rd<1GI|SiU5%QR$ns341>P
zh2*EPK_4CIq)wIpnDR#$ht9c2gxc>4#;&v4h{%QEuY-P!QC8*M0iE$DDJOe)`)j=a
z71sF)aoKx>cFw2B0^pI*Fi+s5)Z=_N)Kgilqv-neXYd?#bWyAdWOnUwC5(L=<C at O6
z^m5aM+~cRuXPGUf?h4iv&#_7J4BKcishry{X-n-m`_d1M%RL9ti1RJNY!!7N*BUeQ
zRbFF%?qajvTH3Fk$P{GL at Y@;qTN#5~Jk8vGpP@~a8>c?)>AmPp3ArxD9?^muF~M`@
zFvs}QgtKbS?5QU?EB+z~PkhPj)O`%+D52L=81>=L8kc=^uKMj4gSD=G{Y89Cz9|%!
zO#6Uzr0dF%=g(-z+qT!&Sq76CuH(!u^Opl+=L5Mg&2hk(3b&=!5{hG$kq`NMWf!`*
zx4jSYU6CQK@}d{6g9R`fKBjSnN=x1gQ$o}~2ZBBDB6STTi;i1q$(4Va2+I)7*AtEV
zenw@{xG!HEPFOo+7U%nPNrw4(CSd+|&Ay9|MUl+s7l*Da_Q+wx&w|!LbS#s_{rG)<
zj}{h>_kXI`*LzgMgbfwfn_=!c$g3voX3l<mi1$eU%)OrVx{rOK0+gpvd#%oUi+G<m
zm-SIT#-4Igur|iZ&7NJ#nt22J=8(M}?5kPwvlzmk38lBK3ZLhmCyM9m0_H2q?|Qzn
zjG3*?Y9Rw!<0TblKW{8hQi}|xv6q#x_hqq%_Wlkdge<6>_KoP;h{nf;16%p~H0E{R
zPqfZ&g?ph7(xCfaDJ;h3&i>dvi5*SQzLBP>{GNdsZ47-eDqDy4&Z3`XZrxr_|J-IX
zmv9bpbfu^Hdx1S&DDL}rXr9 at j82(U-I-QmN=nbs9&cHsttlt;i-bh=j<K13(gFT2%
zXqY`z&%-J|{(N8`)ghZl@%|f?DLzs}vHuq5Q?*_J+Viy63p%Gh2U%pAFQ(8Ig}g(^
zG&@--;V8(4<Jd*_=RNQk{2TbQwsfL;&gRHkAPE`Bg8Jq32-Tlln0}RT7hrBTm6}ei
z?IdI%3(mHL?%f2Tw~glZAS?k*qfkBGkkyN+2i(o$63SgcoKR`Wm2aLA;*b&VlCK*E
zH;$;!DlNJ4rRN5vkoG6T_j9s5C&ND`+n<W(bTS>uN;25;nE>qzPZsgJ-Yc}eOXe5I
zEePJj=v|EGU36wu6e!*kPQvMO!v!{z7DsRp&*tpJc}N=b0Q>Mwv0pF;dL9${E+hU<
zV5f3IXK%tJWRQuhC}$c&bS`vfL&C8fc7<FyA!Rsj9yeX+UIT0^?)gq@@OW_N7Ol5X
zzml+2b#SiLSyT7Z(>j7sX~}i|)Ok{Q(R;Mgk}DrIw=Q(<V#w~irgb9uVo*Ez@#e?}
zr6pIsQ=~o3oi+^@lFnC5J8oXP2r1|KAzkEZSnVh(o1k*sc9hLEe)XdhWEXEErH_aI
zP21{Qbl#4)UEinZyczc-_i$d0&)tuo!d^%hv5WK|JOgF3C^Hu{IZ=b<%xa+pI*RBd
zy$!k)b}?VuD7yqZ5#UOB^vpi%gu=QkWsT~Y+!n$jV4^cslta&>WuxbH$8fMN-P$Cs
zXL3C=YE#b;dZuFV>5N^J(w;bUD0pA1d!cxX7Y35~e6O#v)9|Yq@)^qOY at vIn?wcQ7
zjZe}SeQ*7!Jdi1`jQXXgGAe7tlLQwM{srM#gbd5(!585VibBbhC!{Cam+_3>8L~~!
z`-qR1B)Zil1uE#D=TYW#N^P(%{n>Hh>8uAFUF%uzl#_-nDKBc73!&%BO8nw69DYic
z{ftm`>AQ#Cjb45^ZnGqKwp2NtE%kh<I;SzOy|p~c#DY+1$^G-E^s}_#&!bCdN6)Bw
zR(<vm-=E$HLjUZle7&bonQEJyT>0d3>8riTi0)mJ<x57BZvVQ5a2#|VkWY*f7mLwZ
zEPGD{Eqv^06~Qr)F1fwOy)(r=diE6B at 7);@*$6hvV%IF=&oX|?LWa3VN2q;|zRA^*
zejFCiuKQ+3yZVObb)shn#VL~i9_PNxq3FKV(XRV;N4xr#Cq3cY&7V=o(>FPNo2!Nj
z&^J4MyVEy3uUFiz&MDDva{5M>g%;4aJAK2`w>*EI(fkShsv!%j7^A+;=^LG7lM$Um
z#WR%2GDh!PdcQ57m3%V%cr(<0EQ-gMp^al9SJ02C&EJDI6Q_$4_WOHC-v=vTX#}Qa
z(tD8hefeQ0JPrOnpzxItoxA;h>iyzqVez at o`@zw|wEUcB&!2LpeUIl*{hi8nWs}cM
zHT at 7t`gwR0?>S!QyH{0kuXlFO@!n#~B=f?$$V5oec|RUI+CV~i at p$r%eUt(D`-4KQ
z>jB2ni_dpw&3<$!U>@<=$h6nHwU4eZ=k5=bQ#f8uKN(-KujJDjJ37%a@(KBf{N;F%
zuF4E+jzi=N-d~OuO2_M~EX#`Dx7}5j5+qY>s-0-l>?C?}GJj2YDmSK?94PdcgtP2)
z-cg-lXY!WyY+lfwW1qJ#(DQRSJd|4n_p<rCzgoz>?mX^!i+Cq{fqls?w2SP^_7ygX
zi+KpT)Gp&MF)z0(=<Stum0iuD;cKjhDpvMVyOwuf%Zxvmv>W*A%oTQ{{gK^dU*~T#
zSK2DOg(vjeY_;8P->^IEPP>c0=J=M~ZTIlhUSqWuvo-9E^%l3aw$9dDgZ(k<s?nNk
zgEjMHxX}{UYHikTo3LMpZLzI(Kda~gKDcz at q21QQd$&I8w*gD>24K7Gu$??5?zTbO
zV|#7L{=^=%hwM-7&+O0bVP`qn at DW%@<oEpE22=3^@&D}$*Ro!P_cyIqwqDkuvHpUi
z^p%7w;a*69_K0rS0T07d at GQIn+?w4tnwivD28-ZQxDIZHdm#=RVKel=Zuky74u1^?
zLGPS at 35Ve$IGGO4gtOpWI3F$t-NRQy95zA^?1t~aU%?OIY505iIs7YR;WzLujKK-)
z?=xXG%!LJT5mdr*xCLsU0Xm=?^gjF%coKd9KZ2jZtMD59JG=)|xu=~1XM+AVa}j(6
zu7+y35$=K}*bD<O1b+!n!PD>@yaHKx2adpr`gR8AK_#q&d!Pln;6Zo{_QQ|imv9K)
zfe)dCd+T&K1I~pnfzIVu!BY4-tcF@>hF*9Oo`AoF7vWWS3*Lc`fz91cf!Qz*E`Ul{
z3M=7usD-t#5$>!B|90I+YMNrL_gO5FXx<!L1HqbDYrMY3iEHYcH*c_F!Kc;QTP7&A
zw}dLqu{K-7#V6M_w>GqGK@>#1xUH?ZsirZ$wymbFIk6$0K%rPPK{e5^Zhf(CR5n4m
zwV^)lD^z?!W?MX;N7QF^)U>uVBw~#e^U)xyF212Ho~UVQOIRTqW;G=08sk>yf>6}h
zTz8+<=^6@}*REA7?dz;A9}Tk-&8 at 9gr)xw|lZbDMCt9i2WrV4S!unVPT~VfDK}LN;
ztf_fJeT@^_gjA@|+-CL7;iM2 at luB!`&LirZ+t)P40}mjhkO;FAF=nbUmRJ|J`a(RK
z+1eCqYz#A9JfGQuYq|Cku`n8B#XIWO$2L%-j|Aeijq&z`xoaR;*Sv<lB`gd>A^)tg
z#n$N>2&k(5VsqDm;1VaeBoxGBi8foWYanQ-Yu;eGgvkW4z=93=XprR`RW9Ho5wUYN
zCoi~~OUluFq at cg19Y5dTGJ<HB)mVcq at TSHv5{eUE97Y0hQ*47lm}sc4Z;XfaHboL)
zc5^%4)TC=5XyIR78X7GKLJ_Xt7B{VcHm}v#-fAse0*#IB at z%Bm3>54g6O(~TupDKj
zd at P#b>=fh_3>BnhseCL_CLEK?iW)1?)>zZXhGISvlxdAMG-~TH9|^^4+ at 2QpyfvE2
zE38MQ;Pi&lL`h!JO=w^PlnSZ5LNJcJMkJY6VXw^R`*=Qc)2DheQ4%Vy$Bpoo)*uXp
z4O<&Ftg}`ZgrXL<KhDlB at S;R)OC1i>+7d)Uaa#;ME<uvWx_FxfK`08=Mw<&lQFBYg
z2G%wqS)>x~^Ld>hT~G=v714?c3Tn=cR7t^!l#&aDVW^vk-)C)Hf at Hg2Up^9wo7N=a
yjg2v5BXN;X?3Z2pgk`rm)>gOP+%?ea;MUM&?ivWVMRVNA|4NC?f at A%U*M9>8^juE>

literal 0
HcmV?d00001

-- 
1.7.12



More information about the wayland-devel mailing list