1 /* $Id: toglFont.c,v 1.8 2009/05/22 00:18:36 gregcouch Exp $ */
2 
3 /* vi:set sw=4 expandtab: */
4 
5 /*
6  * Togl - a Tk OpenGL widget
7  *
8  * Copyright (C) 1996-2002  Brian Paul and Ben Bederson
9  * Copyright (C) 2005-2008  Greg Couch
10  * See the LICENSE file for copyright details.
11  */
12 
13 /*
14  * Togl Bitmap Font support
15  *
16  * If bitmap font support is requested, then this file is included into
17  * togl.c.  Parts of this file are based on <http://wiki.tcl.tk/13881>,
18  * "Creating and Using Tcl Handles in C Extensions".
19  *
20  * Neither the Tk public nor the internal interface give enough information
21  * to reuse the font in OpenGL, so we copy the private structures here to
22  * access what we need.
23  *
24  * Globals needed by the font module are in togl.c
25  */
26 
27 #include <tkFont.h>
28 
29 struct Togl_BitmapFontInfo
30 {
31     GLuint  base;
32     GLuint  first;
33     GLuint  last;
34     int     contextTag;
35     /* TODO: keep original font and/or encoding */
36 };
37 typedef struct Togl_BitmapFontInfo Togl_BitmapFontInfo;
38 
39 #define BITMAP_FONT_INFO(obj) \
40                 ((Togl_BitmapFontInfo *) (obj)->internalRep.otherValuePtr)
41 #define SET_BITMAP_FONT_INFO(obj) \
42                 (obj)->internalRep.otherValuePtr
43 
44 static void Togl_FontFree(Tcl_Obj *obj);
45 static void Togl_FontDup(Tcl_Obj *src, Tcl_Obj *dup);
46 static void Togl_FontString(Tcl_Obj *obj);
47 static int Togl_FontSet(Tcl_Interp *interp, Tcl_Obj *obj);
48 
49 static Tcl_ObjType Togl_BitmapFontType = {
50     "Togl BitmapFont",          /* name */
51     Togl_FontFree,              /* free internal rep */
52     Togl_FontDup,               /* dup internal rep */
53     Togl_FontString,            /* update string from internal rep */
54     Togl_FontSet                /* set internal rep from string */
55 };
56 
57 static int
Togl_FontSet(Tcl_Interp * interp,Tcl_Obj * obj)58 Togl_FontSet(Tcl_Interp *interp, Tcl_Obj *obj)
59 {
60     if (interp)
61         Tcl_AppendResult(interp, "cannot (re)build object of type \"",
62                 Togl_BitmapFontType.name, "\"", NULL);
63     return TCL_ERROR;
64 }
65 
66 static void
Togl_FontFree(Tcl_Obj * obj)67 Togl_FontFree(Tcl_Obj *obj)
68 {
69     Togl_BitmapFontInfo *bfi = BITMAP_FONT_INFO(obj);
70 
71     ckfree((char *) bfi);
72 }
73 
74 static void
Togl_FontString(Tcl_Obj * obj)75 Togl_FontString(Tcl_Obj *obj)
76 {
77     /* assert(obj->bytes == NULL) */
78     static char buf[256];
79     register unsigned len;
80     Togl_BitmapFontInfo *bfi = BITMAP_FONT_INFO(obj);
81 
82 #if !defined(TOGL_AGL) && !defined(TOGL_NSOPENGL)
83     snprintf(buf, sizeof buf - 1, "{{%s} %d %d %d}",
84             Togl_BitmapFontType.name, bfi->base, bfi->first, bfi->last);
85 #else
86     /* unlike every other platform, on Aqua, GLint is long */
87     snprintf(buf, sizeof buf - 1, "{{%s} %ld %ld %ld}",
88             Togl_BitmapFontType.name, bfi->base, bfi->first, bfi->last);
89 #endif
90     buf[sizeof buf - 1] = '\0';
91     len = strlen(buf);
92     obj->bytes = (char *) ckalloc(len + 1);
93     strcpy(obj->bytes, buf);
94     obj->length = len;
95 }
96 
97 static void
Togl_FontDup(Tcl_Obj * src,Tcl_Obj * dup)98 Togl_FontDup(Tcl_Obj *src, Tcl_Obj *dup)
99 {
100     /*
101      * When duplicated, lose the font-ness and just be a string.
102      * So don't copy the internal representation and don't set
103      * dup->typePtr.
104      */
105 }
106 
107 #if defined(TOGL_X11)
108 /* From tkUnixFont.c */
109 /*
110  * The following structure encapsulates an individual screen font.  A font
111  * object is made up of however many SubFonts are necessary to display a
112  * stream of multilingual characters.
113  */
114 
115 typedef struct FontFamily FontFamily;
116 
117 typedef struct SubFont
118 {
119     char  **fontMap;            /* Pointer to font map from the FontFamily,
120                                  * cached here to save a dereference. */
121     XFontStruct *fontStructPtr; /* The specific screen font that will be used
122                                  * when displaying/measuring chars belonging to
123                                  * the FontFamily. */
124     FontFamily *familyPtr;      /* The FontFamily for this SubFont. */
125 } SubFont;
126 
127 /*
128  * The following structure represents Unix's implementation of a font
129  * object.
130  */
131 
132 #  define SUBFONT_SPACE		3
133 #  define BASE_CHARS		256
134 
135 typedef struct UnixFont
136 {
137     TkFont  font;               /* Stuff used by generic font package.  Must be
138                                  * first in structure. */
139     SubFont staticSubFonts[SUBFONT_SPACE];
140     /* Builtin space for a limited number of SubFonts. */
141     int     numSubFonts;        /* Length of following array. */
142     SubFont *subFontArray;      /* Array of SubFonts that have been loaded in
143                                  * order to draw/measure all the characters
144                                  * encountered by this font so far.  All fonts
145                                  * start off with one SubFont initialized by
146                                  * AllocFont() from the original set of font
147                                  * attributes.  Usually points to
148                                  * staticSubFonts, but may point to malloced
149                                  * space if there are lots of SubFonts. */
150     SubFont controlSubFont;     /* Font to use to display control-character
151                                  * expansions. */
152 
153 #  if 0
154     Display *display;           /* Display that owns font. */
155     int     pixelSize;          /* Original pixel size used when font was
156                                  * constructed. */
157     TkXLFDAttributes xa;        /* Additional attributes that specify the
158                                  * preferred foundry and encoding to use when
159                                  * constructing additional SubFonts. */
160     int     widths[BASE_CHARS]; /* Widths of first 256 chars in the base font,
161                                  * for handling common case. */
162     int     underlinePos;       /* Offset from baseline to origin of underline
163                                  * bar (used when drawing underlined font)
164                                  * (pixels). */
165     int     barHeight;          /* Height of underline or overstrike bar (used
166                                  * when drawing underlined or strikeout font)
167                                  * (pixels). */
168 #  endif
169 } UnixFont;
170 
171 #elif defined(TOGL_WGL)
172 #  include <tkWinInt.h>
173 /* From tkWinFont.c */
174 
175 typedef struct FontFamily FontFamily;
176 
177 /*
178  * The following structure encapsulates an individual screen font.  A font
179  * object is made up of however many SubFonts are necessary to display a
180  * stream of multilingual characters.
181  */
182 
183 typedef struct SubFont
184 {
185     char  **fontMap;            /* Pointer to font map from the FontFamily,
186                                  * cached here to save a dereference. */
187     HFONT   hFont;              /* The specific screen font that will be used
188                                  * when displaying/measuring chars belonging to
189                                  * the FontFamily. */
190     FontFamily *familyPtr;      /* The FontFamily for this SubFont. */
191 } SubFont;
192 
193 /*
194  * The following structure represents Windows' implementation of a font
195  * object.
196  */
197 
198 #  define SUBFONT_SPACE		3
199 #  define BASE_CHARS		128
200 
201 typedef struct WinFont
202 {
203     TkFont  font;               /* Stuff used by generic font package.  Must be
204                                  * first in structure. */
205     SubFont staticSubFonts[SUBFONT_SPACE];
206     /* Builtin space for a limited number of SubFonts. */
207     int     numSubFonts;        /* Length of following array. */
208     SubFont *subFontArray;      /* Array of SubFonts that have been loaded in
209                                  * order to draw/measure all the characters
210                                  * encountered by this font so far.  All fonts
211                                  * start off with one SubFont initialized by
212                                  * AllocFont() from the original set of font
213                                  * attributes.  Usually points to
214                                  * staticSubFonts, but may point to malloced
215                                  * space if there are lots of SubFonts. */
216 
217     HWND    hwnd;               /* Toplevel window of application that owns
218                                  * this font, used for getting HDC for
219                                  * offscreen measurements. */
220     int     pixelSize;          /* Original pixel size used when font was
221                                  * constructed. */
222     int     widths[BASE_CHARS]; /* Widths of first 128 chars in the base font,
223                                  * for handling common case.  The base font is
224                                  * always used to draw characters between
225                                  * 0x0000 and 0x007f. */
226 } WinFont;
227 
228 #elif defined(TOGL_AGL)
229 
230 typedef struct FontFamily
231 {
232     struct FontFamily *nextPtr; /* Next in list of all known font families. */
233     int     refCount;           /* How many SubFonts are referring to this
234                                  * FontFamily.  When the refCount drops to
235                                  * zero, this FontFamily may be freed. */
236     /*
237      * Key.
238      */
239 
240     FMFontFamily faceNum;       /* Unique face number key for this FontFamily. */
241 
242     /*
243      * Derived properties.
244      */
245 
246     Tcl_Encoding encoding;      /* Encoding for this font family. */
247 #  if 0
248     int     isSymbolFont;       /* Non-zero if this is a symbol family. */
249     int     isMultiByteFont;    /* Non-zero if this is a multi-byte family. */
250     char    typeTable[256];     /* Table that identfies all lead bytes for a
251                                  * multi-byte family, used when measuring
252                                  * chars. If a byte is a lead byte, the value
253                                  * at the corresponding position in the
254                                  * typeTable is 1, otherwise 0.  If this is a
255                                  * single-byte font, all entries are 0. */
256     char   *fontMap[FONTMAP_PAGES];
257     /* Two-level sparse table used to determine quickly if the specified
258      * character exists. As characters are encountered, more pages in this
259      * table are dynamically added.  The contents of each page is a bitmask
260      * consisting of FONTMAP_BITSPERPAGE bits, representing whether this font
261      * can be used to display the given character at the corresponding bit
262      * position.  The high bits of the character are used to pick which page of
263      * the table is used. */
264 #  endif
265 } FontFamily;
266 
267 /*
268  * The following structure encapsulates an individual screen font.  A font
269  * object is made up of however many SubFonts are necessary to display a
270  * stream of multilingual characters.
271  */
272 
273 typedef struct SubFont
274 {
275     char  **fontMap;            /* Pointer to font map from the FontFamily,
276                                  * cached here to save a dereference. */
277     FontFamily *familyPtr;      /* The FontFamily for this SubFont. */
278 } SubFont;
279 
280 /*
281  * The following structure represents Macintosh's implementation of a font
282  * object.
283  */
284 
285 #  define SUBFONT_SPACE                3
286 
287 typedef struct MacFont
288 {
289     TkFont  font;               /* Stuff used by generic font package.  Must be
290                                  * first in structure. */
291     SubFont staticSubFonts[SUBFONT_SPACE];
292     /* Builtin space for a limited number of SubFonts. */
293     int     numSubFonts;        /* Length of following array. */
294     SubFont *subFontArray;      /* Array of SubFonts that have been loaded in
295                                  * order to draw/measure all the characters
296                                  * encountered by this font so far.  All fonts
297                                  * start off with one SubFont initialized by
298                                  * AllocFont() from the original set of font
299                                  * attributes.  Usually points to
300                                  * staticSubFonts, but may point to malloced
301                                  * space if there are lots of SubFonts. */
302 
303     short   size;               /* Font size in pixels, constructed from font
304                                  * attributes. */
305     short   style;              /* Style bits, constructed from font
306                                  * attributes. */
307 } MacFont;
308 #endif
309 
310 /*
311  * Load the named bitmap font as a sequence of bitmaps in a display list.
312  * fontname may be any font recognized by Tk_GetFont.
313  */
314 Tcl_Obj *
Togl_LoadBitmapFont(const Togl * togl,const char * fontname)315 Togl_LoadBitmapFont(const Togl *togl, const char *fontname)
316 {
317     Tk_Font font;
318     Togl_BitmapFontInfo *bfi;
319     Tcl_Obj *obj;
320 
321 #if defined(TOGL_X11)
322     UnixFont *unixfont;
323     XFontStruct *fontinfo;
324 #elif defined(TOGL_WGL)
325     WinFont *winfont;
326     HFONT   oldFont;
327     TEXTMETRIC tm;
328 #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL)
329     MacFont *macfont;
330 #endif
331     int     first, last, count;
332     GLuint  fontbase;
333 
334     if (!fontname) {
335         fontname = DEFAULT_FONTNAME;
336     }
337 
338     font = Tk_GetFont(togl->Interp, togl->TkWin, fontname);
339     if (!font) {
340         return NULL;
341     }
342 #if defined(TOGL_X11)
343     unixfont = (UnixFont *) font;
344     fontinfo = unixfont->subFontArray->fontStructPtr;
345     first = fontinfo->min_char_or_byte2;
346     last = fontinfo->max_char_or_byte2;
347 #elif defined(TOGL_WGL)
348     winfont = (WinFont *) font;
349     oldFont =
350             (HFONT) SelectObject(togl->tglGLHdc, winfont->subFontArray->hFont);
351     GetTextMetrics(togl->tglGLHdc, &tm);
352     first = tm.tmFirstChar;
353     last = tm.tmLastChar;
354 #elif defined(TOGL_AGL) || defined(TOGL_NSOPENGL)
355     macfont = (MacFont *) font;
356     first = 10;                 /* don't know how to determine font range on
357                                  * Mac... */
358     last = 255;
359 #endif
360 
361     if (last > 255)
362         last = 255;             /* no unicode support */
363 
364     count = last - first + 1;
365     fontbase = glGenLists((GLuint) (last + 1));
366     if (fontbase == 0) {
367 #ifdef TOGL_WGL
368         SelectObject(togl->tglGLHdc, oldFont);
369 #endif
370         Tk_FreeFont(font);
371         return NULL;
372     }
373 #if defined(TOGL_WGL)
374     wglUseFontBitmaps(togl->tglGLHdc, first, count, fontbase + first);
375     SelectObject(togl->tglGLHdc, oldFont);
376 #elif defined(TOGL_X11)
377     glXUseXFont(fontinfo->fid, first, count, (int) fontbase + first);
378 #elif defined(TOGL_AGL)
379     /* deprecated in OS X 10.5 */
380     aglUseFont(togl->Ctx,
381             macfont->subFontArray->familyPtr->faceNum,
382             macfont->style, macfont->size, first, count, fontbase + first);
383 #elif defined(TOGL_NSOPENGL)
384     /* No NSOpenGL equivalent to aglUseFont(). */
385 #endif
386     Tk_FreeFont(font);
387 
388     bfi = (Togl_BitmapFontInfo *) ckalloc(sizeof (Togl_BitmapFontInfo));
389     bfi->base = fontbase;
390     bfi->first = first;
391     bfi->last = last;
392     bfi->contextTag = togl->contextTag;
393 
394     obj = Tcl_NewObj();
395     SET_BITMAP_FONT_INFO(obj) = bfi;
396     obj->typePtr = &Togl_BitmapFontType;
397 
398     return obj;
399 }
400 
401 /*
402  * Release the display lists which were generated by Togl_LoadBitmapFont().
403  */
404 int
Togl_UnloadBitmapFont(const Togl * togl,Tcl_Obj * toglfont)405 Togl_UnloadBitmapFont(const Togl *togl, Tcl_Obj *toglfont)
406 {
407     Togl_BitmapFontInfo *bfi;
408 
409     if (toglfont == NULL || toglfont->typePtr != &Togl_BitmapFontType) {
410         Tcl_Interp *interp = Togl_Interp(togl);
411 
412         Tcl_AppendResult(interp, "font not found", NULL);
413         return TCL_ERROR;
414     }
415     bfi = BITMAP_FONT_INFO(toglfont);
416     glDeleteLists(bfi->base, bfi->last + 1);    /* match glGenLists */
417     return TCL_OK;
418 }
419 
420 int
Togl_WriteObj(const Togl * togl,const Tcl_Obj * toglfont,Tcl_Obj * obj)421 Togl_WriteObj(const Togl *togl, const Tcl_Obj *toglfont, Tcl_Obj *obj)
422 {
423     const char *str;
424     int     len;
425 
426     str = Tcl_GetStringFromObj(obj, &len);
427     return Togl_WriteChars(togl, toglfont, str, len);
428 }
429 
430 int
Togl_WriteChars(const Togl * togl,const Tcl_Obj * toglfont,const char * str,int len)431 Togl_WriteChars(const Togl *togl, const Tcl_Obj *toglfont, const char *str,
432         int len)
433 {
434     /* TODO: assume utf8 encoding and convert to font encoding */
435     Togl_BitmapFontInfo *bfi;
436 
437     if (toglfont == NULL || toglfont->typePtr != &Togl_BitmapFontType)
438         return -1;
439     bfi = BITMAP_FONT_INFO(toglfont);
440     if (Togl_ContextTag(togl) != bfi->contextTag)
441         return -1;
442     if (len == 0)
443         len = strlen(str);
444     glListBase(bfi->base);
445     glCallLists(len, GL_UNSIGNED_BYTE, str);
446     return len;
447 }
448