2 * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * This file will only be compiled if the HAVE_XLIB macro is defined.
29 * Code to get BDF fonts from the X server. Reimplementation of the famous
30 * "getbdf" program by the equally famous der Mouse :-)
38 #include <X11/Xutil.h>
39 #include <X11/Xatom.h>
40 #include <X11/Xproto.h>
42 #include <X11/Xmu/Error.h>
47 * Routine to compare two glyphs by encoding so they can be sorted.
50 by_encoding(const void *a, const void *b)
54 c1 = (bdf_glyph_t *) a;
55 c2 = (bdf_glyph_t *) b;
56 if (c1->encoding < c2->encoding)
58 else if (c1->encoding > c2->encoding)
64 _bdf_get_glyphs(Display *d, XFontStruct *f, bdf_font_t *font,
65 bdf_callback_t callback, void *data)
67 unsigned int off, b1, b2, black, x, y, bpr;
74 bdf_callback_struct_t cb;
78 black = BlackPixel(d, DefaultScreen(d));
81 * Create the Pixmap which will be used to draw the glyphs.
83 canvas = XCreatePixmap(d, XRootWindow(d, DefaultScreen(d)),
84 font->bbx.width, font->bbx.height, 1);
87 * Create the graphics contexts for drawing.
89 gcv.function = GXcopy;
90 gcv.foreground = WhitePixel(d, DefaultScreen(d));
91 cleargc = XCreateGC(d, canvas, GCFunction|GCForeground, &gcv);
93 gcv.background = gcv.foreground;
94 gcv.foreground = black;
96 drawgc = XCreateGC(d, canvas,
97 GCFunction|GCForeground|GCBackground|GCFont, &gcv);
102 for (b1 = f->min_byte1; b1 <= f->max_byte1; b1++) {
104 off = (b1 - f->min_byte1) *
105 (f->max_char_or_byte2 + 1 - f->min_char_or_byte2);
107 for (b2 = f->min_char_or_byte2; b2 <= f->max_char_or_byte2;
111 * Point at the glyph metrics.
113 cp = (f->per_char != 0) ? f->per_char + off : &f->min_bounds;
115 if (cp->lbearing || cp->rbearing || cp->width ||
116 cp->ascent || cp->descent) {
118 * Make sure there is enough glyph storage to handle
121 if (font->glyphs_used == font->glyphs_size) {
122 if (font->glyphs_size == 0)
123 font->glyphs = (bdf_glyph_t *)
124 malloc(sizeof(bdf_glyph_t) * 16);
126 font->glyphs = (bdf_glyph_t *)
127 realloc((char *) font->glyphs,
128 sizeof(bdf_glyph_t) *
129 (font->glyphs_size + 16));
130 font->glyphs_size += 16;
134 * Point at the next glyph structure.
136 gp = font->glyphs + font->glyphs_used++;
139 * Determine the glyph encoding and set the metrics.
141 gp->encoding = (b1 << 8) | b2;
142 gp->dwidth = cp->width;
143 gp->swidth = (unsigned short) (cp->width * 72000.0
144 / (font->point_size * font->resolution_x));
145 gp->bbx.width = cp->rbearing - cp->lbearing;
146 gp->bbx.x_offset = cp->lbearing;
147 gp->bbx.ascent = cp->ascent;
148 gp->bbx.descent = cp->descent;
149 gp->bbx.y_offset = -cp->descent;
150 gp->bbx.height = cp->ascent + cp->descent;
153 * Create a glyph name.
155 sprintf(name, "char%d", gp->encoding);
156 gp->name = (char *) malloc(strlen(name) + 1);
157 (void) strcpy(gp->name, name);
160 * Determine the number of bytes that will be needed for this
163 bpr = (gp->bbx.width + 7) >> 3;
164 gp->bytes = bpr * gp->bbx.height;
165 gp->bitmap = (unsigned char *) malloc(gp->bytes);
166 (void) memset((char *) gp->bitmap, 0, gp->bytes);
169 * Clear the PSF Unicode mappings.
171 gp->unicode.map_size = gp->unicode.map_used = 0;
176 XFillRectangle(d, canvas, cleargc, 0, 0,
177 font->bbx.width, font->bbx.height);
182 ch.byte1 = (b1 == 0) ? (b2 >> 8) : b1;
184 XDrawString16(d, canvas, drawgc, -cp->lbearing, cp->ascent,
186 image = XGetImage(d, canvas, 0, 0,
187 font->bbx.width, font->bbx.height, 1L,
189 for (y = 0; y < gp->bbx.height; y++) {
190 for (x = 0; x < gp->bbx.width; x++) {
191 if (XGetPixel(image, x, y) == black)
192 gp->bitmap[(y * bpr) + (x >> 3)] |=
196 XDestroyImage(image);
199 * Call the update callback if necessary.
202 cb.reason = BDF_LOADING;
203 cb.total = font->glyphs_size;
204 cb.current = font->glyphs_used;
205 (*callback)(&cb, data);
212 * Delete the Pixmap and the GCs.
214 XFreePixmap(d, canvas);
219 * Make sure the glyphs are sorted by encoding.
221 qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
226 error_handler(Display *d, XErrorEvent *event)
229 if (event->request_code != X_GetAtomName)
230 fprintf(stderr, "X Server Error\n");
232 XmuPrintDefaultErrorMessage(d, event, stderr);
238 bdf_load_server_font(Display *d, XFontStruct *f, char *name,
239 bdf_options_t *opts, bdf_callback_t callback, void *data)
241 unsigned int i, len, b1, b2;
245 bdf_property_t *pp, prop;
246 bdf_callback_struct_t cb;
247 int (*old_error_handler)();
252 font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
257 * Set up the font bounding box.
259 font->bbx.width = f->max_bounds.rbearing - f->min_bounds.lbearing;
260 font->bbx.x_offset = f->min_bounds.lbearing;
261 font->bbx.height = f->max_bounds.ascent + f->max_bounds.descent;
262 font->bbx.ascent = f->max_bounds.ascent;
263 font->bbx.descent = f->max_bounds.descent;
264 font->bbx.y_offset = -font->bbx.descent;
267 * If the font happens to be a character cell or monowidth, make sure that
268 * value is taken from the max bounds.
270 font->monowidth = f->max_bounds.width;
272 font->default_glyph = (int) f->default_char;
275 * Now load the font properties.
277 old_error_handler = XSetErrorHandler(error_handler);
278 for (i = 0, xfp = f->properties; i < f->n_properties; i++, xfp++) {
279 if (xfp->name == XA_FONT)
281 * Set the font name but don't add it to the list in the font.
283 font->name = XGetAtomName(d, (Atom) xfp->card32);
286 * Add the property to the font.
288 prop.name = XGetAtomName(d, xfp->name);
290 if ((pp = bdf_get_property(prop.name)) == 0) {
292 * The property does not exist, so create it with type Atom.
294 bdf_create_property(prop.name, BDF_ATOM);
295 pp = bdf_get_property(prop.name);
297 prop.format = pp->format;
298 switch (prop.format) {
300 prop.value.atom = XGetAtomName(d, (Atom) xfp->card32);
303 prop.value.card32 = xfp->card32;
306 prop.value.int32 = (int) xfp->card32;
310 * Ignore the _XMBDFED_INFO property.
312 if (strcmp(prop.name, "_XMBDFED_INFO") != 0)
313 bdf_add_font_property(font, &prop);
317 * Free up the Atom names returned by X.
320 if (prop.format == BDF_ATOM)
321 XFree(prop.value.atom);
324 XSetErrorHandler(old_error_handler);
327 * Now go through and initialize the various fields needed for the font.
331 * If the font name was not set when the properties were loaded,
332 * set it to the name that was passed.
334 if (font->name == 0) {
335 len = (unsigned int) strlen(name);
336 font->name = (char *) malloc(len + 1);
337 (void) memcpy(font->name, name, len + 1);
341 * If the font default glyph is non-zero, make sure the DEFAULT_CHAR
342 * property is updated appropriately. Otherwise, make sure the
343 * DEFAULT_CHAR property is deleted from the font.
345 if (font->default_glyph > 0) {
346 prop.name = "DEFAULT_CHAR";
347 prop.format = BDF_INTEGER;
348 prop.value.int32 = font->default_glyph;
349 bdf_add_font_property(font, &prop);
350 } else if (bdf_get_font_property(font, "DEFAULT_CHAR") != 0)
351 bdf_delete_font_property(font, "DEFAULT_CHAR");
354 * Check the point size.
356 if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0)
357 font->point_size = (pp->value.card32 / 10);
359 font->point_size = 12;
362 * Check for the deprecated "RESOLUTION" property first in case it exists
363 * and "RESOLUTION_X" and "RESOLUTION_Y" do not.
365 if ((pp = bdf_get_font_property(font, "RESOLUTION")) != 0)
366 font->resolution_x = font->resolution_y = pp->value.int32;
368 if ((pp = bdf_get_font_property(font, "RESOLUTION_X")) != 0)
369 font->resolution_x = pp->value.int32;
370 if ((pp = bdf_get_font_property(font, "RESOLUTION_Y")) != 0)
371 font->resolution_y = pp->value.int32;
374 * If the horizontal or vertical resolutions have not been set, then
375 * define them to be the resolution of the display.
377 if (font->resolution_x == 0)
379 (int) (((((double) DisplayWidth(d, DefaultScreen(d))) * 25.4) /
380 ((double) DisplayWidthMM(d, DefaultScreen(d)))) + 0.5);
381 if (font->resolution_y == 0)
383 (int) (((((double) DisplayHeight(d, DefaultScreen(d))) * 25.4) /
384 ((double) DisplayHeightMM(d, DefaultScreen(d)))) + 0.5);
387 * Check the font ascent and descent.
389 if ((pp = bdf_get_font_property(font, "FONT_ASCENT")) != 0)
390 font->font_ascent = pp->value.int32;
393 * Add the FONT_ASCENT property.
395 prop.name = "FONT_ASCENT";
396 prop.format = BDF_INTEGER;
397 prop.value.int32 = font->bbx.ascent;
398 bdf_add_font_property(font, &prop);
399 font->font_ascent = font->bbx.ascent;
402 if ((pp = bdf_get_font_property(font, "FONT_DESCENT")) != 0)
403 font->font_descent = pp->value.int32;
406 * Add the FONT_DESCENT property.
408 prop.name = "FONT_DESCENT";
409 prop.format = BDF_INTEGER;
410 prop.value.int32 = font->bbx.descent;
411 bdf_add_font_property(font, &prop);
412 font->font_descent = font->bbx.descent;
416 * Get the font spacing.
418 font->spacing = BDF_PROPORTIONAL;
419 if ((pp = bdf_get_font_property(font, "SPACING")) != 0) {
420 switch (pp->value.atom[0]) {
421 case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
422 case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break;
423 case 'C': case 'c': font->spacing = BDF_CHARCELL; break;
428 * Now determine the number of glyphs.
430 if (f->per_char != 0) {
431 for (b1 = f->min_byte1; b1 <= f->max_byte1; b1++) {
432 len = (b1 - f->min_byte1) *
433 (f->max_char_or_byte2 + 1 - f->min_char_or_byte2);
434 for (b2 = f->min_char_or_byte2; b2 <= f->max_char_or_byte2;
436 cp = f->per_char + len;
438 * If any of the metrics values are non-zero, then count this
441 if (cp->lbearing || cp->rbearing || cp->width ||
442 cp->ascent || cp->descent)
447 font->glyphs_size = (f->max_byte1 + 1 - f->min_byte1) *
448 (f->max_char_or_byte2 + 1 - f->min_char_or_byte2);
451 * Call the callback if it was provided.
454 cb.reason = BDF_LOAD_START;
455 cb.total = font->glyphs_size;
457 (*callback)(&cb, data);
461 * Allocate enough glyph storage for the specified number of glyphs.
463 font->glyphs = (bdf_glyph_t *)
464 malloc(sizeof(bdf_glyph_t) * font->glyphs_size);
467 * Actually load the glyphs.
469 _bdf_get_glyphs(d, f, font, callback, data);
472 * Add a message to the font to indicate it was loaded
475 _bdf_add_comment(font, "Font grabbed from the X server.", 31);
476 _bdf_add_acmsg(font, "Font grabbed from the X server.", 31);
479 * Mark the font as being modified.
486 #endif /* HAVE_XLIB */