]> git.karo-electronics.de Git - gbdfed.git/blob - bdfgrab.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / bdfgrab.c
1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
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.
21  */
22
23 /*
24  * This file will only be compiled if the HAVE_XLIB macro is defined.
25  */
26 #ifdef HAVE_XLIB
27
28 /*
29  * Code to get BDF fonts from the X server.  Reimplementation of the famous
30  * "getbdf" program by the equally famous der Mouse :-)
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <X11/Xlib.h>
38 #include <X11/Xutil.h>
39 #include <X11/Xatom.h>
40 #include <X11/Xproto.h>
41 #if 0
42 #include <X11/Xmu/Error.h>
43 #endif
44 #include "bdfP.h"
45
46 /*
47  * Routine to compare two glyphs by encoding so they can be sorted.
48  */
49 static int
50 by_encoding(const void *a, const void *b)
51 {
52     bdf_glyph_t *c1, *c2;
53
54     c1 = (bdf_glyph_t *) a;
55     c2 = (bdf_glyph_t *) b;
56     if (c1->encoding < c2->encoding)
57       return -1;
58     else if (c1->encoding > c2->encoding)
59       return 1;
60     return 0;
61 }
62
63 static void
64 _bdf_get_glyphs(Display *d, XFontStruct *f, bdf_font_t *font,
65                 bdf_callback_t callback, void *data)
66 {
67     unsigned int off, b1, b2, black, x, y, bpr;
68     GC cleargc, drawgc;
69     Pixmap canvas;
70     XImage *image;
71     XCharStruct *cp;
72     bdf_glyph_t *gp;
73     XChar2b ch;
74     bdf_callback_struct_t cb;
75     char name[16];
76     XGCValues gcv;
77
78     black = BlackPixel(d, DefaultScreen(d));
79
80     /*
81      * Create the Pixmap which will be used to draw the glyphs.
82      */
83     canvas = XCreatePixmap(d, XRootWindow(d, DefaultScreen(d)),
84                            font->bbx.width, font->bbx.height, 1);
85
86     /*
87      * Create the graphics contexts for drawing.
88      */
89     gcv.function = GXcopy;
90     gcv.foreground = WhitePixel(d, DefaultScreen(d));
91     cleargc = XCreateGC(d, canvas, GCFunction|GCForeground, &gcv);
92
93     gcv.background = gcv.foreground;
94     gcv.foreground = black;
95     gcv.font = f->fid;
96     drawgc = XCreateGC(d, canvas,
97                        GCFunction|GCForeground|GCBackground|GCFont, &gcv);
98
99     /*
100      * Do it.
101      */
102     for (b1 = f->min_byte1; b1 <= f->max_byte1; b1++) {
103
104         off = (b1 - f->min_byte1) *
105             (f->max_char_or_byte2 + 1 - f->min_char_or_byte2);
106
107         for (b2 = f->min_char_or_byte2; b2 <= f->max_char_or_byte2;
108              b2++, off++) {
109
110             /*
111              * Point at the glyph metrics.
112              */
113             cp = (f->per_char != 0) ? f->per_char + off : &f->min_bounds;
114
115             if (cp->lbearing || cp->rbearing || cp->width ||
116                 cp->ascent || cp->descent) {
117                 /*
118                  * Make sure there is enough glyph storage to handle
119                  * the glyphs.
120                  */
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);
125                     else
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;
131                 }
132
133                 /*
134                  * Point at the next glyph structure.
135                  */
136                 gp = font->glyphs + font->glyphs_used++;
137
138                 /*
139                  * Determine the glyph encoding and set the metrics.
140                  */
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;
151
152                 /*
153                  * Create a glyph name.
154                  */
155                 sprintf(name, "char%d", gp->encoding);
156                 gp->name = (char *) malloc(strlen(name) + 1);
157                 (void) strcpy(gp->name, name);
158
159                 /*
160                  * Determine the number of bytes that will be needed for this
161                  * glyph.
162                  */
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);
167
168                 /*
169                  * Clear the PSF Unicode mappings.
170                  */
171                 gp->unicode.map_size = gp->unicode.map_used = 0;
172
173                 /*
174                  * Clear the canvas.
175                  */
176                 XFillRectangle(d, canvas, cleargc, 0, 0,
177                                font->bbx.width, font->bbx.height);
178
179                 /*
180                  * Render the glyph.
181                  */
182                 ch.byte1 = (b1 == 0) ? (b2 >> 8) : b1;
183                 ch.byte2 = b2;
184                 XDrawString16(d, canvas, drawgc, -cp->lbearing, cp->ascent,
185                               &ch, 1);
186                 image = XGetImage(d, canvas, 0, 0,
187                                   font->bbx.width, font->bbx.height, 1L,
188                                   XYPixmap);
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)] |=
193                               (0x80 >> (x & 7));
194                     }
195                 }
196                 XDestroyImage(image);
197
198                 /*
199                  * Call the update callback if necessary.
200                  */
201                 if (callback != 0) {
202                     cb.reason = BDF_LOADING;
203                     cb.total = font->glyphs_size;
204                     cb.current = font->glyphs_used;
205                     (*callback)(&cb, data);
206                 }
207             }
208         }
209     }
210
211     /*
212      * Delete the Pixmap and the GCs.
213      */
214     XFreePixmap(d, canvas);
215     XFreeGC(d, cleargc);
216     XFreeGC(d, drawgc);
217
218     /*
219      * Make sure the glyphs are sorted by encoding.
220      */
221     qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
222           by_encoding);
223 }
224
225 static int
226 error_handler(Display *d, XErrorEvent *event)
227 {
228
229     if (event->request_code != X_GetAtomName)
230       fprintf(stderr, "X Server Error\n");
231 #if 0
232         XmuPrintDefaultErrorMessage(d, event, stderr);
233 #endif
234     return 0;
235 }
236
237 bdf_font_t *
238 bdf_load_server_font(Display *d, XFontStruct *f, char *name,
239                      bdf_options_t *opts, bdf_callback_t callback, void *data)
240 {
241     unsigned int i, len, b1, b2;
242     bdf_font_t *font;
243     XFontProp *xfp;
244     XCharStruct *cp;
245     bdf_property_t *pp, prop;
246     bdf_callback_struct_t cb;
247     int (*old_error_handler)();
248
249     if (f == 0)
250       return 0;
251
252     font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
253
254     font->bpp = 1;
255
256     /*
257      * Set up the font bounding box.
258      */
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;
265
266     /*
267      * If the font happens to be a character cell or monowidth, make sure that
268      * value is taken from the max bounds.
269      */
270     font->monowidth = f->max_bounds.width;
271
272     font->default_glyph = (int) f->default_char;
273
274     /*
275      * Now load the font properties.
276      */
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)
280           /*
281            * Set the font name but don't add it to the list in the font.
282            */
283           font->name = XGetAtomName(d, (Atom) xfp->card32);
284         else {
285             /*
286              * Add the property to the font.
287              */
288             prop.name = XGetAtomName(d, xfp->name);
289             if (prop.name) {
290                 if ((pp = bdf_get_property(prop.name)) == 0) {
291                     /*
292                      * The property does not exist, so create it with type Atom.
293                      */
294                     bdf_create_property(prop.name, BDF_ATOM);
295                     pp = bdf_get_property(prop.name);
296                 }
297                 prop.format = pp->format;
298                 switch (prop.format) {
299                   case BDF_ATOM:
300                     prop.value.atom = XGetAtomName(d, (Atom) xfp->card32);
301                     break;
302                   case BDF_CARDINAL:
303                     prop.value.card32 = xfp->card32;
304                     break;
305                   case BDF_INTEGER:
306                     prop.value.int32 = (int) xfp->card32;
307                     break;
308                 }
309                 /*
310                  * Ignore the _XMBDFED_INFO property.
311                  */
312                 if (strcmp(prop.name, "_XMBDFED_INFO") != 0)
313                   bdf_add_font_property(font, &prop);
314             }
315
316             /*
317              * Free up the Atom names returned by X.
318              */
319             XFree(prop.name);
320             if (prop.format == BDF_ATOM)
321               XFree(prop.value.atom);
322         }
323     }
324     XSetErrorHandler(old_error_handler);
325
326     /*
327      * Now go through and initialize the various fields needed for the font.
328      */
329
330     /*
331      * If the font name was not set when the properties were loaded,
332      * set it to the name that was passed.
333      */
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);
338     }
339
340     /*
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.
344      */
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");
352
353     /*
354      * Check the point size.
355      */
356     if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0)
357       font->point_size = (pp->value.card32 / 10);
358     else
359       font->point_size = 12;
360
361     /*
362      * Check for the deprecated "RESOLUTION" property first in case it exists
363      * and "RESOLUTION_X" and "RESOLUTION_Y" do not.
364      */
365     if ((pp = bdf_get_font_property(font, "RESOLUTION")) != 0)
366       font->resolution_x = font->resolution_y = pp->value.int32;
367
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;
372
373     /*
374      * If the horizontal or vertical resolutions have not been set, then
375      * define them to be the resolution of the display.
376      */
377     if (font->resolution_x == 0)
378       font->resolution_x =
379           (int) (((((double) DisplayWidth(d, DefaultScreen(d))) * 25.4) /
380                    ((double) DisplayWidthMM(d, DefaultScreen(d)))) + 0.5);
381     if (font->resolution_y == 0)
382       font->resolution_y =
383           (int) (((((double) DisplayHeight(d, DefaultScreen(d))) * 25.4) /
384                    ((double) DisplayHeightMM(d, DefaultScreen(d)))) + 0.5);
385
386     /*
387      * Check the font ascent and descent.
388      */
389     if ((pp = bdf_get_font_property(font, "FONT_ASCENT")) != 0)
390       font->font_ascent = pp->value.int32;
391     else {
392         /*
393          * Add the FONT_ASCENT property.
394          */
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;
400     }
401
402     if ((pp = bdf_get_font_property(font, "FONT_DESCENT")) != 0)
403       font->font_descent = pp->value.int32;
404     else {
405         /*
406          * Add the FONT_DESCENT property.
407          */
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;
413     }
414
415     /*
416      * Get the font spacing.
417      */
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;
424         }
425     }
426
427     /*
428      * Now determine the number of glyphs.
429      */
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;
435                  b2++, len++) {
436                 cp = f->per_char + len;
437                 /*
438                  * If any of the metrics values are non-zero, then count this
439                  * as a glyph.
440                  */
441                 if (cp->lbearing || cp->rbearing || cp->width ||
442                     cp->ascent || cp->descent)
443                   font->glyphs_size++;
444             }
445         }
446     } else
447       font->glyphs_size = (f->max_byte1 + 1 - f->min_byte1) *
448           (f->max_char_or_byte2 + 1 - f->min_char_or_byte2);
449
450     /*
451      * Call the callback if it was provided.
452      */
453     if (callback != 0) {
454         cb.reason = BDF_LOAD_START;
455         cb.total = font->glyphs_size;
456         cb.current = 0;
457         (*callback)(&cb, data);
458     }
459
460     /*
461      * Allocate enough glyph storage for the specified number of glyphs.
462      */
463     font->glyphs = (bdf_glyph_t *)
464         malloc(sizeof(bdf_glyph_t) * font->glyphs_size);
465
466     /*
467      * Actually load the glyphs.
468      */
469     _bdf_get_glyphs(d, f, font, callback, data);
470
471     /*
472      * Add a message to the font to indicate it was loaded
473      * from the server.
474      */
475     _bdf_add_comment(font, "Font grabbed from the X server.", 31);
476     _bdf_add_acmsg(font, "Font grabbed from the X server.", 31);
477
478     /*
479      * Mark the font as being modified.
480      */
481     font->modified = 1;
482
483     return font;
484 }
485
486 #endif /* HAVE_XLIB */