warzone2100/3rdparty/quesoglc/font.c

1120 lines
32 KiB
C

/* QuesoGLC
* A free implementation of the OpenGL Character Renderer (GLC)
* Copyright (c) 2002, 2004-2009, Bertrand Coconnier
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id$ */
/** \file
* defines the so-called "Font commands" described in chapter 3.7 of the GLC
* specs.
*/
/** \defgroup font Font commands
* Commands to create, manage and destroy fonts.
*
* A font is a stylistically consistent set of glyphs that can be used to
* render some set of characters. Each font has a family name (for example
* Palatino) and a state variable that selects one of the faces (for
* example Regular, Bold, Italic, BoldItalic) that the font contains. A
* typeface is the combination of a family and a face (for example
* Palatino Bold).
*
* A font is an instantiation of a master for a given face.
*
* Every font has an associated character map. A character map is a table of
* entries that maps integer values to the name string that identifies the
* characters. The character maps are used by GLC, for instance, to determine
* that the character code \e 65 corresponds to \e A. The character map of a
* font can be modified by either adding new entries or changing the mapping
* of the characters (see glcFontMap()).
*
* GLC maintains two lists of fonts : \b GLC_FONT_LIST and
* \b GLC_CURRENT_FONT_LIST. The former contains every font that have been
* created with the commands glcNewFontFromFamily() and glcNewFontFromMaster()
* and the later contains the fonts that GLC can use when it renders a
* character (notice however that if \b GLC_AUTO_FONT is enabled, GLC may
* automatically add new fonts from \b GLC_FONT_LIST to the
* \b GLC_CURRENT_FONT_LIST ). Finally, it must be stressed that the order in
* which the fonts are stored in the \b GLC_CURRENT_FONT_LIST matters : the
* first font of the list should be considered as the main font with which
* strings are rendered, while other fonts of this list should be seen as
* fallback fonts (i.e. fonts that are used when the first font of
* \b GLC_CURRENT_FONT_LIST does not map the character to render).
*
* Most of the commands in this category have a parameter \e inFont. Unless
* otherwise specified, these commands raise \b GLC_PARAMETER_ERROR if
* \e inFont is less than zero or is greater than or equal to the value of
* the variable \b GLC_FONT_COUNT.
*/
#include "internal.h"
/* Most font commands need to check that :
* 1. The current thread owns a context state
* 2. The font identifier 'inFont' is legal
* This internal function does both checks and returns the pointer to the
* __GLCfont object that is identified by 'inFont' if the checks have succeeded
* otherwise returns NULL.
*/
__GLCfont* __glcVerifyFontParameters(const GLint inFont)
{
FT_ListNode node = NULL;
__GLCfont *font = NULL;
__GLCcontext *ctx = GLC_GET_CURRENT_CONTEXT();
/* Check if the current thread owns a context state */
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return NULL;
}
/* Verify if the font identifier is in legal bounds */
for (node = ctx->fontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == inFont) break;
}
if (!node) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
/* Returns the __GLCfont object identified by inFont */
return font;
}
/* Do the actual job of glcAppendFont(). This function can be called as an
* internal version of glcAppendFont() where the current GLC context is already
* determined and the font ID has been resolved in its corresponding __GLCfont
* object.
*/
void __glcAppendFont(__GLCcontext* inContext, __GLCfont* inFont)
{
FT_ListNode node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
if (!node) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
#ifndef GLC_FT_CACHE
if (!__glcFontOpen(inFont, inContext)) {
__glcFree(node);
return;
}
#endif
/* Add the font to GLC_CURRENT_FONT_LIST */
node->data = inFont;
FT_List_Add(&inContext->currentFontList, node);
}
/** \ingroup font
* This command appends \e inFont to the list \b GLC_CURRENT_FONT_LIST.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element of
* the list \b GLC_FONT_LIST or if \e inFont is an element in the list
* \b GLC_CURRENT_FONT_LIST at the beginning of command execution.
* \param inFont The ID of the font to append to the list
* \b GLC_CURRENT_FONT_LIST
* \sa glcGetListc() with argument \b GLC_CURRENT_FONT_LIST
* \sa glcGeti() with argument \b GLC_CURRENT_FONT_COUNT
* \sa glcFont()
* \sa glcNewFontFromFamily()
* \sa glcNewFontFromMaster()
*/
void APIENTRY glcAppendFont(GLint inFont)
{
__GLCcontext *ctx = NULL;
__GLCfont *font = NULL;
GLC_INIT_THREAD();
/* Verify that the thread has a current context and that the font identified
* by 'inFont' exists.
*/
font = __glcVerifyFontParameters(inFont);
if (!font)
return;
ctx = GLC_GET_CURRENT_CONTEXT();
/* Check if inFont is already an element of GLC_CURRENT_FONT_LIST */
if (FT_List_Find(&ctx->currentFontList, font)) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
__glcAppendFont(ctx, font);
}
/** \ingroup font
* This command deletes the font identified by \e inFont. If \e inFont is an
* element in the list \b GLC_CURRENT_FONT_LIST, the command removes that
* element from the list. All information about the font is lost, and the
* indice \e inFont become unused.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element of
* the list \b GLC_FONT_LIST and if \e inFont has not been generated by
* glcGenFontID().
* \param inFont The ID of the font to delete
* \sa glcGetListi() with argument \b GLC_FONT_LIST
* \sa glcGeti() with argument \b GLC_FONT_COUNT
* \sa glcIsFont()
* \sa glcGenFontID()
* \sa glcNewFontFromFamily()
* \sa glcNewFontFromMaster()
*/
void APIENTRY glcDeleteFont(GLint inFont)
{
__GLCcontext *ctx = NULL;
__GLCfont *font = NULL;
FT_ListNode node = NULL;
GLC_INIT_THREAD();
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
/* Search the font to be deleted */
for (node = ctx->fontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == inFont) {
/* remove the font from the GLC_FONT_LIST then destroy it */
FT_List_Remove(&ctx->fontList, node);
break;
}
}
if (!node) {
/* The font is not an element of GLC_FONT_LIST then check if its ID has been
* generated by glcGenFontID() but has never been used.
*/
for (node = ctx->genFontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == inFont) {
/* Remove the font from the empty font list generated by
* glcGenFontID().
*/
FT_List_Remove(&ctx->genFontList, node);
break;
}
}
/* The font does not exist */
if (!node) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return;
}
}
__glcFree(node);
__glcContextDeleteFont(ctx, font);
}
#ifndef GLC_FT_CACHE
/* Function called by FT_List_Finalize
* Close the face of a font when GLC_CURRENT_FONT_LIST is deleted
*/
static void __glcCloseFace(FT_Memory GLC_UNUSED_ARG(inMemory), void* data,
void* GLC_UNUSED_ARG(user))
{
__GLCfont* font = (__GLCfont*)data;
assert(font);
__glcFontClose(font);
}
#endif
/** \ingroup font
* This command begins by removing all elements from the list
* \b GLC_CURRENT_FONT_LIST. If \e inFont is nonzero, the command then appends
* \e inFont to the list. Otherwise, the command does not raise an error and
* the list remains empty.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inFont is nonzero and is
* not an element of the list \b GLC_FONT_LIST.
* \param inFont The ID of a font.
* \sa glcGetListc() with argument \b GLC_CURRENT_FONT_LIST
* \sa glcGeti() with argument \b GLC_CURRENT_FONT_COUNT
* \sa glcAppendFont()
*/
void APIENTRY glcFont(GLint inFont)
{
__GLCcontext *ctx = NULL;
FT_ListNode node = NULL;
__GLCfont *font = NULL;
GLC_INIT_THREAD();
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return;
}
if (inFont) {
font = __glcVerifyFontParameters(inFont);
/* Verify that the thread has a current context and that the font
* identified by 'inFont' exists.
*/
if (!font) {
/* No need to raise an error since __glcVerifyFontParameters() already
* did it
*/
return;
}
/* Check if the font is already in GLC_CURRENT_FONT_LIST */
node = FT_List_Find(&ctx->currentFontList, font);
if (node) {
/* Remove the font from the list */
FT_List_Remove(&ctx->currentFontList, node);
}
else {
#ifndef GLC_FT_CACHE
if (!__glcFontOpen(font, ctx))
return;
#endif
/* Append the font identified by inFont to GLC_CURRENT_FONT_LIST */
node = ctx->currentFontList.head;
if (node) {
/* We keep the first node of the current font list in order not to need
* to create a new one to store the font identified by 'inFont'
*/
#ifndef GLC_FT_CACHE
__GLCfont* dummyFont = (__GLCfont*)node->data;
/* Close the face of the font stored in the first node */
__glcFontClose(dummyFont);
#endif
/* Remove the first node of the list to prevent it to be deleted by
* FT_List_Finalize().
*/
FT_List_Remove(&ctx->currentFontList, node);
}
else {
/* The list is empty, create a new node */
node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
if (!node) {
#ifndef GLC_FT_CACHE
__glcFontClose(font);
#endif
__glcRaiseError(GLC_RESOURCE_ERROR);
return;
}
}
}
}
#ifdef GLC_FT_CACHE
/* Empties GLC_CURRENT_FONT_LIST */
FT_List_Finalize(&ctx->currentFontList, NULL,
&__glcCommonArea.memoryManager, NULL);
#else
/* Close the remaining fonts in GLC_CURRENT_FONT_LIST and empty the list */
FT_List_Finalize(&ctx->currentFontList, __glcCloseFace,
&__glcCommonArea.memoryManager, NULL);
#endif
if (inFont) {
/* Insert the updated node as the first and only node */
node->data = font;
FT_List_Add(&ctx->currentFontList, node);
}
}
/** \ingroup font
* This command attempts to set the current face of the font identified by
* \e inFont to the face identified by the string \e inFace. Examples for
* font faces are strings like <tt>"Normal"</tt>, <tt>"Bold"</tt> or
* <tt>"Bold Italic"</tt>. In contrast to some systems that have a different
* font for each face, GLC allows you to have the face be an attribute of
* the font.
*
* If \e inFace is not an element of the font's string list attribute
* \b GLC_FACE_LIST, the command leaves the font's current face unchanged and
* returns \b GL_FALSE. If the command succeeds, it returns \b GL_TRUE.
*
* If \e inFont is zero, the command iterates over the
* \b GLC_CURRENT_FONT_LIST. For each of the fonts named therein, the command
* attempts to set the font's current face to the face in that font that is
* identified by \e inFace. In this case, the command returns \b GL_TRUE if
* \b GLC_CURRENT_FONT_LIST contains one or more elements and the command
* successfully sets the current face of each of the fonts named in the list.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element in
* the list \b GLC_FONT_LIST.
* \param inFont The ID of the font to be changed
* \param inFace The face for \e inFont
* \return \b GL_TRUE if the command succeeded to set the face \e inFace
* to the font \e inFont. \b GL_FALSE is returned otherwise.
* \sa glcGetFontFace()
*/
GLboolean APIENTRY glcFontFace(GLint inFont, const GLCchar* inFace)
{
__GLCcontext *ctx = NULL;
GLCchar8* UinFace = NULL;
__GLCfont* font = NULL;
GLC_INIT_THREAD();
assert(inFace);
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return GL_FALSE;
}
UinFace = __glcConvertToUtf8(inFace, ctx->stringState.stringType);
if (!UinFace)
return GL_FALSE;
if (inFont) {
GLboolean result = GL_FALSE;
/* Check if the current thread owns a context state
* and if the font identified by inFont exists
*/
font = __glcVerifyFontParameters(inFont);
if (!font) {
__glcFree(UinFace);
return GL_FALSE;
}
/* Open the new face */
result = __glcFontFace(font, UinFace, ctx);
__glcFree(UinFace);
return result;
}
else {
FT_ListNode node = NULL;
if (!ctx->currentFontList.head) {
__glcFree(UinFace);
return GL_FALSE;
}
/* Check that every font of GLC_CURRENT_FONT_LIST has a face identified
* by UinFace.
*/
for (node = ctx->currentFontList.head; node; node = node->next) {
__GLCmaster* master = NULL;
__GLCfaceDescriptor* faceDesc = NULL;
font = (__GLCfont*)node->data;
master = __glcMasterCreate(font->parentMasterID, ctx);
assert(master);
/* Get the face descriptor of the face identified by the string inFace */
faceDesc = __glcFaceDescCreate(master, UinFace, ctx, 0);
__glcMasterDestroy(master);
if (!faceDesc) {
/* No face identified by UinFace has been found in the font */
__glcFree(UinFace);
return GL_FALSE;
}
__glcFaceDescDestroy(faceDesc, ctx);
}
/* Set the current face of every font of GLC_CURRENT_FONT_LIST to the face
* identified by UinFace.
*/
for (node = ctx->currentFontList.head; node; node = node->next)
__glcFontFace((__GLCfont*)node->data, UinFace, ctx);
__glcFree(UinFace);
return GL_TRUE;
}
}
/** \ingroup font
* This command modifies the character map of the font identified by \e inFont
* such that the font maps \e inCode to the character whose name is the string
* \e inCharName. If \e inCharName is \b GLC_NONE, \e inCode is removed from
* the character map.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inCharName is not
* \b GLC_NONE or an element of the font string's list attribute
* \b GLC_CHAR_LIST.
* \param inFont The ID of the font
* \param inCode The integer ID of a character
* \param inCharName The string name of a character
* \sa glcGetFontMap()
*/
void APIENTRY glcFontMap(GLint inFont, GLint inCode, const GLCchar* inCharName)
{
__GLCfont *font = NULL;
GLint code = 0;
__GLCcontext* ctx = NULL;
GLC_INIT_THREAD();
/* Check if the font parameters are valid */
font = __glcVerifyFontParameters(inFont);
if (!font)
return;
ctx = GLC_GET_CURRENT_CONTEXT();
/* Get the character code converted to the UCS-4 format */
code = __glcConvertGLintToUcs4(ctx, inCode);
if (code < 0)
return;
if (!inCharName)
/* Remove the character from the map */
__glcCharMapRemoveChar(font->charMap, code);
else {
GLCchar8* buffer = NULL;
GLCulong mappedCode = 0;
__GLCglyph* glyph = NULL;
GLint error = 0;
/* Convert the character name identified by inCharName into UTF-8 format.
* The result is stored into 'buffer'.
*/
buffer = __glcConvertToUtf8(inCharName, ctx->stringState.stringType);
if (!buffer)
return;
/* Retrieve the Unicode code from its name */
error = __glcCodeFromName(buffer);
if (error < 0) {
__glcFree(buffer);
return;
}
mappedCode = (GLCulong)error;
/* Get the glyph that corresponds to the mapped code */
glyph = __glcFaceDescGetGlyph(font->faceDesc, mappedCode, ctx);
if (!glyph) {
__glcFree(buffer);
return;
}
/* Add the character and its corresponding glyph to the character map */
__glcCharMapAddChar(font->charMap, inCode, glyph);
__glcFree(buffer);
}
}
/* Allocate a new ID for a font and store it in a special list so that the same
* ID is not allocated twice.
*/
GLint __glcGenFontID(__GLCcontext* inContext)
{
FT_ListNode node = NULL;
__GLCfont* font = NULL;
GLint id = 1;
/* Look for an ID which is not associated to an existing font */
for (id = 1; id <= 0x7fffffff; id++) {
/* Check against fonts stored in GLC_FONT_LIST */
for (node = inContext->fontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == id)
break;
}
/* A font in GLC_FONT_LIST has already the current ID, check for next ID */
if (node)
continue;
/* Check against fonts already generated by glcGenFontID() but not yet
* associated to a font of GLC_FONT_LIST.
*/
for (node = inContext->genFontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == id)
break;
}
/* If the current ID is not associated then exit*/
if (!node)
break;
}
/* If we have scanned all possible ID values and failed to find one which is
* not yet associated (which is very unlikely) then exit with an error.
*/
if (node) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
/* Create an empty font */
node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
if (!node) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return 0;
}
font = __glcFontCreate(id, NULL, inContext, 0);
if (!font) {
__glcFree(node);
return 0;
}
node->data = font;
FT_List_Add(&inContext->genFontList, node);
return id;
}
/** \ingroup font
* This command returns a font ID that is not an element of the list
* \b GLC_FONT_LIST. This command has also the effect of creating an empty
* font for the returned ID so that this ID become used.
* \return A new font ID
* \sa glcDeleteFont()
* \sa glcIsFont()
* \sa glcNewFontFromFamily()
* \sa glcNewFontFromMaster()
*/
GLint APIENTRY glcGenFontID(void)
{
__GLCcontext *ctx = NULL;
GLC_INIT_THREAD();
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return 0;
}
return __glcGenFontID(ctx);
}
/** \ingroup font
* This command returns the string name of the current face of the font
* identified by \e inFont.
* \param inFont The font ID
* \return The string name of the font \e inFont
* \sa glcFontFace()
*/
const GLCchar* APIENTRY glcGetFontFace(GLint inFont)
{
__GLCfont *font = NULL;
GLC_INIT_THREAD();
font = __glcVerifyFontParameters(inFont);
if (font) {
GLCchar *buffer = NULL;
__GLCcontext *ctx = GLC_GET_CURRENT_CONTEXT();
/* Convert the string name of the face into the current string type */
buffer = __glcConvertFromUtf8ToBuffer(ctx,
__glcFaceDescGetStyleName(font->faceDesc));
if (!buffer)
return GLC_NONE;
/* returns the name */
return buffer;
}
else
return GLC_NONE;
}
/** \ingroup font
* This command returns an attribute of the font identified by \e inFont that
* is a string from a string list identified by \e inAttrib. The command
* returns the string at offset \e inIndex from the first element in \e
* inAttrib. For example, if \e inFont has a face list (\c Regular, \c Bold,
* \c Italic ) and \e inIndex is \c 2, then the command returns \c Italic if
* you query \b GLC_FACE_LIST.
*
* Every GLC state variable that is a list has an associated integer element
* count whose value is the number of elements in the list.
*
* Below are the string list attributes associated with each GLC master and
* font and their element count attributes :
* <center>
* <table>
* <caption>Master/font string list attributes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td> <td>Element count attribute</td>
* </tr>
* <tr>
* <td><b>GLC_CHAR_LIST</b></td>
* <td>0x0050</td>
* <td><b>GLC_CHAR_COUNT</b></td>
* </tr>
* <tr>
* <td><b>GLC_FACE_LIST</b></td>
* <td>0x0051</td>
* <td><b>GLC_FACE_COUNT</b></td>
* </tr>
* </table>
* </center>
* \n The command raises \b GLC_PARAMETER_ERROR if \e inIndex is less than
* zero or is greater than or equal to the value of the list element count
* attribute.
* \param inFont The font ID
* \param inAttrib The string list from which a string is requested
* \param inIndex The offset from the first element of the list associated
* with \e inAttrib
* \return A string attribute of \e inFont identified by \e inAttrib
* \sa glcGetMasterListc()
* \sa glcGetFontc()
* \sa glcGetFonti()
*/
const GLCchar* APIENTRY glcGetFontListc(GLint inFont, GLCenum inAttrib,
GLint inIndex)
{
__GLCfont* font = NULL;
__GLCcontext* ctx = NULL;
const GLCchar8* name = NULL;
GLC_INIT_THREAD();
/* Check if the font parameters are valid */
font = __glcVerifyFontParameters(inFont);
if (!font)
return NULL;
ctx = GLC_GET_CURRENT_CONTEXT();
switch(inAttrib) {
case GLC_FACE_LIST:
return glcGetMasterListc(font->parentMasterID, inAttrib, inIndex);
case GLC_CHAR_LIST:
name = __glcCharMapGetCharNameByIndex(font->charMap, inIndex);
if (!name)
return NULL;
return __glcConvertFromUtf8ToBuffer(ctx, name);
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return NULL;
}
}
/** \ingroup font
* This command returns the string name of the character that the font
* identified by \e inFont maps \e inCode to.
*
* To change the map, that is, associate a different name string with the
* integer ID of a font, use glcFontMap().
*
* If \e inCode cannot be mapped in the font, the command returns \b GLC_NONE.
*
* The command raises \b GLC_PARAMETER_ERROR if \e inFont is not an element of
* the list \b GLC_FONT_LIST
* \note Changing the map of a font is possible but changing the map of a
* master is not.
* \param inFont The integer ID of the font from which to select the character
* \param inCode The integer ID of the character in the font map
* \return The string name of the character that the font \e inFont maps
* \e inCode to.
* \sa glcGetMasterMap()
* \sa glcFontMap()
*/
const GLCchar* APIENTRY glcGetFontMap(GLint inFont, GLint inCode)
{
__GLCfont *font = NULL;
__GLCcontext *ctx = NULL;
GLint code = 0;
const GLCchar8* name = NULL;
GLC_INIT_THREAD();
/* Check if the font parameters are valid */
font = __glcVerifyFontParameters(inFont);
if (!font)
return NULL;
ctx = GLC_GET_CURRENT_CONTEXT();
/* Get the character code converted to the UCS-4 format */
code = __glcConvertGLintToUcs4(ctx, inCode);
if (code < 0)
return NULL;
name = __glcCharMapGetCharName(font->charMap, code);
if (!name)
return NULL;
return __glcConvertFromUtf8ToBuffer(ctx, name);
}
/** \ingroup font
* This command returns a string attribute of the font identified by
* \e inFont. The table below lists the string attributes that are
* associated with each GLC master and font.
* <center>
* <table>
* <caption>Master/font string attributes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td>
* </tr>
* <tr>
* <td><b>GLC_FAMILY</b></td> <td>0x0060</td>
* </tr>
* <tr>
* <td><b>GLC_MASTER_FORMAT</b></td> <td>0x0061</td>
* </tr>
* <tr>
* <td><b>GLC_VENDOR</b></td> <td>0x0062</td>
* </tr>
* <tr>
* <td><b>GLC_VERSION</b></td> <td>0x0063</td>
* </tr>
* <tr>
* <td><b>GLC_FULL_NAME_SGI</b></td> <td>0x8002</td>
* </tr>
* </table>
* </center>
* \param inFont The font for which the attribute is requested
* \param inAttrib The requested string attribute
* \return The string attribute \e inAttrib of the font \e inFont
* \sa glcGetMasterc()
* \sa glcGetFonti()
* \sa glcGetFontListc()
*/
const GLCchar* APIENTRY glcGetFontc(GLint inFont, GLCenum inAttrib)
{
__GLCfont *font = NULL;
GLC_INIT_THREAD();
/* Check if the font parameters are valid */
font = __glcVerifyFontParameters(inFont);
if (font)
/* Those are master attributes so we call the equivalent master function */
return glcGetMasterc(font->parentMasterID, inAttrib);
else
return GLC_NONE;
}
/** \ingroup font
* This command returns an integer attribute of the font identified by
* \e inFont. The attribute is identified by \e inAttrib. The table below
* lists the integer attributes that are associated with each GLC master
* and font.
* <center>
* <table>
* <caption>Master/font integer attributes</caption>
* <tr>
* <td>Name</td> <td>Enumerant</td>
* </tr>
* <tr>
* <td><b>GLC_CHAR_COUNT</b></td> <td>0x0070</td>
* </tr>
* <tr>
* <td><b>GLC_FACE_COUNT</b></td> <td>0x0071</td>
* </tr>
* <tr>
* <td><b>GLC_IS_FIXED_PITCH</b></td> <td>0x0072</td>
* </tr>
* <tr>
* <td><b>GLC_MAX_MAPPED_CODE</b></td> <td>0x0073</td>
* </tr>
* <tr>
* <td><b>GLC_MIN_MAPPED_CODE</b></td> <td>0x0074</td>
* </tr>
* </table>
* </center>
* \param inFont The font for which the attribute is requested.
* \param inAttrib The requested integer attribute
* \return The value of the specified integer attribute
* \sa glcGetMasteri()
* \sa glcGetFontc()
* \sa glcGetFontListc()
*/
GLint APIENTRY glcGetFonti(GLint inFont, GLCenum inAttrib)
{
__GLCfont *font = NULL;
GLC_INIT_THREAD();
/* Check if the font parameters are valid */
font = __glcVerifyFontParameters(inFont);
if (!font)
return 0;
switch(inAttrib) {
case GLC_CHAR_COUNT:
return __glcCharMapGetCount(font->charMap);
case GLC_IS_FIXED_PITCH:
return __glcFaceDescIsFixedPitch(font->faceDesc);
case GLC_MAX_MAPPED_CODE:
return __glcCharMapGetMaxMappedCode(font->charMap);
case GLC_MIN_MAPPED_CODE:
return __glcCharMapGetMinMappedCode(font->charMap);
case GLC_FACE_COUNT:
return glcGetMasteri(font->parentMasterID, inAttrib);
default:
__glcRaiseError(GLC_PARAMETER_ERROR);
return GLC_NONE;
}
}
/** \ingroup font
* This command returns \b GL_TRUE if \e inFont is the ID of a font. If
* \e inFont is not the ID of a font, the command does not raise an error.
* \param inFont The element to be tested
* \return \b GL_TRUE if \e inFont is the ID of a font, \b GL_FALSE
* otherwise.
* \sa glcGenFontID()
* \sa glcNewFontFromFamily()
* \sa glcNewFontFromMaster()
*/
GLboolean APIENTRY glcIsFont(GLint inFont)
{
__GLCcontext *ctx = NULL;
FT_ListNode node = NULL;
GLC_INIT_THREAD();
/* Check if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return GL_FALSE;
}
/* Verify if the font identifier exists */
for (node = ctx->fontList.head; node; node = node->next) {
__GLCfont *font = (__GLCfont*)node->data;
if (font->id == inFont)
return GL_TRUE;
}
/* If the ID corresponds to an empty font reserved by glcGenFontID() then
* return GL_TRUE in order to identify the ID as reserved.
*/
for (node = ctx->genFontList.head; node; node = node->next) {
__GLCfont* font = (__GLCfont*)node->data;
if (font->id == inFont)
return GL_TRUE;
}
return GL_FALSE;
}
/* This internal function deletes the font identified by inFont (if any) and
* creates a new font based on the pattern 'inPattern'. The resulting font is
* added to the list GLC_FONT_LIST.
*/
__GLCfont* __glcNewFontFromMaster(GLint inFontID, __GLCmaster* inMaster,
__GLCcontext *inContext, GLint inCode)
{
FT_ListNode node = NULL;
__GLCfont* font = NULL;
/* Look for the font which ID is inFont in the GLC_FONT_LIST */
for (node = inContext->fontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == inFontID) {
FT_List_Remove(&inContext->fontList, node);
break;
}
}
if (!node) {
/* Look if the ID is in the empty fonts generated by glcGenFontID() */
for (node = inContext->genFontList.head; node; node = node->next) {
font = (__GLCfont*)node->data;
if (font->id == inFontID) {
FT_List_Remove(&inContext->genFontList, node);
break;
}
}
}
if (node)
__glcContextDeleteFont(inContext, font);
else {
/* Create a new entry for GLC_FONT_LIST */
node = (FT_ListNode)__glcMalloc(sizeof(FT_ListNodeRec));
if (!node) {
__glcRaiseError(GLC_RESOURCE_ERROR);
return NULL;
}
}
/* Create a new font and add it to the list GLC_FONT_LIST */
font = __glcFontCreate(inFontID, inMaster, inContext, inCode);
if (!font) {
__glcFree(node);
return NULL;
}
node->data = font;
FT_List_Add(&inContext->fontList, node);
return font;
}
/** \ingroup font
* This command creates a new font from the master identified by \e inMaster.
* The ID of the new font is \e inFont. If the command succeeds, it returns
* \e inFont. If \e inFont is the ID of a font at the beginning of command
* execution, the command executes the command \c glcDeleteFont(inFont) before
* creating the new font.
* \param inFont The ID of the new font
* \param inMaster The master from which to create the new font
* \return The ID of the new font if the command succceeds, \c 0 otherwise.
* \sa glcGetListi() with argument \b GLC_FONT_LIST
* \sa glcGeti() with argument \b GLC_FONT_COUNT
* \sa glcIsFont()
* \sa glcGenFontID()
* \sa glcNewFontFromFamily()
* \sa glcDeleteFont()
*/
GLint APIENTRY glcNewFontFromMaster(GLint inFont, GLint inMaster)
{
__GLCcontext *ctx = NULL;
__GLCmaster *master = NULL;
__GLCfont *font = NULL;
GLC_INIT_THREAD();
/* Check if inFont is in legal bounds */
if (inFont < 1) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return 0;
}
/* Verify that the thread has a current context and that the master
* identified by 'inMaster' exists.
*/
master = __glcVerifyMasterParameters(inMaster);
if (!master)
return 0;
ctx = GLC_GET_CURRENT_CONTEXT();
/* Create and return the new font */
font = __glcNewFontFromMaster(inFont, master, ctx, 0);
__glcMasterDestroy(master);
return font->id;
}
/** \ingroup font
* This command performs a sequential search beginning with the first element
* of the GLC master list, looking for the first master whose string
* attribute \b GLC_FAMILY equals \e inFamily. If there is no such master the
* command returns zero. Otherwise, the command creates a new font from the
* master. The ID of the new font is \e inFont.
*
* If the command succeeds, it returns \e inFont. If \e inFont is the ID of a
* font at the beginning of command execution, the command executes the
* command \c glcDeleteFont(inFont) before creating the new font.
* \param inFont The ID of the new font.
* \param inFamily The font family, that is, the string that \b GLC_FAMILY
* attribute has to match.
* \return The ID of the new font if the command succeeds, \c 0 otherwise.
* \sa glcGetListi() with argument \b GLC_FONT_LIST
* \sa glcGeti() with argument \b GLC_FONT_COUNT
* \sa glcIsFont()
* \sa glcGenFontID()
* \sa glcNewFontFromMaster()
* \sa glcDeleteFont()
*/
GLint APIENTRY glcNewFontFromFamily(GLint inFont, const GLCchar* inFamily)
{
__GLCcontext *ctx = NULL;
GLCchar8* UinFamily = NULL;
__GLCmaster* master = NULL;
__GLCfont *font = NULL;
GLC_INIT_THREAD();
assert(inFamily);
/* Check if inFont is in legal bounds */
if (inFont < 1) {
__glcRaiseError(GLC_PARAMETER_ERROR);
return 0;
}
/* Verify if the current thread owns a context state */
ctx = GLC_GET_CURRENT_CONTEXT();
if (!ctx) {
__glcRaiseError(GLC_STATE_ERROR);
return 0;
}
/* Convert the family name in UTF-8 encoding */
UinFamily = __glcConvertToUtf8(inFamily, ctx->stringState.stringType);
if (!UinFamily)
return 0;
master = __glcMasterFromFamily(ctx, UinFamily);
__glcFree(UinFamily);
if (!master)
return 0;
/* Create and return the new font */
font = __glcNewFontFromMaster(inFont, master, ctx, 0);
__glcMasterDestroy(master);
return font->id;
}