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