summaryrefslogtreecommitdiff
path: root/genfontfile.c
blob: a98f80124434ba77e7699d12023f5d1bf8810623 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/* Copyright (c) Mark J. Kilgard, 1997. */

/* This program is freely distributable without licensing fees  and is
   provided without guarantee or warrantee expressed or  implied. This
   program is -not- in the public domain. */

/* X compile line: cc -o gentexfont gentexfont.c -lX11 */

/* 2000-10-01: Stripped down the original code to get a simple bitmap C-code generator  */
/*             for use with the VDR project (see http://www.cadsoft.de/people/kls/vdr)  */
/*             Renamed the file 'genfontfile.c' since it no longer generates 'tex' data */
/*             Klaus Schmidinger (kls@cadsoft.de)                                       */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <math.h>

typedef struct {
  unsigned short c;       /* Potentially support 16-bit glyphs. */
  unsigned char width;
  unsigned char height;
  signed char xoffset;
  signed char yoffset;
  signed char advance;
  char dummy;           /* Space holder for alignment reasons. */
  short x;
  short y;
} TexGlyphInfo;

typedef struct {
  short width;
  short height;
  short xoffset;
  short yoffset;
  short advance;
  unsigned char *bitmap;
} PerGlyphInfo, *PerGlyphInfoPtr;

typedef struct {
  int min_char;
  int max_char;
  int max_ascent;
  int max_descent;
  PerGlyphInfo glyph[1];
} FontInfo, *FontInfoPtr;

Display *dpy;
FontInfoPtr fontinfo;

/* #define REPORT_GLYPHS */
#ifdef REPORT_GLYPHS
#define DEBUG_GLYPH4(msg,a,b,c,d) printf(msg,a,b,c,d)
#define DEBUG_GLYPH(msg) printf(msg)
#else
#define DEBUG_GLYPH4(msg,a,b,c,d) { /* nothing */ }
#define DEBUG_GLYPH(msg) { /* nothing */ }
#endif

#define MAX_GLYPHS_PER_GRAB 512  /* this is big enough for 2^9 glyph
                                    character sets */

FontInfoPtr
SuckGlyphsFromServer(Display * dpy, Font font)
{
  Pixmap offscreen;
  XFontStruct *fontinfo;
  XImage *image;
  GC xgc;
  XGCValues values;
  int numchars;
  int width, height, pixwidth;
  int i, j;
  XCharStruct *charinfo;
  XChar2b character;
  unsigned char *bitmapData;
  int x, y;
  int spanLength;
  int charWidth, charHeight, maxSpanLength;
  int grabList[MAX_GLYPHS_PER_GRAB];
  int glyphsPerGrab = MAX_GLYPHS_PER_GRAB;
  int numToGrab, thisglyph;
  FontInfoPtr myfontinfo;

  fontinfo = XQueryFont(dpy, font);
  if (!fontinfo)
    return NULL;

  numchars = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1;
  if (numchars < 1)
    return NULL;

  myfontinfo = (FontInfoPtr) malloc(sizeof(FontInfo) + (numchars - 1) * sizeof(PerGlyphInfo));
  if (!myfontinfo)
    return NULL;

  myfontinfo->min_char = fontinfo->min_char_or_byte2;
  myfontinfo->max_char = fontinfo->max_char_or_byte2;
  myfontinfo->max_ascent = fontinfo->max_bounds.ascent;
  myfontinfo->max_descent = fontinfo->max_bounds.descent;

  width = fontinfo->max_bounds.rbearing - fontinfo->min_bounds.lbearing;
  height = fontinfo->max_bounds.ascent + fontinfo->max_bounds.descent;

  maxSpanLength = (width + 7) / 8;
  /* Be careful determining the width of the pixmap; the X protocol allows
     pixmaps of width 2^16-1 (unsigned short size) but drawing coordinates
     max out at 2^15-1 (signed short size).  If the width is too large, we
     need to limit the glyphs per grab.  */
  if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) {
    glyphsPerGrab = (1 << 15) / (8 * maxSpanLength);
  }
  pixwidth = glyphsPerGrab * 8 * maxSpanLength;
  offscreen = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)),
    pixwidth, height, 1);

  values.font = font;
  values.background = 0;
  values.foreground = 0;
  xgc = XCreateGC(dpy, offscreen, GCFont | GCBackground | GCForeground, &values);

  XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height);
  XSetForeground(dpy, xgc, 1);

  numToGrab = 0;
  if (fontinfo->per_char == NULL) {
    charinfo = &(fontinfo->min_bounds);
    charWidth = charinfo->rbearing - charinfo->lbearing;
    charHeight = charinfo->ascent + charinfo->descent;
    spanLength = (charWidth + 7) / 8;
  }
  for (i = 0; i < numchars; i++) {
    if (fontinfo->per_char != NULL) {
      charinfo = &(fontinfo->per_char[i]);
      charWidth = charinfo->rbearing - charinfo->lbearing;
      charHeight = charinfo->ascent + charinfo->descent;
      if (charWidth == 0 || charHeight == 0) {
        /* Still must move raster pos even if empty character */
        myfontinfo->glyph[i].width = 0;
        myfontinfo->glyph[i].height = 0;
        myfontinfo->glyph[i].xoffset = 0;
        myfontinfo->glyph[i].yoffset = 0;
        myfontinfo->glyph[i].advance = charinfo->width;
        myfontinfo->glyph[i].bitmap = NULL;
        goto PossiblyDoGrab;
      }
    }
    grabList[numToGrab] = i;

    /* XXX is this right for large fonts? */
    character.byte2 = (i + fontinfo->min_char_or_byte2) & 255;
    character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8;

    /* XXX we could use XDrawImageString16 which would also paint the backing 

       rectangle but X server bugs in some scalable font rasterizers makes it 

       more effective to do XFillRectangles to clear the pixmap and
       XDrawImage16 for the text.  */
    XDrawString16(dpy, offscreen, xgc,
      -charinfo->lbearing + 8 * maxSpanLength * numToGrab,
      charinfo->ascent, &character, 1);

    numToGrab++;

  PossiblyDoGrab:

    if (numToGrab >= glyphsPerGrab || i == numchars - 1) {
      image = XGetImage(dpy, offscreen,
        0, 0, pixwidth, height, 1, XYPixmap);
      for (j = 0; j < numToGrab; j++) {
        thisglyph = grabList[j];
        if (fontinfo->per_char != NULL) {
          charinfo = &(fontinfo->per_char[thisglyph]);
          charWidth = charinfo->rbearing - charinfo->lbearing;
          charHeight = charinfo->ascent + charinfo->descent;
          spanLength = (charWidth + 7) / 8;
        }
        bitmapData = calloc(height * spanLength, sizeof(char));
        if (!bitmapData)
          goto FreeFontAndReturn;
        DEBUG_GLYPH4("index %d, glyph %d (%d by %d)\n",
          j, thisglyph + fontinfo->min_char_or_byte2, charWidth, charHeight);
        for (y = 0; y < charHeight; y++) {
          for (x = 0; x < charWidth; x++) {
            /* XXX The algorithm used to suck across the font ensures that
               each glyph begins on a byte boundary.  In theory this would
               make it convienent to copy the glyph into a byte oriented
               bitmap.  We actually use the XGetPixel function to extract
               each pixel from the image which is not that efficient.  We
               could either do tighter packing in the pixmap or more
               efficient extraction from the image.  Oh well.  */
            if (XGetPixel(image, j * maxSpanLength * 8 + x, charHeight - 1 - y)) {
              DEBUG_GLYPH("x");
              bitmapData[y * spanLength + x / 8] |= (1 << (x & 7));
            } else {
              DEBUG_GLYPH(" ");
            }
          }
          DEBUG_GLYPH("\n");
        }
        myfontinfo->glyph[thisglyph].width = charWidth;
        myfontinfo->glyph[thisglyph].height = charHeight;
        myfontinfo->glyph[thisglyph].xoffset = charinfo->lbearing;
        myfontinfo->glyph[thisglyph].yoffset = -charinfo->descent;
        myfontinfo->glyph[thisglyph].advance = charinfo->width;
        myfontinfo->glyph[thisglyph].bitmap = bitmapData;
      }
      XDestroyImage(image);
      numToGrab = 0;
      /* do we need to clear the offscreen pixmap to get more? */
      if (i < numchars - 1) {
        XSetForeground(dpy, xgc, 0);
        XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height);
        XSetForeground(dpy, xgc, 1);
      }
    }
  }
  XFreeGC(dpy, xgc);
  XFreePixmap(dpy, offscreen);
  return myfontinfo;

FreeFontAndReturn:
  XDestroyImage(image);
  XFreeGC(dpy, xgc);
  XFreePixmap(dpy, offscreen);
  for (j = i - 1; j >= 0; j--) {
    if (myfontinfo->glyph[j].bitmap)
      free(myfontinfo->glyph[j].bitmap);
  }
  free(myfontinfo);
  return NULL;
}

void
printGlyph(FontInfoPtr font, int c)
{
  PerGlyphInfoPtr glyph;
  unsigned char *bitmapData;
  int width, height, spanLength;
  int x, y, l;
  char buf[1000], *b;

  if (c < font->min_char || c > font->max_char) {
    fprintf(stderr, "out of range glyph\n");
    exit(1);
  }
  glyph = &font->glyph[c - font->min_char];
  bitmapData = glyph->bitmap;
    width = glyph->width;
    spanLength = (width + 7) / 8;
    height = glyph->height;

    printf("  {             // %d\n", c);
    printf("     %d, %d,\n", glyph->advance, font->max_ascent + font->max_descent);
    for (y = 0; y < font->max_ascent - glyph->yoffset - height; y++) {
        printf("     0x%08X,  // ", 0);
        for (x = 0; x < glyph->xoffset + width || x < glyph->advance; x++)
            putchar('.');
        putchar('\n');
        }
    for (y = height; y-- > 0;) {
        l = 0;
        b = buf;
        for (x = 0; x < glyph->xoffset; x++)
            *b++ = '.';
        if (bitmapData) {
           for (x = 0; x < width; x++) {
               if (bitmapData[y * spanLength + x / 8] & (1 << (x & 7))) {
                  *b++ = '*';
                  l |= 1;
                  }
               else
                  *b++ = '.';
               l <<= 1;
               }
           for (x = 0; x < glyph->advance - width - glyph->xoffset; x++) {
               *b++ = '.';
               l <<= 1;
               }
           }
        *b = 0;
        printf("     0x%08X,  // %s\n", l, buf);
        }
    for (y = 0; y < font->max_descent + glyph->yoffset; y++) {
        printf("     0x%08X,  // ", 0);
        for (x = 0; x < glyph->xoffset + width || x < glyph->advance; x++)
            putchar('.');
        putchar('\n');
        }
    printf("  },\n");
}

void
getMetric(FontInfoPtr font, int c, TexGlyphInfo * tgi)
{
  PerGlyphInfoPtr glyph;
  unsigned char *bitmapData;

  tgi->c = c;
  if (c < font->min_char || c > font->max_char) {
    tgi->width = 0;
    tgi->height = 0;
    tgi->xoffset = 0;
    tgi->yoffset = 0;
    tgi->dummy = 0;
    tgi->advance = 0;
    return;
  }
  glyph = &font->glyph[c - font->min_char];
  bitmapData = glyph->bitmap;
  if (bitmapData) {
    tgi->width = glyph->width;
    tgi->height = glyph->height;
    tgi->xoffset = glyph->xoffset;
    tgi->yoffset = glyph->yoffset;
  } else {
    tgi->width = 0;
    tgi->height = 0;
    tgi->xoffset = 0;
    tgi->yoffset = 0;
  }
  tgi->dummy = 0;
  tgi->advance = glyph->advance;
}

int
main(int argc, char *argv[])
{
  int c;
  TexGlyphInfo tgi;
  int usageError = 0;
  char *varname, *fontname;
  XFontStruct *xfont;
  int i;

  if (argc == 3) {
     varname  = argv[1];
     fontname = argv[2];
     }
  else
     usageError = 1;

  if (usageError) {
    fprintf(stderr, "\n");
    fprintf(stderr, "usage: genfontfile variable_name X_font_name\n");
    fprintf(stderr, "\n");
    exit(1);
  }

  dpy = XOpenDisplay(NULL);
  if (!dpy) {
    fprintf(stderr, "could not open display\n");
    exit(1);
  }
  /* find an OpenGL-capable RGB visual with depth buffer */
  xfont = XLoadQueryFont(dpy, fontname);
  if (!xfont) {
    fprintf(stderr, "could not get load X font: %s\n", fontname);
    exit(1);
  }
  fontinfo = SuckGlyphsFromServer(dpy, xfont->fid);
  if (!fontinfo) {
    fprintf(stderr, "could not get font glyphs\n");
    exit(1);
  }

  printf("%s[][%d] = {\n", varname, fontinfo->max_ascent + fontinfo->max_descent + 2);
  for (c = 32; c < 256; c++) {
      getMetric(fontinfo, c, &tgi);
      printGlyph(fontinfo, c);
      }
  printf("  };\n");
  return 0;
}