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