1 /* QuesoGLC
2  * A free implementation of the OpenGL Character Renderer (GLC)
3  * Copyright (c) 2002, 2004-2009, Bertrand Coconnier
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 /* $Id: font.c 857 2009-01-17 12:17:31Z bcoconni $ */
20 
21 /** \file
22  *  defines the so-called "Font commands" described in chapter 3.7 of the GLC
23  *  specs.
24  */
25 
26 /** \defgroup font Font commands
27  *  Commands to create, manage and destroy fonts.
28  *
29  *  A font is a stylistically consistent set of glyphs that can be used to
30  *  render some set of characters. Each font has a family name (for example
31  *  Palatino) and a state variable that selects one of the faces (for
32  *  example Regular, Bold, Italic, BoldItalic) that the font contains. A
33  *  typeface is the combination of a family and a face (for example
34  *  Palatino Bold).
35  *
36  *  A font is an instantiation of a master for a given face.
37  *
38  *  Every font has an associated character map. A character map is a table of
39  *  entries that maps integer values to the name string that identifies the
40  *  characters. The character maps are used by GLC, for instance, to determine
41  *  that the character code \e 65 corresponds to \e A. The character map of a
42  *  font can be modified by either adding new entries or changing the mapping
43  *  of the characters (see glcFontMap()).
44  *
45  *  GLC maintains two lists of fonts : \b GLC_FONT_LIST and
46  *  \b GLC_CURRENT_FONT_LIST. The former contains every font that have been
47  *  created with the commands glcNewFontFromFamily() and glcNewFontFromMaster()
48  *  and the later contains the fonts that GLC can use when it renders a
49  *  character (notice however that if \b GLC_AUTO_FONT is enabled, GLC may
50  *  automatically add new fonts from \b GLC_FONT_LIST to the
51  *  \b GLC_CURRENT_FONT_LIST ). Finally, it must be stressed that the order in
52  *  which the fonts are stored in the \b GLC_CURRENT_FONT_LIST matters : the
53  *  first font of the list should be considered as the main font with which
54  *  strings are rendered, while other fonts of this list should be seen as
55  *  fallback fonts (i.e. fonts that are used when the first font of
56  *  \b GLC_CURRENT_FONT_LIST does not map the character to render).
57  *
58  *  Most of the commands in this category have a parameter \e inFont. Unless
59  *  otherwise specified, these commands raise \b GLC_PARAMETER_ERROR if
60  *  \e inFont is less than zero or is greater than or equal to the value of
61  *  the variable \b GLC_FONT_COUNT.
62  */
63 
64 #include "internal.h"
65 
66 
67 
68 /* Most font commands need to check that :
69  *   1. The current thread owns a context state
70  *   2. The font identifier 'inFont' is legal
71  * This internal function does both checks and returns the pointer to the
72  * __GLCfont object that is identified by 'inFont' if the checks have succeeded
73  * otherwise returns NULL.
74  */
__glcVerifyFontParameters(GLint inFont)75 __GLCfont* __glcVerifyFontParameters(GLint inFont)
76 {
77   __GLCcontext *ctx = GLC_GET_CURRENT_CONTEXT();
78   FT_ListNode node = NULL;
79   __GLCfont *font = NULL;
80 
81   /* Check if the current thread owns a context state */
82   if (!ctx) {
83     __glcRaiseError(GLC_STATE_ERROR);
84     return NULL;
85   }
86 
87   /* Verify if the font identifier is in legal bounds */
88   for (node = ctx->fontList.head; node; node = node->next) {
89     font = (__GLCfont*)node->data;
90     if (font->id == inFont) break;
91   }
92 
93   if (!node) {
94     __glcRaiseError(GLC_PARAMETER_ERROR);
95     return NULL;
96   }
97 
98   /* Returns the __GLCfont object identified by inFont */
99   return font;
100 }
101 
102 
103 
104 /* Do the actual job of glcAppendFont(). This function can be called as an
105  * internal version of glcAppendFont() where the current GLC context is already
106  * determined and the font ID has been resolved in its corresponding __GLCfont
107  * object.
108  */
__glcAppendFont(__GLCcontext * inContext,__GLCfont * inFont)109 void __glcAppendFont(__GLCcontext* inContext, __GLCfont* inFont)
110 {
111   FT_ListNode node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
112 
113   if (!node) {
114     __glcRaiseError(GLC_RESOURCE_ERROR);
115     return;
116   }
117 
118 #ifndef GLC_FT_CACHE
119   if (!__glcFontOpen(inFont, inContext)) {
120     __glcFree(node);
121     return;
122   }
123 #endif
124 
125   /* Add the font to GLC_CURRENT_FONT_LIST */
126   node->data = inFont;
127   FT_List_Add(&inContext->currentFontList, node);
128 }
129 
130 
131 
132 /** \ingroup font
133  *  This command appends \e inFont to the list \b GLC_CURRENT_FONT_LIST.
134  *
135  *  The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element of
136  *  the list \b GLC_FONT_LIST or if \e inFont is an element in the list
137  *  \b GLC_CURRENT_FONT_LIST at the beginning of command execution.
138  *  \param inFont The ID of the font to append to the list
139  *                \b GLC_CURRENT_FONT_LIST
140  *  \sa glcGetListc() with argument \b GLC_CURRENT_FONT_LIST
141  *  \sa glcGeti() with argument \b GLC_CURRENT_FONT_COUNT
142  *  \sa glcFont()
143  *  \sa glcNewFontFromFamily()
144  *  \sa glcNewFontFromMaster()
145  */
glcAppendFont(GLint inFont)146 void APIENTRY glcAppendFont(GLint inFont)
147 {
148   __GLCcontext *ctx = NULL;
149   __GLCfont *font = NULL;
150 
151   GLC_INIT_THREAD();
152 
153   /* Verify that the thread has a current context and that the font identified
154    * by 'inFont' exists.
155    */
156   font = __glcVerifyFontParameters(inFont);
157   if (!font)
158     return;
159 
160   ctx = GLC_GET_CURRENT_CONTEXT();
161 
162   /* Check if inFont is already an element of GLC_CURRENT_FONT_LIST */
163   if (FT_List_Find(&ctx->currentFontList, font)) {
164     __glcRaiseError(GLC_PARAMETER_ERROR);
165     return;
166   }
167 
168   __glcAppendFont(ctx, font);
169 }
170 
171 
172 
173 /* This internal function must be called each time that a command destroys
174  * a font. __glcDeleteFont removes, if necessary, the font identified by
175  * inFont from the list GLC_CURRENT_FONT_LIST and then delete the font.
176  */
__glcDeleteFont(__GLCfont * font,__GLCcontext * inContext)177 static void __glcDeleteFont(__GLCfont* font, __GLCcontext* inContext)
178 {
179   FT_ListNode node = NULL;
180 
181   /* Look for the font into GLC_CURRENT_FONT_LIST */
182   node = FT_List_Find(&inContext->currentFontList, font);
183 
184   /* If the font has been found, remove it from the list */
185   if (node) {
186     FT_List_Remove(&inContext->currentFontList, node);
187 #ifndef GLC_FT_CACHE
188     __glcFontClose(font);
189 #endif
190     __glcFree(node);
191   }
192   __glcFontDestroy(font, inContext);
193 }
194 
195 
196 
197 /** \ingroup font
198  *  This command deletes the font identified by \e inFont. If \e inFont is an
199  *  element in the list \b GLC_CURRENT_FONT_LIST, the command removes that
200  *  element from the list. All information about the font is lost, and the
201  *  indice \e inFont become unused.
202  *
203  *  The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element of
204  *  the list \b GLC_FONT_LIST and if \e inFont has not been generated by
205  *  glcGenFontID().
206  *  \param inFont The ID of the font to delete
207  *  \sa glcGetListi() with argument \b GLC_FONT_LIST
208  *  \sa glcGeti() with argument \b GLC_FONT_COUNT
209  *  \sa glcIsFont()
210  *  \sa glcGenFontID()
211  *  \sa glcNewFontFromFamily()
212  *  \sa glcNewFontFromMaster()
213  */
glcDeleteFont(GLint inFont)214 void APIENTRY glcDeleteFont(GLint inFont)
215 {
216   __GLCcontext *ctx = NULL;
217   __GLCfont *font = NULL;
218   FT_ListNode node = NULL;
219 
220   GLC_INIT_THREAD();
221 
222   ctx = GLC_GET_CURRENT_CONTEXT();
223   if (!ctx) {
224     __glcRaiseError(GLC_STATE_ERROR);
225     return;
226   }
227 
228   /* Search the font to be deleted */
229   for (node = ctx->fontList.head; node; node = node->next) {
230     font = (__GLCfont*)node->data;
231     if (font->id == inFont) {
232       /* remove the font from the GLC_FONT_LIST then destroy it */
233       FT_List_Remove(&ctx->fontList, node);
234       break;
235     }
236   }
237 
238   if (!node) {
239     for (node = ctx->genFontList.head; node; node = node->next) {
240       font = (__GLCfont*)node->data;
241       if (font->id == inFont) {
242 	/* Remove the font from the empty font list generated by
243 	 * glcGenFontID().
244 	 */
245 	FT_List_Remove(&ctx->genFontList, node);
246 	break;
247       }
248     }
249 
250     if (!node) {
251       __glcRaiseError(GLC_PARAMETER_ERROR);
252       return;
253     }
254   }
255 
256   __glcFree(node);
257   __glcDeleteFont(font, ctx);
258 }
259 
260 
261 
262 #ifndef GLC_FT_CACHE
263 /* Function called by FT_List_Finalize
264  * Close the face of a font when GLC_CURRENT_FONT_LIST is deleted
265  */
__glcCloseFace(FT_Memory GLC_UNUSED_ARG (inMemory),void * data,void * GLC_UNUSED_ARG (user))266 static void __glcCloseFace(FT_Memory GLC_UNUSED_ARG(inMemory), void* data,
267 			   void* GLC_UNUSED_ARG(user))
268 {
269   __GLCfont* font = (__GLCfont*)data;
270 
271   assert(font);
272   __glcFontClose(font);
273 }
274 #endif
275 
276 
277 
278 /** \ingroup font
279  *  This command begins by removing all elements from the list
280  *  \b GLC_CURRENT_FONT_LIST. If \e inFont is nonzero, the command then appends
281  *  \e inFont to the list. Otherwise, the command does not raise an error and
282  *  the list remains empty.
283  *
284  *  The command raises \b GLC_PARAMETER_ERROR if \e inFont is nonzero and is
285  *  not an element of the list \b GLC_FONT_LIST.
286  *  \param inFont The ID of a font.
287  *  \sa glcGetListc() with argument \b GLC_CURRENT_FONT_LIST
288  *  \sa glcGeti() with argument \b GLC_CURRENT_FONT_COUNT
289  *  \sa glcAppendFont()
290  */
glcFont(GLint inFont)291 void APIENTRY glcFont(GLint inFont)
292 {
293   __GLCcontext *ctx = NULL;
294 
295   GLC_INIT_THREAD();
296 
297   /* Verify if the current thread owns a context state */
298   ctx = GLC_GET_CURRENT_CONTEXT();
299   if (!ctx) {
300     __glcRaiseError(GLC_STATE_ERROR);
301     return;
302   }
303 
304   if (inFont) {
305     FT_ListNode node = NULL;
306     __GLCfont *font = __glcVerifyFontParameters(inFont);
307 
308     /* Verify that the thread has a current context and that the font
309      * identified by 'inFont' exists.
310      */
311     if (!font) {
312       /* No need to raise an error since __glcVerifyFontParameters() already
313        * did it
314        */
315       return;
316     }
317 
318     /* Check if the font is already in GLC_CURRENT_FONT_LIST */
319     node = FT_List_Find(&ctx->currentFontList, font);
320     if (node) {
321       /* Remove the font from the list */
322       FT_List_Remove(&ctx->currentFontList, node);
323     }
324     else {
325 #ifndef GLC_FT_CACHE
326       if (!__glcFontOpen(font, ctx))
327 	return;
328 #endif
329 
330       /* Append the font identified by inFont to GLC_CURRENT_FONT_LIST */
331       node = ctx->currentFontList.head;
332       if (node) {
333         /* We keep the first node of the current font list in order not to need
334          * to create a new one to store the font identified by 'inFont'
335          */
336 #ifndef GLC_FT_CACHE
337         __GLCfont* dummyFont = (__GLCfont*)node->data;
338 
339         /* Close the face of the font stored in the first node */
340 	__glcFontClose(dummyFont);
341 #endif
342         /* Remove the first node of the list to prevent it to be deleted by
343          * FT_List_Finalize().
344          */
345         FT_List_Remove(&ctx->currentFontList, node);
346       }
347       else {
348         /* The list is empty, create a new node */
349         node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
350         if (!node) {
351 #ifndef GLC_FT_CACHE
352 	  __glcFontClose(font);
353 #endif
354           __glcRaiseError(GLC_RESOURCE_ERROR);
355           return;
356         }
357       }
358     }
359 
360 #ifndef GLC_FT_CACHE
361     /* Close the remaining fonts in GLC_CURRENT_FONT_LIST and empty the list */
362     FT_List_Finalize(&ctx->currentFontList, __glcCloseFace,
363 		     &__glcCommonArea.memoryManager, NULL);
364 #else
365     /* Empties GLC_CURRENT_FONT_LIST */
366     FT_List_Finalize(&ctx->currentFontList, NULL,
367 		     &__glcCommonArea.memoryManager, NULL);
368 #endif
369     /* Insert the updated node as the first and only node */
370     node->data = font;
371     FT_List_Add(&ctx->currentFontList, node);
372   }
373   else {
374     /* Empties the list GLC_CURRENT_FONT_LIST */
375 #ifndef GLC_FT_CACHE
376     FT_List_Finalize(&ctx->currentFontList, __glcCloseFace,
377                      &__glcCommonArea.memoryManager, NULL);
378 #else
379     FT_List_Finalize(&ctx->currentFontList, NULL,
380                      &__glcCommonArea.memoryManager, NULL);
381 #endif
382   }
383 }
384 
385 
386 
387 /** \ingroup font
388  *  This command attempts to set the current face of the font identified by
389  *  \e inFont to the face identified by the string \e inFace. Examples for
390  *  font faces are strings like <tt>"Normal"</tt>, <tt>"Bold"</tt> or
391  *  <tt>"Bold Italic"</tt>. In contrast to some systems that have a different
392  *  font for each face, GLC allows you to have the face be an attribute of
393  *  the font.
394  *
395  *  If \e inFace is not an element of the font's string list attribute
396  *  \b GLC_FACE_LIST, the command leaves the font's current face unchanged and
397  *  returns \b GL_FALSE. If the command succeeds, it returns \b GL_TRUE.
398  *
399  *  If \e inFont is zero, the command iterates over the
400  *  \b GLC_CURRENT_FONT_LIST. For each of the fonts named therein, the command
401  *  attempts to set the font's current face to the face in that font that is
402  *  identified by \e inFace. In this case, the command returns \b GL_TRUE if
403  *  \b GLC_CURRENT_FONT_LIST contains one or more elements and the command
404  *  successfully sets the current face of each of the fonts named in the list.
405  *
406  *  The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element in
407  *  the list \b GLC_FONT_LIST.
408  *  \param inFont The ID of the font to be changed
409  *  \param inFace The face for \e inFont
410  *  \return \b GL_TRUE if the command succeeded to set the face \e inFace
411  *          to the font \e inFont. \b GL_FALSE is returned otherwise.
412  *  \sa glcGetFontFace()
413  */
glcFontFace(GLint inFont,const GLCchar * inFace)414 GLboolean APIENTRY glcFontFace(GLint inFont, const GLCchar* inFace)
415 {
416   __GLCcontext *ctx = NULL;
417   GLCchar8* UinFace = NULL;
418   __GLCfont* font = NULL;
419 
420   GLC_INIT_THREAD();
421 
422   assert(inFace);
423 
424   /* Check if the current thread owns a context state */
425   ctx = GLC_GET_CURRENT_CONTEXT();
426   if (!ctx) {
427     __glcRaiseError(GLC_STATE_ERROR);
428     return GL_FALSE;
429   }
430 
431   UinFace = __glcConvertToUtf8(inFace, ctx->stringState.stringType);
432   if (!UinFace)
433     return GL_FALSE;
434 
435   if (inFont) {
436     GLboolean result = GL_FALSE;
437 
438     /* Check if the current thread owns a context state
439      * and if the font identified by inFont exists
440      */
441     font = __glcVerifyFontParameters(inFont);
442     if (!font) {
443       __glcFree(UinFace);
444       return GL_FALSE;
445     }
446 
447     /* Open the new face */
448     result = __glcFontFace(font, UinFace, ctx);
449     __glcFree(UinFace);
450     return result;
451   }
452   else {
453     FT_ListNode node = NULL;
454 
455     if (!ctx->currentFontList.head) {
456       __glcFree(UinFace);
457       return GL_FALSE;
458     }
459 
460     /* Check that every font of GLC_CURRENT_FONT_LIST has a face identified
461      * by UinFace.
462      */
463     for (node = ctx->currentFontList.head; node; node = node->next) {
464       __GLCmaster* master = NULL;
465       __GLCfaceDescriptor* faceDesc = NULL;
466 
467       font = (__GLCfont*)node->data;
468       master = __glcMasterCreate(font->parentMasterID, ctx);
469       assert(master);
470 
471       /* Get the face descriptor of the face identified by the string inFace */
472       faceDesc = __glcFaceDescCreate(master, UinFace, ctx, 0);
473       __glcMasterDestroy(master);
474       if (!faceDesc) {
475 	/* No face identified by UinFace has been found in the font */
476 	__glcFree(UinFace);
477 	return GL_FALSE;
478       }
479 
480       __glcFaceDescDestroy(faceDesc, ctx);
481     }
482 
483     /* Set the current face of every font of GLC_CURRENT_FONT_LIST to the face
484      * identified by UinFace.
485      */
486     for (node = ctx->currentFontList.head; node; node = node->next)
487       __glcFontFace((__GLCfont*)node->data, UinFace, ctx);
488 
489     __glcFree(UinFace);
490     return GL_TRUE;
491   }
492 }
493 
494 
495 
496 /** \ingroup font
497  *  This command modifies the character map of the font identified by \e inFont
498  *  such that the font maps \e inCode to the character whose name is the string
499  *  \e inCharName. If \e inCharName is \b GLC_NONE, \e inCode is removed from
500  *  the character map.
501  *
502  *  The command raises \b GLC_PARAMETER_ERROR if \e inCharName is not
503  *  \b GLC_NONE or an element of the font string's list attribute
504  *  \b GLC_CHAR_LIST.
505  *  \param inFont The ID of the font
506  *  \param inCode The integer ID of a character
507  *  \param inCharName The string name of a character
508  *  \sa glcGetFontMap()
509  */
glcFontMap(GLint inFont,GLint inCode,const GLCchar * inCharName)510 void APIENTRY glcFontMap(GLint inFont, GLint inCode, const GLCchar* inCharName)
511 {
512   __GLCfont *font = NULL;
513   GLint code = 0;
514   __GLCcontext* ctx = NULL;
515 
516   GLC_INIT_THREAD();
517 
518   /* Check if the font parameters are valid */
519   font = __glcVerifyFontParameters(inFont);
520   if (!font)
521     return;
522 
523   ctx = GLC_GET_CURRENT_CONTEXT();
524 
525   /* Get the character code converted to the UCS-4 format */
526   code = __glcConvertGLintToUcs4(ctx, inCode);
527   if (code < 0)
528     return;
529 
530   if (!inCharName)
531     /* Remove the character from the map */
532     __glcCharMapRemoveChar(font->charMap, code);
533   else {
534     GLCchar8* buffer = NULL;
535     GLCulong mappedCode  = 0;
536     __GLCglyph* glyph = NULL;
537     GLint error = 0;
538 
539     /* Convert the character name identified by inCharName into UTF-8 format.
540      * The result is stored into 'buffer'.
541      */
542     buffer = __glcConvertToUtf8(inCharName, ctx->stringState.stringType);
543     if (!buffer)
544       return;
545 
546     /* Retrieve the Unicode code from its name */
547     error = __glcCodeFromName(buffer);
548     if (error < 0) {
549       __glcFree(buffer);
550       return;
551     }
552     mappedCode = (GLCulong)error;
553 
554     /* Get the glyph that corresponds to the mapped code */
555     glyph = __glcFaceDescGetGlyph(font->faceDesc, mappedCode, ctx);
556     if (!glyph) {
557       __glcFree(buffer);
558       return;
559     }
560     /* Add the character and its corresponding glyph to the character map */
561     __glcCharMapAddChar(font->charMap, inCode, glyph);
562     __glcFree(buffer);
563   }
564 }
565 
566 
567 
568 /** \ingroup font
569  *  This command returns a font ID that is not an element of the list
570  *  \b GLC_FONT_LIST. This command has also the effect of creating an empty
571  *  font for the returned ID so that this ID become used.
572  *  \return A new font ID
573  *  \sa glcDeleteFont()
574  *  \sa glcIsFont()
575  *  \sa glcNewFontFromFamily()
576  *  \sa glcNewFontFromMaster()
577  */
glcGenFontID(void)578 GLint APIENTRY glcGenFontID(void)
579 {
580   __GLCcontext *ctx = NULL;
581   FT_ListNode node = NULL;
582   __GLCfont* font = NULL;
583   GLint id = 1;
584 
585   GLC_INIT_THREAD();
586 
587   /* Verify if the current thread owns a context state */
588   ctx = GLC_GET_CURRENT_CONTEXT();
589   if (!ctx) {
590     __glcRaiseError(GLC_STATE_ERROR);
591     return 0;
592   }
593 
594   /* Look for an ID which is not associated to an existing font */
595   for (id = 1; id <= 0x7fffffff; id++) {
596     /* Check against fonts stored in GLC_FONT_LIST */
597     for (node = ctx->fontList.head; node; node = node->next) {
598       font = (__GLCfont*)node->data;
599 
600       if (font->id == id)
601 	break;
602     }
603 
604     /* A font in GLC_FONT_LIST has already the current ID, check for next ID */
605     if (node)
606       continue;
607 
608     /* Check against fonts already generated by glcGenFontID() but not yet
609      * associated to a font of GLC_FONT_LIST.
610      */
611     for (node = ctx->genFontList.head; node; node = node->next) {
612       font = (__GLCfont*)node->data;
613 
614       if (font->id == id)
615 	break;
616     }
617 
618     /* If the current ID is not associated then exit*/
619     if (!node)
620       break;
621   }
622 
623   /* If we have scanned all possible ID values and failed to find one which is
624    * not yet associated (which is very unlikely) then exit with an error.
625    */
626   if (node) {
627     __glcRaiseError(GLC_RESOURCE_ERROR);
628     return 0;
629   }
630 
631   /* Create an empty font */
632   node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
633   if (!node) {
634     __glcRaiseError(GLC_RESOURCE_ERROR);
635     return 0;
636   }
637 
638   /* Create an empty font */
639   font = __glcFontCreate(id, NULL, ctx, 0);
640   if (!font) {
641     __glcFree(node);
642     return 0;
643   }
644 
645   node->data = font;
646   FT_List_Add(&ctx->genFontList, node);
647 
648   return id;
649 }
650 
651 
652 
653 /** \ingroup font
654  *  This command returns the string name of the current face of the font
655  *  identified by \e inFont.
656  *  \param inFont The font ID
657  *  \return The string name of the font \e inFont
658  *  \sa glcFontFace()
659  */
glcGetFontFace(GLint inFont)660 const GLCchar* APIENTRY glcGetFontFace(GLint inFont)
661 {
662   __GLCfont *font = NULL;
663 
664   GLC_INIT_THREAD();
665 
666   font = __glcVerifyFontParameters(inFont);
667   if (font) {
668     GLCchar *buffer = NULL;
669     __GLCcontext *ctx = GLC_GET_CURRENT_CONTEXT();
670 
671     /* Convert the string name of the face into the current string type */
672     buffer = __glcConvertFromUtf8ToBuffer(ctx, __glcFaceDescGetStyleName(font->faceDesc),
673 					  ctx->stringState.stringType);
674     if (!buffer)
675       return GLC_NONE;
676 
677     /* returns the name */
678     return buffer;
679   }
680   else
681     return GLC_NONE;
682 }
683 
684 
685 
686 /** \ingroup font
687  *  This command returns an attribute of the font identified by \e inFont that
688  *  is a string from a string list identified by \e inAttrib. The command
689  *  returns the string at offset \e inIndex from the first element in \e
690  *  inAttrib. For example, if \e inFont has a face list (\c Regular, \c Bold,
691  *  \c Italic ) and \e inIndex is \c 2, then the command returns \c Italic if
692  *  you query \b GLC_FACE_LIST.
693  *
694  *  Every GLC state variable that is a list has an associated integer element
695  *  count whose value is the number of elements in the list.
696  *
697  *  Below are the string list attributes associated with each GLC master and
698  *  font and their element count attributes :
699  * <center>
700  * <table>
701  * <caption>Master/font string list attributes</caption>
702  *   <tr>
703  *     <td>Name</td> <td>Enumerant</td> <td>Element count attribute</td>
704  *   </tr>
705  *   <tr>
706  *     <td><b>GLC_CHAR_LIST</b></td>
707  *     <td>0x0050</td>
708  *     <td><b>GLC_CHAR_COUNT</b></td>
709  *   </tr>
710  *   <tr>
711  *     <td><b>GLC_FACE_LIST</b></td>
712  *     <td>0x0051</td>
713  *     <td><b>GLC_FACE_COUNT</b></td>
714  *   </tr>
715  * </table>
716  * </center>
717  *  \n The command raises \b GLC_PARAMETER_ERROR if \e inIndex is less than
718  *  zero or is greater than or equal to the value of the list element count
719  *  attribute.
720  *  \param inFont The font ID
721  *  \param inAttrib The string list from which a string is requested
722  *  \param inIndex The offset from the first element of the list associated
723  *                 with \e inAttrib
724  *  \return A string attribute of \e inFont identified by \e inAttrib
725  *  \sa glcGetMasterListc()
726  *  \sa glcGetFontc()
727  *  \sa glcGetFonti()
728  */
glcGetFontListc(GLint inFont,GLCenum inAttrib,GLint inIndex)729 const GLCchar* APIENTRY glcGetFontListc(GLint inFont, GLCenum inAttrib,
730 					GLint inIndex)
731 {
732   __GLCfont* font = NULL;
733   __GLCcontext* ctx = NULL;
734   const GLCchar8* name = NULL;
735 
736   GLC_INIT_THREAD();
737 
738   /* Check if the font parameters are valid */
739   font = __glcVerifyFontParameters(inFont);
740   if (!font)
741     return NULL;
742 
743   ctx = GLC_GET_CURRENT_CONTEXT();
744 
745   switch(inAttrib) {
746   case GLC_FACE_LIST:
747     return glcGetMasterListc(font->parentMasterID, inAttrib, inIndex);
748   case GLC_CHAR_LIST:
749     name = __glcCharMapGetCharNameByIndex(font->charMap, inIndex);
750     if (!name)
751       return NULL;
752 
753     return __glcConvertFromUtf8ToBuffer(ctx, name,
754 					ctx->stringState.stringType);
755   default:
756     __glcRaiseError(GLC_PARAMETER_ERROR);
757     return NULL;
758   }
759 }
760 
761 
762 
763 /** \ingroup font
764  *  This command returns the string name of the character that the font
765  *  identified by \e inFont maps \e inCode to.
766  *
767  *  To change the map, that is, associate a different name string with the
768  *  integer ID of a font, use glcFontMap().
769  *
770  *  If \e inCode cannot be mapped in the font, the command returns \b GLC_NONE.
771  *
772  *  The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element of
773  *  the list \b GLC_FONT_LIST
774  *  \note Changing the map of a font is possible but changing the map of a
775  *        master is not.
776  *  \param inFont The integer ID of the font from which to select the character
777  *  \param inCode The integer ID of the character in the font map
778  *  \return The string name of the character that the font \e inFont maps
779  *          \e inCode to.
780  *  \sa glcGetMasterMap()
781  *  \sa glcFontMap()
782  */
glcGetFontMap(GLint inFont,GLint inCode)783 const GLCchar* APIENTRY glcGetFontMap(GLint inFont, GLint inCode)
784 {
785   __GLCfont *font = NULL;
786   __GLCcontext *ctx = NULL;
787   GLint code = 0;
788   const GLCchar8* name = NULL;
789 
790   GLC_INIT_THREAD();
791 
792   /* Check if the font parameters are valid */
793   font = __glcVerifyFontParameters(inFont);
794   if (!font)
795     return NULL;
796 
797   ctx = GLC_GET_CURRENT_CONTEXT();
798 
799   /* Get the character code converted to the UCS-4 format */
800   code = __glcConvertGLintToUcs4(ctx, inCode);
801   if (code < 0)
802     return NULL;
803 
804   name = __glcCharMapGetCharName(font->charMap, code);
805   if (!name)
806     return NULL;
807 
808   return __glcConvertFromUtf8ToBuffer(ctx, name, ctx->stringState.stringType);
809 }
810 
811 
812 
813 /** \ingroup font
814  *  This command returns a string attribute of the font identified by
815  *  \e inFont. The table below lists the string attributes that are
816  *  associated with each GLC master and font.
817  *  <center>
818  *  <table>
819  *  <caption>Master/font string attributes</caption>
820  *    <tr>
821  *      <td>Name</td> <td>Enumerant</td>
822  *    </tr>
823  *    <tr>
824  *      <td><b>GLC_FAMILY</b></td> <td>0x0060</td>
825  *    </tr>
826  *    <tr>
827  *      <td><b>GLC_MASTER_FORMAT</b></td> <td>0x0061</td>
828  *    </tr>
829  *    <tr>
830  *      <td><b>GLC_VENDOR</b></td> <td>0x0062</td>
831  *    </tr>
832  *    <tr>
833  *      <td><b>GLC_VERSION</b></td> <td>0x0063</td>
834  *    </tr>
835  *    <tr>
836  *      <td><b>GLC_FULL_NAME_SGI</b></td> <td>0x8002</td>
837  *    </tr>
838  *  </table>
839  *  </center>
840  *  \param inFont The font for which the attribute is requested
841  *  \param inAttrib The requested string attribute
842  *  \return The string attribute \e inAttrib of the font \e inFont
843  *  \sa glcGetMasterc()
844  *  \sa glcGetFonti()
845  *  \sa glcGetFontListc()
846  */
glcGetFontc(GLint inFont,GLCenum inAttrib)847 const GLCchar* APIENTRY glcGetFontc(GLint inFont, GLCenum inAttrib)
848 {
849   __GLCfont *font = NULL;
850 
851   GLC_INIT_THREAD();
852 
853   /* Check if the font parameters are valid */
854   font = __glcVerifyFontParameters(inFont);
855   if (font)
856     /* Those are master attributes so we call the equivalent master function */
857     return glcGetMasterc(font->parentMasterID, inAttrib);
858   else
859     return GLC_NONE;
860 }
861 
862 
863 
864 /** \ingroup font
865  *  This command returns an integer attribute of the font identified by
866  *  \e inFont. The attribute is identified by \e inAttrib. The table below
867  *  lists the integer attributes that are associated with each GLC master
868  *  and font.
869  *  <center>
870  *  <table>
871  *  <caption>Master/font integer attributes</caption>
872  *    <tr>
873  *      <td>Name</td> <td>Enumerant</td>
874  *    </tr>
875  *    <tr>
876  *      <td><b>GLC_CHAR_COUNT</b></td> <td>0x0070</td>
877  *    </tr>
878  *    <tr>
879  *      <td><b>GLC_FACE_COUNT</b></td> <td>0x0071</td>
880  *    </tr>
881  *    <tr>
882  *      <td><b>GLC_IS_FIXED_PITCH</b></td> <td>0x0072</td>
883  *    </tr>
884  *    <tr>
885  *      <td><b>GLC_MAX_MAPPED_CODE</b></td> <td>0x0073</td>
886  *    </tr>
887  *    <tr>
888  *      <td><b>GLC_MIN_MAPPED_CODE</b></td> <td>0x0074</td>
889  *    </tr>
890  *  </table>
891  *  </center>
892  *  \param inFont The font for which the attribute is requested.
893  *  \param inAttrib The requested integer attribute
894  *  \return The value of the specified integer attribute
895  *  \sa glcGetMasteri()
896  *  \sa glcGetFontc()
897  *  \sa glcGetFontListc()
898  */
glcGetFonti(GLint inFont,GLCenum inAttrib)899 GLint APIENTRY glcGetFonti(GLint inFont, GLCenum inAttrib)
900 {
901   __GLCfont *font = NULL;
902 
903   GLC_INIT_THREAD();
904 
905   /* Check if the font parameters are valid */
906   font = __glcVerifyFontParameters(inFont);
907   if (!font)
908     return 0;
909 
910   switch(inAttrib) {
911   case GLC_CHAR_COUNT:
912     return __glcCharMapGetCount(font->charMap);
913   case GLC_IS_FIXED_PITCH:
914     return __glcFaceDescIsFixedPitch(font->faceDesc);
915   case GLC_MAX_MAPPED_CODE:
916     return __glcCharMapGetMaxMappedCode(font->charMap);
917   case GLC_MIN_MAPPED_CODE:
918     return __glcCharMapGetMinMappedCode(font->charMap);
919   case GLC_FACE_COUNT:
920     return glcGetMasteri(font->parentMasterID, inAttrib);
921   default:
922     __glcRaiseError(GLC_PARAMETER_ERROR);
923     return GLC_NONE;
924   }
925 }
926 
927 
928 
929 /** \ingroup font
930  *  This command returns \b GL_TRUE if \e inFont is the ID of a font. If
931  *  \e inFont is not the ID of a font, the command does not raise an error.
932  *  \param inFont The element to be tested
933  *  \return \b GL_TRUE if \e inFont is the ID of a font, \b GL_FALSE
934  *          otherwise.
935  *  \sa glcGenFontID()
936  *  \sa glcNewFontFromFamily()
937  *  \sa glcNewFontFromMaster()
938  */
glcIsFont(GLint inFont)939 GLboolean APIENTRY glcIsFont(GLint inFont)
940 {
941   __GLCcontext *ctx = NULL;
942   FT_ListNode node = NULL;
943 
944   GLC_INIT_THREAD();
945 
946   /* Check if the current thread owns a context state */
947   ctx = GLC_GET_CURRENT_CONTEXT();
948   if (!ctx) {
949     __glcRaiseError(GLC_STATE_ERROR);
950     return GL_FALSE;
951   }
952 
953   /* Verify if the font identifier exists */
954   for (node = ctx->fontList.head; node; node = node->next) {
955     __GLCfont *font = (__GLCfont*)node->data;
956     if (font->id == inFont)
957       return GL_TRUE;
958   }
959 
960   /* If the ID corresponds to an empty font reserved by glcGenFontID() then
961    * return GL_TRUE in order to identify the ID as reserved.
962    */
963   for (node = ctx->genFontList.head; node; node = node->next) {
964     __GLCfont* font = (__GLCfont*)node->data;
965     if (font->id == inFont)
966       return GL_TRUE;
967   }
968 
969   return GL_FALSE;
970 }
971 
972 
973 
974 /* This internal function deletes the font identified by inFont (if any) and
975  * creates a new font based on the pattern 'inPattern'. The resulting font is
976  * added to the list GLC_FONT_LIST.
977  */
__glcNewFontFromMaster(GLint inFontID,__GLCmaster * inMaster,__GLCcontext * inContext,GLint inCode)978 __GLCfont* __glcNewFontFromMaster(GLint inFontID, __GLCmaster* inMaster,
979 				  __GLCcontext *inContext, GLint inCode)
980 {
981   FT_ListNode node = NULL;
982   __GLCfont* font = NULL;
983 
984   /* Look for the font which ID is inFont in the GLC_FONT_LIST */
985   for (node = inContext->fontList.head; node; node = node->next) {
986     font = (__GLCfont*)node->data;
987     if (font->id == inFontID) {
988       FT_List_Remove(&inContext->fontList, node);
989       break;
990     }
991   }
992 
993   if (!node) {
994     /* Look if the ID is in the empty fonts generated by glcGenFontID() */
995     for (node = inContext->genFontList.head; node; node = node->next) {
996       font = (__GLCfont*)node->data;
997       if (font->id == inFontID) {
998 	FT_List_Remove(&inContext->genFontList, node);
999 	break;
1000       }
1001     }
1002   }
1003 
1004   if (node)
1005     __glcDeleteFont(font, inContext);
1006   else {
1007     /* Create a new entry for GLC_FONT_LIST */
1008     node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
1009     if (!node) {
1010       __glcRaiseError(GLC_RESOURCE_ERROR);
1011       return NULL;
1012     }
1013   }
1014 
1015   /* Create a new font and add it to the list GLC_FONT_LIST */
1016   font = __glcFontCreate(inFontID, inMaster, inContext, inCode);
1017   if (!font) {
1018     __glcFree(node);
1019     return NULL;
1020   }
1021   node->data = font;
1022   FT_List_Add(&inContext->fontList, node);
1023 
1024   return font;
1025 }
1026 
1027 
1028 
1029 /** \ingroup font
1030  *  This command creates a new font from the master identified by \e inMaster.
1031  *  The ID of the new font is \e inFont. If the command succeeds, it returns
1032  *  \e inFont. If \e inFont is the ID of a font at the beginning of command
1033  *  execution, the command executes the command \c glcDeleteFont(inFont) before
1034  *  creating the new font.
1035  *  \param inFont The ID of the new font
1036  *  \param inMaster The master from which to create the new font
1037  *  \return The ID of the new font if the command succceeds, \c 0 otherwise.
1038  *  \sa glcGetListi() with argument \b GLC_FONT_LIST
1039  *  \sa glcGeti() with argument \b GLC_FONT_COUNT
1040  *  \sa glcIsFont()
1041  *  \sa glcGenFontID()
1042  *  \sa glcNewFontFromFamily()
1043  *  \sa glcDeleteFont()
1044  */
glcNewFontFromMaster(GLint inFont,GLint inMaster)1045 GLint APIENTRY glcNewFontFromMaster(GLint inFont, GLint inMaster)
1046 {
1047   __GLCcontext *ctx = NULL;
1048   __GLCmaster *master = NULL;
1049   __GLCfont *font = NULL;
1050 
1051   GLC_INIT_THREAD();
1052 
1053   /* Check if inFont is in legal bounds */
1054   if (inFont < 1) {
1055     __glcRaiseError(GLC_PARAMETER_ERROR);
1056     return 0;
1057   }
1058 
1059   /* Verify that the thread has a current context and that the master
1060    * identified by 'inMaster' exists.
1061    */
1062   master = __glcVerifyMasterParameters(inMaster);
1063   if (!master)
1064     return 0;
1065 
1066   ctx = GLC_GET_CURRENT_CONTEXT();
1067 
1068   /* Create and return the new font */
1069   font = __glcNewFontFromMaster(inFont, master, ctx, 0);
1070   __glcMasterDestroy(master);
1071   return font->id;
1072 }
1073 
1074 
1075 
1076 /** \ingroup font
1077  *  This command performs a sequential search beginning with the first element
1078  *  of the GLC master list, looking for the first master whose string
1079  *  attribute \b GLC_FAMILY equals \e inFamily. If there is no such master the
1080  *  command returns zero. Otherwise, the command creates a new font from the
1081  *  master. The ID of the new font is \e inFont.
1082  *
1083  *  If the command succeeds, it returns \e inFont. If \e inFont is the ID of a
1084  *  font at the beginning of command execution, the command executes the
1085  *  command \c glcDeleteFont(inFont) before creating the new font.
1086  *  \param inFont The ID of the new font.
1087  *  \param inFamily The font family, that is, the string that \b GLC_FAMILY
1088  *                  attribute has to match.
1089  *  \return The ID of the new font if the command succeeds, \c 0 otherwise.
1090  *  \sa glcGetListi() with argument \b GLC_FONT_LIST
1091  *  \sa glcGeti() with argument \b GLC_FONT_COUNT
1092  *  \sa glcIsFont()
1093  *  \sa glcGenFontID()
1094  *  \sa glcNewFontFromMaster()
1095  *  \sa glcDeleteFont()
1096  */
glcNewFontFromFamily(GLint inFont,const GLCchar * inFamily)1097 GLint APIENTRY glcNewFontFromFamily(GLint inFont, const GLCchar* inFamily)
1098 {
1099   __GLCcontext *ctx = NULL;
1100   GLCchar8* UinFamily = NULL;
1101   __GLCmaster* master = NULL;
1102   __GLCfont *font = NULL;
1103 
1104   GLC_INIT_THREAD();
1105 
1106   assert(inFamily);
1107 
1108   /* Check if inFont is in legal bounds */
1109   if (inFont < 1) {
1110     __glcRaiseError(GLC_PARAMETER_ERROR);
1111     return 0;
1112   }
1113 
1114   /* Verify if the current thread owns a context state */
1115   ctx = GLC_GET_CURRENT_CONTEXT();
1116   if (!ctx) {
1117     __glcRaiseError(GLC_STATE_ERROR);
1118     return 0;
1119   }
1120 
1121   /* Convert the family name in UTF-8 encoding */
1122   UinFamily = __glcConvertToUtf8(inFamily, ctx->stringState.stringType);
1123   if (!UinFamily)
1124     return 0;
1125 
1126   master = __glcMasterFromFamily(ctx, UinFamily);
1127 
1128   __glcFree(UinFamily);
1129   if (!master)
1130     return 0;
1131 
1132   /* Create and return the new font */
1133   font = __glcNewFontFromMaster(inFont, master, ctx, 0);
1134   __glcMasterDestroy(master);
1135   return font->id;
1136 }
1137