1 /* QuesoGLC
2  * A free implementation of the OpenGL Character Renderer (GLC)
3  * Copyright (c) 2002, 2004-2008, 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: ofont.c 848 2008-11-02 12:56:00Z bcoconni $ */
20 
21 /* Defines the methods of an object that is intended to managed fonts */
22 
23 /** \file
24  * defines the object __GLCfont which manage the fonts
25  */
26 
27 #include <math.h>
28 #include "internal.h"
29 
30 
31 
32 /* Constructor of the object : it allocates memory and initializes the member
33  * of the new object.
34  * The user must give the master 'inParent' which the font will instantiate.
35  */
__glcFontCreate(GLint inID,__GLCmaster * inMaster,__GLCcontext * inContext,GLint inCode)36 __GLCfont* __glcFontCreate(GLint inID, __GLCmaster* inMaster,
37 			   __GLCcontext* inContext, GLint inCode)
38 {
39   __GLCfont *This = NULL;
40 
41   assert(inContext);
42 
43   This = (__GLCfont*)__glcMalloc(sizeof(__GLCfont));
44   if (!This) {
45     __glcRaiseError(GLC_RESOURCE_ERROR);
46     return NULL;
47   }
48 
49   if (inMaster) {
50     /* At font creation, the default face is the first one.
51      * glcFontFace() can change the face.
52      */
53     This->faceDesc = __glcFaceDescCreate(inMaster, NULL, inContext, inCode);
54     if (!This->faceDesc) {
55       __glcFree(This);
56       return NULL;
57     }
58 
59     This->charMap = __glcFaceDescGetCharMap(This->faceDesc, inContext);
60     if (!This->charMap) {
61       __glcFaceDescDestroy(This->faceDesc, inContext);
62       __glcFree(This);
63       return NULL;
64     }
65 
66     This->parentMasterID = __glcMasterGetID(inMaster, inContext);
67   }
68   else {
69     /* Creates an empty font (used by glcGenFontID() to reserve font IDs) */
70     This->faceDesc = NULL;
71     This->charMap = NULL;
72     This->parentMasterID = 0;
73   }
74 
75   This->id = inID;
76 
77   return This;
78 }
79 
80 
81 
82 /* Destructor of the object */
__glcFontDestroy(__GLCfont * This,__GLCcontext * inContext)83 void __glcFontDestroy(__GLCfont *This, __GLCcontext* inContext)
84 {
85   if (This->charMap)
86     __glcCharMapDestroy(This->charMap);
87 
88   if (This->faceDesc)
89     __glcFaceDescDestroy(This->faceDesc, inContext);
90 
91   __glcFree(This);
92 }
93 
94 
95 
96 /* Extract from the font the glyph which corresponds to the character code
97  * 'inCode'.
98  */
__glcFontGetGlyph(__GLCfont * This,GLint inCode,__GLCcontext * inContext)99 __GLCglyph* __glcFontGetGlyph(__GLCfont *This, GLint inCode,
100 			      __GLCcontext* inContext)
101 {
102   /* Try to get the glyph from the character map */
103   __GLCglyph* glyph = __glcCharMapGetGlyph(This->charMap, inCode);
104 
105   if (!glyph) {
106     /* If it fails, we must extract the glyph from the face */
107     glyph = __glcFaceDescGetGlyph(This->faceDesc, inCode, inContext);
108     if (!glyph)
109       return NULL;
110 
111     /* Update the character map so that the glyph will be cached */
112     __glcCharMapAddChar(This->charMap, inCode, glyph);
113   }
114 
115   return glyph;
116 }
117 
118 
119 
120 /* Get the bounding box of a glyph according to the size given by inScaleX and
121  * inScaleY. The result is returned in outVec. 'inCode' contains the character
122  * code for which the bounding box is requested.
123  */
__glcFontGetBoundingBox(__GLCfont * This,GLint inCode,GLfloat * outVec,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY)124 GLfloat* __glcFontGetBoundingBox(__GLCfont *This, GLint inCode,
125 				 GLfloat* outVec, __GLCcontext* inContext,
126 				 GLfloat inScaleX, GLfloat inScaleY)
127 {
128   /* Get the glyph from the font */
129   __GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
130 
131   assert(outVec);
132 
133   if (!glyph)
134     return NULL;
135 
136   /* If the bounding box of the glyph is cached then copy it to outVec and
137    * return.
138    */
139   if (glyph->boundingBoxCached && inContext->enableState.glObjects) {
140     memcpy(outVec, glyph->boundingBox, 4 * sizeof(GLfloat));
141     return outVec;
142   }
143 
144   /* Otherwise, we must extract the bounding box from the face file */
145   if (!__glcFaceDescGetBoundingBox(This->faceDesc, glyph->index, outVec,
146 				   inScaleX, inScaleY, inContext))
147     return NULL;
148 
149   /* Special case for glyphes which have no bounding box (i.e. spaces) */
150   if ((fabs(outVec[0] - outVec[2]) < GLC_EPSILON)
151       || (fabs(outVec[1] - outVec[3]) < GLC_EPSILON)) {
152     GLfloat advance[2] = {0.f, 0.f};
153 
154     if (__glcFontGetAdvance(This, inCode, advance, inContext, inScaleX,
155 			    inScaleY)) {
156       if (fabs(outVec[0] - outVec[2]) < GLC_EPSILON)
157 	outVec[2] += advance[0];
158 
159       if (fabs(outVec[1] - outVec[3]) < GLC_EPSILON)
160 	outVec[3] += advance[1];
161     }
162   }
163 
164   /* Copy the result to outVec and return */
165   if (inContext->enableState.glObjects) {
166     memcpy(glyph->boundingBox, outVec, 4 * sizeof(GLfloat));
167     glyph->boundingBoxCached = GL_TRUE;
168   }
169 
170   return outVec;
171 }
172 
173 
174 
175 /* Get the advance of a glyph according to the size given by inScaleX and
176  * inScaleY. The result is returned in outVec. 'inCode' contains the character
177  * code for which the advance is requested.
178  */
__glcFontGetAdvance(__GLCfont * This,GLint inCode,GLfloat * outVec,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY)179 GLfloat* __glcFontGetAdvance(__GLCfont* This, GLint inCode, GLfloat* outVec,
180 			     __GLCcontext* inContext, GLfloat inScaleX,
181 			     GLfloat inScaleY)
182 {
183   /* Get the glyph from the font */
184   __GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
185 
186   assert(outVec);
187 
188   if (!glyph)
189     return NULL;
190 
191   /* If the advance of the glyph is cached then copy it to outVec and
192    * return.
193    */
194   if (glyph->advanceCached && inContext->enableState.glObjects) {
195     memcpy(outVec, glyph->advance, 2 * sizeof(GLfloat));
196     return outVec;
197   }
198 
199   /* Otherwise, we must extract the advance from the face file */
200   if (!__glcFaceDescGetAdvance(This->faceDesc, glyph->index, outVec, inScaleX,
201 			       inScaleY, inContext))
202     return NULL;
203 
204   /* Copy the result to outVec and return */
205   if (inContext->enableState.glObjects) {
206     memcpy(glyph->advance, outVec, 2 * sizeof(GLfloat));
207     glyph->advanceCached = GL_TRUE;
208   }
209 
210   return outVec;
211 }
212 
213 
214 
215 /* Get the kerning information of a pair of glyph according to the size given by
216  * inScaleX and inScaleY. The result is returned in outVec. 'inCode' contains
217  * the current character code and 'inPrevCode' the character code of the
218  * previously displayed character.
219  */
__glcFontGetKerning(__GLCfont * This,GLint inCode,GLint inPrevCode,GLfloat * outVec,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY)220 GLfloat* __glcFontGetKerning(__GLCfont* This, GLint inCode, GLint inPrevCode,
221 			     GLfloat* outVec, __GLCcontext* inContext,
222 			     GLfloat inScaleX, GLfloat inScaleY)
223 {
224   __GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
225   __GLCglyph* prevGlyph = __glcFontGetGlyph(This, inPrevCode, inContext);
226 
227   if (!glyph || !prevGlyph)
228     return NULL;
229 
230   return __glcFaceDescGetKerning(This->faceDesc, glyph->index, prevGlyph->index,
231 				 inScaleX, inScaleY, outVec, inContext);
232 }
233 
234 
235 
236 /* This internal function tries to open the face file which name is identified
237  * by 'inFace'. If it succeeds, it closes the previous face and stores the new
238  * face attributes in the __GLCfont object "inFont". Otherwise, it leaves the
239  * font unchanged. GL_TRUE or GL_FALSE are returned to indicate if the function
240  * succeeded or not.
241  */
__glcFontFace(__GLCfont * This,const GLCchar8 * inFace,__GLCcontext * inContext)242 GLboolean __glcFontFace(__GLCfont* This, const GLCchar8* inFace,
243 			__GLCcontext *inContext)
244 {
245   __GLCfaceDescriptor *faceDesc = NULL;
246   __GLCmaster *master = NULL;
247   __GLCcharMap* newCharMap = NULL;
248 
249   /* TODO : Verify if the font has already the required face activated */
250 
251   master = __glcMasterCreate(This->parentMasterID, inContext);
252   if (!master)
253     return GL_FALSE;
254 
255   /* Get the face descriptor of the face identified by the string inFace */
256   faceDesc = __glcFaceDescCreate(master, inFace, inContext, 0);
257   if (!faceDesc) {
258     __glcMasterDestroy(master);
259     return GL_FALSE;
260   }
261 
262   newCharMap = __glcFaceDescGetCharMap(faceDesc, inContext);
263   if (!newCharMap) {
264     __glcFaceDescDestroy(faceDesc, inContext);
265     __glcMasterDestroy(master);
266     return GL_FALSE;
267   }
268 
269   __glcMasterDestroy(master);
270 
271 #ifndef GLC_FT_CACHE
272   /* If the font belongs to GLC_CURRENT_FONT_LIST then open the font file */
273   if (FT_List_Find(&inContext->currentFontList, This)) {
274 
275     /* Open the new face */
276     if (!__glcFaceDescOpen(faceDesc, inContext)) {
277       __glcFaceDescDestroy(faceDesc, inContext);
278       __glcCharMapDestroy(newCharMap);
279       return GL_FALSE;
280     }
281 
282     /* Close the current face */
283     __glcFontClose(This);
284   }
285 #endif
286 
287   /* Destroy the current charmap */
288   if (This->charMap)
289     __glcCharMapDestroy(This->charMap);
290 
291   This->charMap = newCharMap;
292 
293   __glcFaceDescDestroy(This->faceDesc, inContext);
294   This->faceDesc = faceDesc;
295 
296   return GL_TRUE;
297 }
298 
299 
300 
301 /* Load a glyph of the current font face and stores the corresponding data in
302  * the corresponding face. The size of the glyph is given by inScaleX and
303  * inScaleY. 'inGlyphIndex' contains the index of the glyph in the font file.
304  */
__glcFontPrepareGlyph(__GLCfont * This,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY,GLCulong inGlyphIndex)305 GLboolean __glcFontPrepareGlyph(__GLCfont* This, __GLCcontext* inContext,
306 				GLfloat inScaleX, GLfloat inScaleY,
307 				GLCulong inGlyphIndex)
308 {
309   GLboolean result = __glcFaceDescPrepareGlyph(This->faceDesc, inContext,
310 					       inScaleX, inScaleY,
311 					       inGlyphIndex);
312 #ifndef GLC_FT_CACHE
313   __glcFaceDescClose(This->faceDesc);
314 #endif
315 
316   return result;
317 }
318