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