1 
2 /*
3  * Mesa 3-D graphics library
4  *
5  * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 
27 /* xfonts.c -- glXUseXFont() for Mesa written by
28  * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de
29  */
30 
31 #include <stdio.h>
32 #include "glxheader.h"
33 #include "main/context.h"
34 #include "xfonts.h"
35 
36 
37 /* Some debugging info.  */
38 
39 #ifdef DEBUG
40 #include <ctype.h>
41 
42 int debug_xfonts = 0;
43 
44 static void
dump_char_struct(XCharStruct * ch,char * prefix)45 dump_char_struct(XCharStruct * ch, char *prefix)
46 {
47    printf("%slbearing = %d, rbearing = %d, width = %d\n",
48 	  prefix, ch->lbearing, ch->rbearing, ch->width);
49    printf("%sascent = %d, descent = %d, attributes = %u\n",
50 	  prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
51 }
52 
53 static void
dump_font_struct(XFontStruct * font)54 dump_font_struct(XFontStruct * font)
55 {
56    printf("ascent = %d, descent = %d\n", font->ascent, font->descent);
57    printf("char_or_byte2 = (%u,%u)\n",
58 	  font->min_char_or_byte2, font->max_char_or_byte2);
59    printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
60    printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False");
61    printf("default_char = %c (\\%03o)\n",
62 	  (char) (isprint(font->default_char) ? font->default_char : ' '),
63 	  font->default_char);
64    dump_char_struct(&font->min_bounds, "min> ");
65    dump_char_struct(&font->max_bounds, "max> ");
66 #if 0
67    for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) {
68       char prefix[8];
69       sprintf(prefix, "%d> ", c);
70       dump_char_struct(&font->per_char[c], prefix);
71    }
72 #endif
73 }
74 
75 static void
dump_bitmap(unsigned int width,unsigned int height,GLubyte * bitmap)76 dump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap)
77 {
78    unsigned int x, y;
79 
80    printf("    ");
81    for (x = 0; x < 8 * width; x++)
82       printf("%o", 7 - (x % 8));
83    putchar('\n');
84    for (y = 0; y < height; y++) {
85       printf("%3o:", y);
86       for (x = 0; x < 8 * width; x++)
87 	 putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x %
88 									 8))))
89 		 ? '*' : '.');
90       printf("   ");
91       for (x = 0; x < width; x++)
92 	 printf("0x%02x, ", bitmap[width * (height - y - 1) + x]);
93       putchar('\n');
94    }
95 }
96 #endif /* DEBUG */
97 
98 
99 /* Implementation.  */
100 
101 /* Fill a BITMAP with a character C from thew current font
102    in the graphics context GC.  WIDTH is the width in bytes
103    and HEIGHT is the height in bits.
104 
105    Note that the generated bitmaps must be used with
106 
107         glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
108         glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
109         glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
110         glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
111         glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
112         glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
113 
114    Possible optimizations:
115 
116      * use only one reusable pixmap with the maximum dimensions.
117      * draw the entire font into a single pixmap (careful with
118        proportional fonts!).
119 */
120 
121 
122 /*
123  * Generate OpenGL-compatible bitmap.
124  */
125 static void
fill_bitmap(Display * dpy,Window win,GC gc,unsigned int width,unsigned int height,int x0,int y0,unsigned int c,GLubyte * bitmap)126 fill_bitmap(Display * dpy, Window win, GC gc,
127 	    unsigned int width, unsigned int height,
128 	    int x0, int y0, unsigned int c, GLubyte * bitmap)
129 {
130    XImage *image;
131    unsigned int x, y;
132    Pixmap pixmap;
133    XChar2b char2b;
134 
135    pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1);
136    XSetForeground(dpy, gc, 0);
137    XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height);
138    XSetForeground(dpy, gc, 1);
139 
140    char2b.byte1 = (c >> 8) & 0xff;
141    char2b.byte2 = (c & 0xff);
142 
143    XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1);
144 
145    image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap);
146    if (image) {
147       /* Fill the bitmap (X11 and OpenGL are upside down wrt each other).  */
148       for (y = 0; y < height; y++)
149 	 for (x = 0; x < 8 * width; x++)
150 	    if (XGetPixel(image, x, y))
151 	       bitmap[width * (height - y - 1) + x / 8] |=
152 		  (1 << (7 - (x % 8)));
153       XDestroyImage(image);
154    }
155 
156    XFreePixmap(dpy, pixmap);
157 }
158 
159 /*
160  * determine if a given glyph is valid and return the
161  * corresponding XCharStruct.
162  */
163 static XCharStruct *
isvalid(XFontStruct * fs,unsigned int which)164 isvalid(XFontStruct * fs, unsigned int which)
165 {
166    unsigned int rows, pages;
167    unsigned int byte1 = 0, byte2 = 0;
168    int i, valid = 1;
169 
170    rows = fs->max_byte1 - fs->min_byte1 + 1;
171    pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
172 
173    if (rows == 1) {
174       /* "linear" fonts */
175       if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
176 	 valid = 0;
177    }
178    else {
179       /* "matrix" fonts */
180       byte2 = which & 0xff;
181       byte1 = which >> 8;
182       if ((fs->min_char_or_byte2 > byte2) ||
183 	  (fs->max_char_or_byte2 < byte2) ||
184 	  (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
185 	 valid = 0;
186    }
187 
188    if (valid) {
189       if (fs->per_char) {
190 	 if (rows == 1) {
191 	    /* "linear" fonts */
192 	    return (fs->per_char + (which - fs->min_char_or_byte2));
193 	 }
194 	 else {
195 	    /* "matrix" fonts */
196 	    i = ((byte1 - fs->min_byte1) * pages) +
197 	       (byte2 - fs->min_char_or_byte2);
198 	    return (fs->per_char + i);
199 	 }
200       }
201       else {
202 	 return (&fs->min_bounds);
203       }
204    }
205    return (NULL);
206 }
207 
208 
209 void
Fake_glXUseXFont(Font font,int first,int count,int listbase)210 Fake_glXUseXFont(Font font, int first, int count, int listbase)
211 {
212    Display *dpy;
213    Window win;
214    Pixmap pixmap;
215    GC gc;
216    XGCValues values;
217    unsigned long valuemask;
218    XFontStruct *fs;
219    GLint swapbytes, lsbfirst, rowlength;
220    GLint skiprows, skippixels, alignment;
221    unsigned int max_width, max_height, max_bm_width, max_bm_height;
222    GLubyte *bm;
223    int i;
224 
225    dpy = glXGetCurrentDisplay();
226    if (!dpy)
227       return;			/* I guess glXMakeCurrent wasn't called */
228    win = RootWindow(dpy, DefaultScreen(dpy));
229 
230    fs = XQueryFont(dpy, font);
231    if (!fs) {
232       _mesa_error(NULL, GL_INVALID_VALUE,
233 		  "Couldn't get font structure information");
234       return;
235    }
236 
237    /* Allocate a bitmap that can fit all characters.  */
238    max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
239    max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
240    max_bm_width = (max_width + 7) / 8;
241    max_bm_height = max_height;
242 
243    bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
244    if (!bm) {
245       XFreeFontInfo(NULL, fs, 1);
246       _mesa_error(NULL, GL_OUT_OF_MEMORY,
247 		  "Couldn't allocate bitmap in glXUseXFont()");
248       return;
249    }
250 
251 #if 0
252    /* get the page info */
253    pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
254    firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
255    lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
256    rows = fs->max_byte1 - fs->min_byte1 + 1;
257    unsigned int first_char, last_char, pages, rows;
258 #endif
259 
260    /* Save the current packing mode for bitmaps.  */
261    glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
262    glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
263    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
264    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
265    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
266    glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
267 
268    /* Enforce a standard packing mode which is compatible with
269       fill_bitmap() from above.  This is actually the default mode,
270       except for the (non)alignment.  */
271    glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
272    glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
273    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
274    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
275    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
276    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
277 
278    pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
279    values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
280    values.background = WhitePixel(dpy, DefaultScreen(dpy));
281    values.font = fs->fid;
282    valuemask = GCForeground | GCBackground | GCFont;
283    gc = XCreateGC(dpy, pixmap, valuemask, &values);
284    XFreePixmap(dpy, pixmap);
285 
286 #ifdef DEBUG
287    if (debug_xfonts)
288       dump_font_struct(fs);
289 #endif
290 
291    for (i = 0; i < count; i++) {
292       unsigned int width, height, bm_width, bm_height;
293       GLfloat x0, y0, dx, dy;
294       XCharStruct *ch;
295       int x, y;
296       unsigned int c = first + i;
297       int list = listbase + i;
298       int valid;
299 
300       /* check on index validity and get the bounds */
301       ch = isvalid(fs, c);
302       if (!ch) {
303 	 ch = &fs->max_bounds;
304 	 valid = 0;
305       }
306       else {
307 	 valid = 1;
308       }
309 
310 #ifdef DEBUG
311       if (debug_xfonts) {
312 	 char s[7];
313 	 sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
314 	 dump_char_struct(ch, s);
315       }
316 #endif
317 
318       /* glBitmap()' parameters:
319          straight from the glXUseXFont(3) manpage.  */
320       width = ch->rbearing - ch->lbearing;
321       height = ch->ascent + ch->descent;
322       x0 = -ch->lbearing;
323       y0 = ch->descent - 0;	/* XXX used to subtract 1 here */
324       /* but that caused a conformace failure */
325       dx = ch->width;
326       dy = 0;
327 
328       /* X11's starting point.  */
329       x = -ch->lbearing;
330       y = ch->ascent;
331 
332       /* Round the width to a multiple of eight.  We will use this also
333          for the pixmap for capturing the X11 font.  This is slightly
334          inefficient, but it makes the OpenGL part real easy.  */
335       bm_width = (width + 7) / 8;
336       bm_height = height;
337 
338       glNewList(list, GL_COMPILE);
339       if (valid && (bm_width > 0) && (bm_height > 0)) {
340 
341 	 memset(bm, '\0', bm_width * bm_height);
342 	 fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
343 
344 	 glBitmap(width, height, x0, y0, dx, dy, bm);
345 #ifdef DEBUG
346 	 if (debug_xfonts) {
347 	    printf("width/height = %u/%u\n", width, height);
348 	    printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
349 	    dump_bitmap(bm_width, bm_height, bm);
350 	 }
351 #endif
352       }
353       else {
354 	 glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
355       }
356       glEndList();
357    }
358 
359    free(bm);
360    XFreeFontInfo(NULL, fs, 1);
361    XFreeGC(dpy, gc);
362 
363    /* Restore saved packing modes.  */
364    glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
365    glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
366    glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
367    glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
368    glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
369    glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
370 }
371