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: ofacedesc.c 870 2009-01-18 12:01:27Z bcoconni $ */
20 
21 /** \file
22  * defines the object __GLCfaceDescriptor that contains the description of a
23  * face. One of the purpose of this object is to encapsulate the FT_Face
24  * structure from FreeType and to add it some more functionalities.
25  * It also allows to centralize the character map management for easier
26  * maintenance.
27  */
28 
29 #include <fontconfig/fontconfig.h>
30 #include <fontconfig/fcfreetype.h>
31 
32 #include "internal.h"
33 #include FT_GLYPH_H
34 #ifdef GLC_FT_CACHE
35 #include FT_CACHE_H
36 #endif
37 #include FT_OUTLINE_H
38 
39 #include FT_TYPE1_TABLES_H
40 #ifdef FT_XFREE86_H
41 #include FT_XFREE86_H
42 #endif
43 #include FT_BDF_H
44 #ifdef FT_WINFONTS_H
45 #include FT_WINFONTS_H
46 #endif
47 #include FT_SFNT_NAMES_H
48 #include FT_TRUETYPE_IDS_H
49 
50 
51 
52 /* Constructor of the object : it allocates memory and initializes the member
53  * of the new object.
54  * The user must give the name of the face, the character map, if it is a fixed
55  * font or not, the file name and the index of the font in its file.
56  */
__glcFaceDescCreate(__GLCmaster * inMaster,const GLCchar8 * inFace,__GLCcontext * inContext,GLint inCode)57 __GLCfaceDescriptor* __glcFaceDescCreate(__GLCmaster* inMaster,
58 					 const GLCchar8* inFace,
59 					 __GLCcontext* inContext, GLint inCode)
60 {
61   __GLCfaceDescriptor* This = NULL;
62   FcObjectSet* objectSet = NULL;
63   FcFontSet *fontSet = NULL;
64   int i = 0;
65   FcPattern* pattern = FcPatternCreate();
66 
67   if (!pattern) {
68     __glcRaiseError(GLC_RESOURCE_ERROR);
69     return NULL;
70   }
71 
72   objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_STYLE, FC_SPACING,
73 			       FC_FILE, FC_INDEX, FC_OUTLINE, FC_CHARSET, NULL);
74   if (!objectSet) {
75     __glcRaiseError(GLC_RESOURCE_ERROR);
76     FcPatternDestroy(pattern);
77     return NULL;
78   }
79   fontSet = FcFontList(inContext->config, pattern, objectSet);
80   FcObjectSetDestroy(objectSet);
81   FcPatternDestroy(pattern);
82   if (!fontSet) {
83     __glcRaiseError(GLC_RESOURCE_ERROR);
84     return NULL;
85   }
86 
87   for (i = 0; i < fontSet->nfont; i++) {
88     FcChar8* family = NULL;
89     int fixed = 0;
90     FcChar8* foundry = NULL;
91     FcChar8* style = NULL;
92     FcBool outline = FcFalse;
93     FcCharSet* charSet = NULL;
94     FcResult result = FcResultMatch;
95     FcBool equal = FcFalse;
96 
97     result = FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &charSet);
98     assert(result != FcResultTypeMismatch);
99     if (inCode && !FcCharSetHasChar(charSet, inCode))
100       continue;
101 
102     /* Check whether the glyphs are outlines */
103     result = FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline);
104     assert(result != FcResultTypeMismatch);
105     if (!outline)
106       continue;
107 
108     result = FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family);
109     assert(result != FcResultTypeMismatch);
110     result = FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry);
111     assert(result != FcResultTypeMismatch);
112     result = FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed);
113     assert(result != FcResultTypeMismatch);
114 
115     if (foundry)
116       pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
117 			       FC_FOUNDRY, FcTypeString, foundry, FC_SPACING,
118 			       FcTypeInteger, fixed, NULL);
119     else
120       pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
121 			       FC_SPACING, FcTypeInteger, fixed, NULL);
122 
123     if (!pattern) {
124       __glcRaiseError(GLC_RESOURCE_ERROR);
125       FcFontSetDestroy(fontSet);
126       return NULL;
127     }
128 
129     equal = FcPatternEqual(pattern, inMaster->pattern);
130     FcPatternDestroy(pattern);
131     if (equal) {
132       if (inFace) {
133 	result = FcPatternGetString(fontSet->fonts[i], FC_STYLE, 0, &style);
134 	assert(result != FcResultTypeMismatch);
135 	if (strcmp((const char*)style, (const char*)inFace))
136 	  continue;
137       }
138       break;
139     }
140   }
141 
142   if (i == fontSet->nfont) {
143     FcFontSetDestroy(fontSet);
144     __glcRaiseError(GLC_RESOURCE_ERROR);
145     return NULL;
146   }
147 
148   This = (__GLCfaceDescriptor*)__glcMalloc(sizeof(__GLCfaceDescriptor));
149   if (!This) {
150     FcFontSetDestroy(fontSet);
151     __glcRaiseError(GLC_RESOURCE_ERROR);
152     return NULL;
153   }
154 
155   This->pattern = FcPatternDuplicate(fontSet->fonts[i]);
156   FcFontSetDestroy(fontSet);
157   if (!This->pattern) {
158     __glcRaiseError(GLC_RESOURCE_ERROR);
159     __glcFree(This);
160     return NULL;
161   }
162 
163   This->node.prev = NULL;
164   This->node.next = NULL;
165   This->node.data = NULL;
166   This->face = NULL;
167 #ifndef GLC_FT_CACHE
168   This->faceRefCount = 0;
169 #endif
170   This->glyphList.head = NULL;
171   This->glyphList.tail = NULL;
172 
173   return This;
174 }
175 
176 
177 
178 /* Destructor of the object */
__glcFaceDescDestroy(__GLCfaceDescriptor * This,__GLCcontext * inContext)179 void __glcFaceDescDestroy(__GLCfaceDescriptor* This, __GLCcontext* inContext)
180 {
181   FT_ListNode node = NULL;
182   FT_ListNode next = NULL;
183 
184 #ifndef GLC_FT_CACHE
185   assert(!This->faceRefCount && !This->face);
186 #endif
187 
188   /* Don't use FT_List_Finalize here, since __glcGlyphDestroy also destroys
189    * the node itself.
190    */
191   node = This->glyphList.head;
192   while (node) {
193     next = node->next;
194     __glcGlyphDestroy((__GLCglyph*)node, inContext);
195     node = next;
196   }
197 
198 #if defined(GLC_FT_CACHE) \
199   && (FREETYPE_MAJOR > 2 \
200      || (FREETYPE_MAJOR == 2 \
201          && (FREETYPE_MINOR > 1 \
202              || (FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 8))))
203   /* In order to make sure its ID is removed from the FreeType cache */
204   FTC_Manager_RemoveFaceID(inContext->cache, (FTC_FaceID)This);
205 #endif
206 
207   FcPatternDestroy(This->pattern);
208   __glcFree(This);
209 }
210 
211 
212 
213 #ifndef GLC_FT_CACHE
214 /* Open a face, select a Unicode charmap. __glcFaceDesc maintains a reference
215  * count for each face so that the face is open only once.
216  */
__glcFaceDescOpen(__GLCfaceDescriptor * This,__GLCcontext * inContext)217 FT_Face __glcFaceDescOpen(__GLCfaceDescriptor* This,
218 			  __GLCcontext* inContext)
219 {
220   if (!This->faceRefCount) {
221     GLCchar8 *fileName = NULL;
222     int index = 0;
223     FcResult result = FcResultMatch;
224 
225     /* get the file name */
226     result = FcPatternGetString(This->pattern, FC_FILE, 0, &fileName);
227     assert(result != FcResultTypeMismatch);
228     /* get the index of the font in font file */
229     result = FcPatternGetInteger(This->pattern, FC_INDEX, 0, &index);
230     assert(result != FcResultTypeMismatch);
231 
232     if (FT_New_Face(inContext->library, (const char*)fileName, index,
233 		    &This->face)) {
234       /* Unable to load the face file */
235       __glcRaiseError(GLC_RESOURCE_ERROR);
236       return NULL;
237     }
238 
239     /* select a Unicode charmap */
240     FT_Select_Charmap(This->face, ft_encoding_unicode);
241 
242     This->faceRefCount = 1;
243   }
244   else
245     This->faceRefCount++;
246 
247   return This->face;
248 }
249 
250 
251 
252 /* Close the face and update the reference counter accordingly */
__glcFaceDescClose(__GLCfaceDescriptor * This)253 void __glcFaceDescClose(__GLCfaceDescriptor* This)
254 {
255   assert(This->faceRefCount > 0);
256 
257   This->faceRefCount--;
258 
259   if (!This->faceRefCount) {
260     assert(This->face);
261 
262     FT_Done_Face(This->face);
263     This->face = NULL;
264   }
265 }
266 
267 
268 
269 #else /* GLC_FT_CACHE */
270 /* Callback function used by the FreeType cache manager to open a given face */
__glcFileOpen(FTC_FaceID inFile,FT_Library inLibrary,FT_Pointer GLC_UNUSED_ARG (inData),FT_Face * outFace)271 FT_Error __glcFileOpen(FTC_FaceID inFile, FT_Library inLibrary,
272 		       FT_Pointer GLC_UNUSED_ARG(inData), FT_Face* outFace)
273 {
274   __GLCfaceDescriptor* file = (__GLCfaceDescriptor*)inFile;
275   GLCchar8 *fileName = NULL;
276   int fileIndex = 0;
277   FcResult result = FcResultMatch;
278   FT_Error error;
279 
280   /* get the file name */
281   result = FcPatternGetString(file->pattern, FC_FILE, 0, &fileName);
282   assert(result != FcResultTypeMismatch);
283   /* get the index of the font in font file */
284   result = FcPatternGetInteger(file->pattern, FC_INDEX, 0, &fileIndex);
285   assert(result != FcResultTypeMismatch);
286 
287   error = FT_New_Face(inLibrary, (const char*)fileName, fileIndex, outFace);
288 
289   if (error) {
290     __glcRaiseError(GLC_RESOURCE_ERROR);
291     return error;
292   }
293 
294   /* select a Unicode charmap */
295   FT_Select_Charmap(*outFace, ft_encoding_unicode);
296 
297   return error;
298 }
299 #endif /* GLC_FT_CACHE */
300 
301 
302 
303 /* Return the glyph which corresponds to codepoint 'inCode' */
__glcFaceDescGetGlyph(__GLCfaceDescriptor * This,GLint inCode,__GLCcontext * inContext)304 __GLCglyph* __glcFaceDescGetGlyph(__GLCfaceDescriptor* This, GLint inCode,
305 				  __GLCcontext* inContext)
306 {
307   FT_Face face = NULL;
308   __GLCglyph* glyph = NULL;
309   FT_ListNode node = NULL;
310 
311   /* Check if the glyph has already been added to the glyph list */
312   for (node = This->glyphList.head; node; node = node->next) {
313     glyph = (__GLCglyph*)node;
314     if (glyph->codepoint == (GLCulong)inCode)
315       return glyph;
316   }
317 
318   /* Open the face */
319 #ifdef GLC_FT_CACHE
320   if (FTC_Manager_LookupFace(inContext->cache, (FTC_FaceID)This, &face)) {
321 #else
322   face = __glcFaceDescOpen(This, inContext);
323   if (!face) {
324 #endif
325     __glcRaiseError(GLC_RESOURCE_ERROR);
326     return NULL;
327   }
328 
329   /* Create a new glyph */
330 #ifdef GLC_FT_CACHE
331   glyph = __glcGlyphCreate(FT_Get_Char_Index(face, inCode), inCode);
332   if (!glyph)
333     return NULL;
334 #else
335   glyph = __glcGlyphCreate(FcFreeTypeCharIndex(face, inCode), inCode);
336   if (!glyph) {
337     __glcFaceDescClose(This);
338     return NULL;
339   }
340 #endif
341   /* Append the new glyph to the list of the glyphes of the face and close the
342    * face.
343    */
344   FT_List_Add(&This->glyphList, (FT_ListNode)glyph);
345 #ifndef GLC_FT_CACHE
346   __glcFaceDescClose(This);
347 #endif
348   return glyph;
349 }
350 
351 
352 
353 /* Load a glyph of the current font face and stores the corresponding data in
354  * the corresponding face. The size of the glyph is given by inScaleX and
355  * inScaleY. 'inGlyphIndex' contains the index of the glyph in the font file.
356  */
357 GLboolean __glcFaceDescPrepareGlyph(__GLCfaceDescriptor* This,
358 				    __GLCcontext* inContext, GLfloat inScaleX,
359 				    GLfloat inScaleY, GLCulong inGlyphIndex)
360 {
361   FT_Int32 loadFlags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM;
362 #ifdef GLC_FT_CACHE
363 # if FREETYPE_MAJOR == 2 \
364      && (FREETYPE_MINOR < 1 \
365          || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 8))
366   FTC_FontRec font;
367 # else
368   FTC_ScalerRec scaler;
369 # endif
370   FT_Size size = NULL;
371 #else
372   FT_Error error;
373 #endif
374 
375   /* If GLC_HINTING_QSO is enabled then perform hinting on the glyph while
376    * loading it.
377    */
378   if (!inContext->enableState.hinting && !inContext->enableState.glObjects)
379     loadFlags |= FT_LOAD_NO_HINTING;
380 
381   /* Open the face */
382 #ifdef GLC_FT_CACHE
383 # if FREETYPE_MAJOR == 2 \
384      && (FREETYPE_MINOR < 1 \
385          || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 8))
386   font.face_id = (FTC_FaceID)This;
387 
388   if (inContext->enableState.glObjects) {
389     font.pix_width = (FT_UShort) inScaleX;
390     font.pix_height = (FT_UShort) inScaleY;
391   }
392   else {
393     font.pix_width = (FT_UShort) (inScaleX *
394       (inContext->renderState.resolution < GLC_EPSILON ?
395        72. : inContext->renderState.resolution) / 72.);
396     font.pix_height = (FT_UShort) (inScaleY *
397       (inContext->renderState.resolution < GLC_EPSILON ?
398        72. : inContext->renderState.resolution) / 72.);
399   }
400 
401   if (FTC_Manager_Lookup_Size(inContext->cache, &font, &This->face, &size)) {
402     __glcRaiseError(GLC_RESOURCE_ERROR);
403     return GL_FALSE;
404   }
405 # else
406   scaler.face_id = (FTC_FaceID)This;
407   scaler.width = (FT_UInt)(inScaleX * 64.);
408   scaler.height = (FT_UInt)(inScaleY * 64.);
409   scaler.pixel = (FT_Int)0;
410 
411   if (inContext->enableState.glObjects) {
412     scaler.x_res = 72;
413     scaler.y_res = 72;
414   }
415   else {
416     scaler.x_res = (FT_UInt)(inContext->renderState.resolution < GLC_EPSILON ?
417 			     72 : inContext->renderState.resolution);
418     scaler.y_res = (FT_UInt)(inContext->renderState.resolution < GLC_EPSILON ?
419 			     72 : inContext->renderState.resolution);
420   }
421 
422   if (FTC_Manager_LookupSize(inContext->cache, &scaler, &size)) {
423     __glcRaiseError(GLC_RESOURCE_ERROR);
424     return GL_FALSE;
425   }
426 
427   This->face = size->face;
428 # endif /* FREETYPE_MAJOR */
429 #else
430   if (!__glcFaceDescOpen(This, inContext))
431     return GL_FALSE;
432 
433   /* Select the size of the glyph */
434   if (inContext->enableState.glObjects) {
435     error = FT_Set_Char_Size(This->face, (FT_F26Dot6)(inScaleX * 64.),
436 			     (FT_F26Dot6)(inScaleY * 64.), 0, 0);
437   }
438   else {
439     error = FT_Set_Char_Size(This->face, (FT_F26Dot6)(inScaleX * 64.),
440 			     (FT_F26Dot6)(inScaleY * 64.),
441 			     (FT_UInt)inContext->renderState.resolution,
442 			     (FT_UInt)inContext->renderState.resolution);
443   }
444   if (error) {
445     __glcFaceDescClose(This);
446     __glcRaiseError(GLC_RESOURCE_ERROR);
447     return GL_FALSE;
448   }
449 #endif
450 
451   /* Load the glyph */
452   if (FT_Load_Glyph(This->face, inGlyphIndex, loadFlags)) {
453     __glcRaiseError(GLC_RESOURCE_ERROR);
454 #ifndef GLC_FT_CACHE
455     __glcFaceDescClose(This);
456 #endif
457     return GL_FALSE;
458   }
459 
460   return GL_TRUE;
461 }
462 
463 
464 
465 /* Destroy the GL objects of every glyph of the face */
466 void __glcFaceDescDestroyGLObjects(__GLCfaceDescriptor* This,
467 				   __GLCcontext* inContext)
468 {
469   FT_ListNode node = NULL;
470 
471   for (node = This->glyphList.head; node; node = node->next) {
472     __GLCglyph* glyph = (__GLCglyph*)node;
473 
474     __glcGlyphDestroyGLObjects(glyph, inContext);
475   }
476 }
477 
478 
479 
480 /* Get the bounding box of a glyph according to the size given by inScaleX and
481  * inScaleY. The result is returned in outVec. 'inGlyphIndex' contains the
482  * index of the glyph in the font file.
483  */
484 GLfloat* __glcFaceDescGetBoundingBox(__GLCfaceDescriptor* This,
485 				     GLCulong inGlyphIndex, GLfloat* outVec,
486 				     GLfloat inScaleX, GLfloat inScaleY,
487 				     __GLCcontext* inContext)
488 {
489   FT_BBox boundBox;
490   FT_Glyph glyph;
491 
492   assert(outVec);
493 
494   if (!__glcFaceDescPrepareGlyph(This, inContext, inScaleX, inScaleY,
495 				 inGlyphIndex))
496     return NULL;
497 
498   /* Get the bounding box of the glyph */
499   FT_Get_Glyph(This->face->glyph, &glyph);
500   FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &boundBox);
501 
502   /* Transform the bounding box according to the conversion from FT_F26Dot6 to
503    * GLfloat and the size in points of the glyph.
504    */
505   outVec[0] = (GLfloat) boundBox.xMin / 64. / inScaleX;
506   outVec[2] = (GLfloat) boundBox.xMax / 64. / inScaleX;
507   outVec[1] = (GLfloat) boundBox.yMin / 64. / inScaleY;
508   outVec[3] = (GLfloat) boundBox.yMax / 64. / inScaleY;
509 
510   FT_Done_Glyph(glyph);
511 #ifndef GLC_FT_CACHE
512   __glcFaceDescClose(This);
513 #endif
514   return outVec;
515 }
516 
517 
518 
519 /* Get the advance of a glyph according to the size given by inScaleX and
520  * inScaleY. The result is returned in outVec. 'inGlyphIndex' contains the
521  * index of the glyph in the font file.
522  */
523 GLfloat* __glcFaceDescGetAdvance(__GLCfaceDescriptor* This,
524 				 GLCulong inGlyphIndex, GLfloat* outVec,
525 				 GLfloat inScaleX, GLfloat inScaleY,
526 				 __GLCcontext* inContext)
527 {
528   assert(outVec);
529 
530   if (!__glcFaceDescPrepareGlyph(This, inContext, inScaleX, inScaleY,
531 				 inGlyphIndex))
532     return NULL;
533 
534   /* Transform the advance according to the conversion from FT_F26Dot6 to
535    * GLfloat.
536    */
537   outVec[0] = (GLfloat) This->face->glyph->advance.x / 64. / inScaleX;
538   outVec[1] = (GLfloat) This->face->glyph->advance.y / 64. / inScaleY;
539 
540 #ifndef GLC_FT_CACHE
541   __glcFaceDescClose(This);
542 #endif
543   return outVec;
544 }
545 
546 
547 
548 /* Use FreeType to determine in which format the face is stored in its file :
549  * Type1, TrueType, OpenType, ...
550  */
551 const GLCchar8* __glcFaceDescGetFontFormat(__GLCfaceDescriptor* This,
552 					   __GLCcontext* inContext,
553 					   GLCenum inAttrib)
554 {
555   static GLCchar8 unknown[] = "Unknown";
556 #ifndef FT_XFREE86_H
557   static GLCchar8 masterFormat1[] = "Type 1";
558   static GLCchar8 masterFormat2[] = "BDF";
559 #  ifdef FT_WINFONTS_H
560   static GLCchar8 masterFormat3[] = "Windows FNT";
561 #  endif /* FT_WINFONTS_H */
562   static GLCchar8 masterFormat4[] = "TrueType/OpenType";
563 #endif /* FT_XFREE86_H */
564 
565   FT_Face face = NULL;
566   PS_FontInfoRec afont_info;
567   const char* acharset_encoding = NULL;
568   const char* acharset_registry = NULL;
569 #ifdef FT_WINFONTS_H
570   FT_WinFNT_HeaderRec aheader;
571 #endif
572   GLCuint count = 0;
573   const GLCchar8* result = NULL;
574 
575   /* Open the face */
576 #ifdef GLC_FT_CACHE
577   if (FTC_Manager_LookupFace(inContext->cache, (FTC_FaceID)This, &face)) {
578 #else
579   face = __glcFaceDescOpen(This, inContext);
580   if (!face) {
581 #endif
582     __glcRaiseError(GLC_RESOURCE_ERROR);
583     return GL_FALSE;
584   }
585 
586 #ifdef FT_XFREE86_H
587   if (inAttrib == GLC_MASTER_FORMAT) {
588     /* This function is undocumented until FreeType 2.3.0 where it has been
589      * added to the public API. It can be safely used nonetheless as long as
590      * the existence of FT_XFREE86_H is checked.
591      */
592     result = (const GLCchar8*)FT_Get_X11_Font_Format(face);
593 #  ifndef GLC_FT_CACHE
594     __glcFaceDescClose(This);
595 #  endif /* GLC_FT_CACHE */
596     return result;
597   }
598 #endif /* FT_XFREE86_H */
599 
600   /* Is it Type 1 ? */
601   if (!FT_Get_PS_Font_Info(face, &afont_info)) {
602     switch(inAttrib) {
603 #ifndef FT_XFREE86_H
604     case GLC_MASTER_FORMAT:
605 #ifndef GLC_FT_CACHE
606       __glcFaceDescClose(This);
607 #endif
608       return masterFormat1;
609 #endif
610     case GLC_FULL_NAME_SGI:
611       if (afont_info.full_name)
612 	result = (GLCchar8*)afont_info.full_name;
613       break;
614     case GLC_VERSION:
615       if (afont_info.version)
616 	result = (GLCchar8*)afont_info.version;
617       break;
618     }
619   }
620   /* Is it BDF ? */
621   else if (!FT_Get_BDF_Charset_ID(face, &acharset_encoding,
622 				  &acharset_registry)) {
623     switch(inAttrib) {
624 #ifndef FT_XFREE86_H
625     case GLC_MASTER_FORMAT:
626       result = masterFormat2;
627       break;
628 #endif
629     case GLC_FULL_NAME_SGI:
630       result = unknown;
631       break;
632     case GLC_VERSION:
633       result = unknown;
634       break;
635     }
636   }
637 #ifdef FT_WINFONTS_H
638   /* Is it Windows FNT ? */
639   else if (!FT_Get_WinFNT_Header(face, &aheader)) {
640     switch(inAttrib) {
641 #ifndef FT_XFREE86_H
642     case GLC_MASTER_FORMAT:
643       result = masterFormat3;
644       break;
645 #endif
646     case GLC_FULL_NAME_SGI:
647       result = unknown;
648       break;
649     case GLC_VERSION:
650       result = unknown;
651       break;
652     }
653   }
654 #endif
655   /* Is it TrueType/OpenType ? */
656   else if ((count = FT_Get_Sfnt_Name_Count(face))) {
657 #if 0
658     GLCuint i = 0;
659     FT_SfntName aName;
660 #endif
661 
662     switch(inAttrib) {
663 #ifndef FT_XFREE86_H
664     case GLC_MASTER_FORMAT:
665       result = masterFormat4;
666       break;
667 #endif
668     case GLC_FULL_NAME_SGI:
669       result = unknown;
670       break;
671     case GLC_VERSION:
672       result = unknown;
673       break;
674     }
675 
676     /* TODO : decode the SFNT name tables in order to get full name
677      * of the TrueType/OpenType fonts and their version
678      */
679 #if 0
680     for (i = 0; i < count; i++) {
681       if (!FT_Get_Sfnt_Name(face, i, &aName)) {
682         if ((aName.name_id != TT_NAME_ID_FULL_NAME)
683 		&& (aName.name_id != TT_NAME_ID_VERSION_STRING))
684 	  continue;
685 
686         switch (aName.platform_id) {
687 	case TT_PLATFORM_APPLE_UNICODE:
688 	  break;
689 	case TT_PLATFORM_MICROSOFT:
690 	  break;
691 	}
692       }
693     }
694 #endif
695   }
696 
697 #ifndef GLC_FT_CACHE
698   /* Close the face */
699   __glcFaceDescClose(This);
700 #endif
701   return result;
702 }
703 
704 
705 
706 /* Get the maximum metrics of a face that is the bounding box that encloses
707  * every glyph of the face, and the maximum advance of the face.
708  */
709 GLfloat* __glcFaceDescGetMaxMetric(__GLCfaceDescriptor* This, GLfloat* outVec,
710 				   __GLCcontext* inContext)
711 {
712   FT_Face face = NULL;
713   /* If the resolution of the context is zero then use the default 72 dpi */
714   GLfloat scale = (inContext->renderState.resolution < GLC_EPSILON ?
715 		   72. : inContext->renderState.resolution) / 72.;
716 
717   assert(outVec);
718 
719 #ifdef GLC_FT_CACHE
720   if (FTC_Manager_LookupFace(inContext->cache, (FTC_FaceID)This, &face))
721 #else
722   face = __glcFaceDescOpen(This, inContext);
723   if (!face)
724 #endif
725     return NULL;
726 
727   scale /= face->units_per_EM;
728 
729   /* Get the values and transform them according to the resolution */
730   outVec[0] = (GLfloat)face->max_advance_width * scale;
731   outVec[1] = (GLfloat)face->max_advance_height * scale;
732   outVec[2] = (GLfloat)face->bbox.yMax * scale;
733   outVec[3] = (GLfloat)face->bbox.yMin * scale;
734   outVec[4] = (GLfloat)face->bbox.xMax * scale;
735   outVec[5] = (GLfloat)face->bbox.xMin * scale;
736 
737 #ifndef GLC_FT_CACHE
738   __glcFaceDescClose(This);
739 #endif
740   return outVec;
741 }
742 
743 
744 
745 /* Get the kerning information of a pair of glyphes according to the size given
746  * by inScaleX and inScaleY. The result is returned in outVec.
747  */
748 GLfloat* __glcFaceDescGetKerning(__GLCfaceDescriptor* This,
749 				 GLCuint inGlyphIndex, GLCuint inPrevGlyphIndex,
750 				 GLfloat inScaleX, GLfloat inScaleY,
751 				 GLfloat* outVec, __GLCcontext* inContext)
752 {
753   FT_Vector kerning;
754   FT_Error error;
755 
756   assert(outVec);
757 
758   if (!__glcFaceDescPrepareGlyph(This, inContext, inScaleX, inScaleY,
759 				 inGlyphIndex))
760     return NULL;
761 
762   if (!FT_HAS_KERNING(This->face)) {
763     outVec[0] = 0.;
764     outVec[1] = 0.;
765     return outVec;
766   }
767 
768   error = FT_Get_Kerning(This->face, inPrevGlyphIndex, inGlyphIndex,
769 			 FT_KERNING_DEFAULT, &kerning);
770 
771 #ifndef GLC_FT_CACHE
772   __glcFaceDescClose(This);
773 #endif
774 
775   if (error)
776     return NULL;
777   else {
778     outVec[0] = (GLfloat) kerning.x / 64. / inScaleX;
779     outVec[1] = (GLfloat) kerning.y / 64. / inScaleY;
780     return outVec;
781   }
782 }
783 
784 
785 
786 /* Get the style name of the face descriptor */
787 GLCchar8* __glcFaceDescGetStyleName(__GLCfaceDescriptor* This)
788 {
789   GLCchar8 *styleName = NULL;
790   FcResult result = FcPatternGetString(This->pattern, FC_STYLE, 0, &styleName);
791 
792   assert(result != FcResultTypeMismatch);
793   return styleName;
794 }
795 
796 
797 
798 /* Determine if the face descriptor has a fixed pitch */
799 GLboolean __glcFaceDescIsFixedPitch(__GLCfaceDescriptor* This)
800 {
801   int fixed = 0;
802   FcResult result = FcPatternGetInteger(This->pattern, FC_SPACING, 0, &fixed);
803 
804   assert(result != FcResultTypeMismatch);
805   return (fixed != FC_PROPORTIONAL);
806 }
807 
808 
809 
810 /* Callback function that is called by the FreeType function
811  * FT_Outline_Decompose() when parsing an outline.
812  * MoveTo is called when the pen move from one curve to another curve.
813  */
814 #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2))
815 static int __glcMoveTo(const FT_Vector *inVecTo, void* inUserData)
816 #else
817 static int __glcMoveTo(FT_Vector *inVecTo, void* inUserData)
818 #endif
819 {
820   __GLCrendererData *data = (__GLCrendererData *) inUserData;
821 
822   /* We don't need to store the point where the pen is since glyphs are defined
823    * by closed loops (i.e. the first point and the last point are the same) and
824    * the first point will be stored by the next call to lineto/conicto/cubicto.
825    */
826 
827   if (!__glcArrayAppend(data->endContour,
828 			&GLC_ARRAY_LENGTH(data->vertexArray)))
829     return 1;
830 
831   data->vector[0] = (GLfloat) inVecTo->x;
832   data->vector[1] = (GLfloat) inVecTo->y;
833   return 0;
834 }
835 
836 
837 
838 /* Callback function that is called by the FreeType function
839  * FT_Outline_Decompose() when parsing an outline.
840  * LineTo is called when the pen draws a line between two points.
841  */
842 #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2))
843 static int __glcLineTo(const FT_Vector *inVecTo, void* inUserData)
844 #else
845 static int __glcLineTo(FT_Vector *inVecTo, void* inUserData)
846 #endif
847 {
848   __GLCrendererData *data = (__GLCrendererData *) inUserData;
849 
850   if (!__glcArrayAppend(data->vertexArray, data->vector))
851     return 1;
852 
853   data->vector[0] = (GLfloat) inVecTo->x;
854   data->vector[1] = (GLfloat) inVecTo->y;
855   return 0;
856 }
857 
858 
859 
860 /* Callback function that is called by the FreeType function
861  * FT_Outline_Decompose() when parsing an outline.
862  * ConicTo is called when the pen draws a conic between two points (and with
863  * one control point).
864  */
865 #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2))
866 static int __glcConicTo(const FT_Vector *inVecControl,
867 			const FT_Vector *inVecTo, void* inUserData)
868 {
869 #else
870 static int __glcConicTo(FT_Vector *inVecControl, FT_Vector *inVecTo,
871 			void* inUserData)
872 {
873 #endif
874   __GLCrendererData *data = (__GLCrendererData *) inUserData;
875   int error = 0;
876 
877   data->vector[2] = (GLfloat)inVecControl->x;
878   data->vector[3] = (GLfloat)inVecControl->y;
879   data->vector[4] = (GLfloat)inVecTo->x;
880   data->vector[5] = (GLfloat)inVecTo->y;
881   error = __glcdeCasteljauConic(inUserData);
882   data->vector[0] = (GLfloat) inVecTo->x;
883   data->vector[1] = (GLfloat) inVecTo->y;
884 
885   return error;
886 }
887 
888 
889 
890 /* Callback functions that is called by the FreeType function
891  * FT_Outline_Decompose() when parsing an outline.
892  * CubicTo is called when the pen draws a cubic between two points (and with
893  * two control points).
894  */
895 #if ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2))
896 static int __glcCubicTo(const FT_Vector *inVecControl1,
897 			const FT_Vector *inVecControl2,
898 			const FT_Vector *inVecTo, void* inUserData)
899 {
900 #else
901 static int __glcCubicTo(FT_Vector *inVecControl1, FT_Vector *inVecControl2,
902 			FT_Vector *inVecTo, void* inUserData)
903 {
904 #endif
905   __GLCrendererData *data = (__GLCrendererData *) inUserData;
906   int error = 0;
907 
908   data->vector[2] = (GLfloat)inVecControl1->x;
909   data->vector[3] = (GLfloat)inVecControl1->y;
910   data->vector[4] = (GLfloat)inVecControl2->x;
911   data->vector[5] = (GLfloat)inVecControl2->y;
912   data->vector[6] = (GLfloat)inVecTo->x;
913   data->vector[7] = (GLfloat)inVecTo->y;
914   error = __glcdeCasteljauCubic(inUserData);
915   data->vector[0] = (GLfloat) inVecTo->x;
916   data->vector[1] = (GLfloat) inVecTo->y;
917 
918   return error;
919 }
920 
921 
922 
923 /* Decompose the outline of a glyph */
924 GLboolean __glcFaceDescOutlineDecompose(__GLCfaceDescriptor* This,
925                                         __GLCrendererData* inData,
926                                         __GLCcontext* inContext)
927 {
928   FT_Outline *outline = NULL;
929   FT_Outline_Funcs outlineInterface;
930   FT_Face face = NULL;
931 
932 #ifndef GLC_FT_CACHE
933   face = This->face;
934 #else
935   if (FTC_Manager_LookupFace(inContext->cache, (FTC_FaceID)This, &face)) {
936     __glcRaiseError(GLC_RESOURCE_ERROR);
937     return GL_FALSE;
938   }
939 #endif
940 
941   /* Initialize the data for FreeType to parse the outline */
942   outline = &face->glyph->outline;
943   outlineInterface.shift = 0;
944   outlineInterface.delta = 0;
945   outlineInterface.move_to = __glcMoveTo;
946   outlineInterface.line_to = __glcLineTo;
947   outlineInterface.conic_to = __glcConicTo;
948   outlineInterface.cubic_to = __glcCubicTo;
949 
950   if (inContext->enableState.glObjects) {
951     /* Distances are computed in object space, so is the tolerance of the
952      * de Casteljau algorithm.
953      */
954     inData->tolerance *= face->units_per_EM;
955   }
956 
957   /* Parse the outline of the glyph */
958   if (FT_Outline_Decompose(outline, &outlineInterface, inData)) {
959     __glcRaiseError(GLC_RESOURCE_ERROR);
960     GLC_ARRAY_LENGTH(inData->vertexArray) = 0;
961     GLC_ARRAY_LENGTH(inData->endContour) = 0;
962     GLC_ARRAY_LENGTH(inData->vertexIndices) = 0;
963     GLC_ARRAY_LENGTH(inData->geomBatches) = 0;
964     return GL_FALSE;
965   }
966 
967   return GL_TRUE;
968 }
969 
970 
971 
972 /* Compute the lower power of 2 that is greater than value. It is used to
973  * determine the smaller texture than can contain a glyph.
974  */
975 static int __glcNextPowerOf2(int value)
976 {
977   int power = 0;
978 
979   for (power = 1; power < value; power <<= 1);
980 
981   return power;
982 }
983 
984 
985 
986 /* Get the size of the bitmap in which the glyph will be rendered */
987 GLboolean __glcFaceDescGetBitmapSize(__GLCfaceDescriptor* This, GLint* outWidth,
988                                      GLint *outHeight, GLfloat inScaleX,
989 				     GLfloat inScaleY, GLint* outPixBoundingBox,
990 				     int inFactor, __GLCcontext* inContext)
991 {
992   FT_Outline outline;
993   FT_Matrix matrix;
994   FT_BBox boundingBox;
995   FT_Face face = This->face;
996 
997   assert(face);
998 
999   outline = face->glyph->outline;
1000 
1001   if (inContext->renderState.renderStyle == GLC_BITMAP) {
1002     GLfloat *transform = inContext->bitmapMatrix;
1003 
1004     /* compute glyph dimensions */
1005     matrix.xx = (FT_Fixed)(transform[0] * 65536. / inScaleX);
1006     matrix.xy = (FT_Fixed)(transform[2] * 65536. / inScaleY);
1007     matrix.yx = (FT_Fixed)(transform[1] * 65536. / inScaleX);
1008     matrix.yy = (FT_Fixed)(transform[3] * 65536. / inScaleY);
1009   }
1010   else {
1011     matrix.xy = 0;
1012     matrix.yx = 0;
1013 
1014     if (inContext->enableState.glObjects) {
1015       matrix.xx = (FT_Fixed)((GLC_TEXTURE_SIZE << 16) / inScaleX);
1016       matrix.yy = (FT_Fixed)((GLC_TEXTURE_SIZE << 16) / inScaleY);
1017     }
1018     else {
1019       matrix.xx = 65536 >> inFactor;
1020       matrix.yy = 65536 >> inFactor;
1021     }
1022   }
1023 
1024   FT_Outline_Transform(&outline, &matrix);
1025   FT_Outline_Get_CBox(&outline, &boundingBox);
1026 
1027   if (inContext->renderState.renderStyle == GLC_BITMAP) {
1028     FT_Pos pitch = 0;
1029 
1030     outPixBoundingBox[0] = GLC_FLOOR_26_6(boundingBox.xMin);
1031     outPixBoundingBox[1] = GLC_FLOOR_26_6(boundingBox.yMin);
1032     outPixBoundingBox[2] = GLC_CEIL_26_6(boundingBox.xMax);
1033     outPixBoundingBox[3] = GLC_CEIL_26_6(boundingBox.yMax);
1034 
1035     /* Calculate pitch to upper 8 byte boundary for 1 bit/pixel, i.e. ceil() */
1036     pitch = (outPixBoundingBox[2] - outPixBoundingBox[0] + 511) >> 9;
1037 
1038     *outWidth = pitch << 3;
1039     *outHeight = (outPixBoundingBox[3] - outPixBoundingBox[1]) >> 6;
1040   }
1041   else {
1042     GLint width = 0;
1043     GLint height = 0;
1044 
1045     if (inContext->enableState.glObjects) {
1046       GLfloat ratioX = 0.f;
1047       GLfloat ratioY = 0.f;
1048       GLfloat ratio = 0.f;
1049 
1050       width = boundingBox.xMax - boundingBox.xMin;
1051       height = boundingBox.yMax - boundingBox.yMin;
1052 
1053       ratioX = width / (64.f * GLC_TEXTURE_SIZE);
1054       ratioY = height / (64.f * GLC_TEXTURE_SIZE);
1055 
1056       ratioX = (ratioX > 1.f) ? ratioX : 1.f;
1057       ratioY = (ratioY > 1.f) ? ratioY : 1.f;
1058       ratio = ((ratioX > ratioY) ? ratioX : ratioY);
1059 
1060       *outWidth = GLC_TEXTURE_SIZE;
1061       *outHeight = GLC_TEXTURE_SIZE;
1062 
1063       outline.flags |= FT_OUTLINE_HIGH_PRECISION;
1064 
1065       if (ratio > 1.f) {
1066 	outPixBoundingBox[0] = boundingBox.xMin
1067 	  - ((GLint)((GLC_TEXTURE_SIZE << 5) - (width * 0.5f)) * ratio);
1068 	outPixBoundingBox[1] = boundingBox.yMin
1069 	  - ((GLint)((GLC_TEXTURE_SIZE << 5) - (height * 0.5f)) * ratio);
1070 	outPixBoundingBox[2] = outPixBoundingBox[0]
1071 	  + ((GLint)((GLC_TEXTURE_SIZE << 6) * ratio));
1072 	outPixBoundingBox[3] = outPixBoundingBox[1]
1073 	  + ((GLint)((GLC_TEXTURE_SIZE << 6) * ratio));
1074 
1075 	matrix.xx = (FT_Fixed)(65536.f / ratio);
1076 	matrix.yy = matrix.xx;
1077 
1078 	FT_Outline_Transform(&outline, &matrix);
1079 	FT_Outline_Get_CBox(&outline, &boundingBox);
1080       }
1081       else {
1082 	outPixBoundingBox[0] = boundingBox.xMin
1083 	  - ((GLC_TEXTURE_SIZE << 5) - (width >> 1));
1084 	outPixBoundingBox[1] = boundingBox.yMin
1085 	  - ((GLC_TEXTURE_SIZE << 5) - (height >> 1));
1086 	outPixBoundingBox[2] = outPixBoundingBox[0] + ((GLC_TEXTURE_SIZE - 1) << 6);
1087 	outPixBoundingBox[3] = outPixBoundingBox[1] + ((GLC_TEXTURE_SIZE - 1) << 6);
1088       }
1089     }
1090     else {
1091       width = (GLC_CEIL_26_6(boundingBox.xMax)
1092 	       - GLC_FLOOR_26_6(boundingBox.xMin)) >> 6;
1093       height = (GLC_CEIL_26_6(boundingBox.yMax)
1094 		- GLC_FLOOR_26_6(boundingBox.yMin)) >> 6;
1095 
1096       *outWidth = __glcNextPowerOf2(width);
1097       *outHeight = __glcNextPowerOf2(height);
1098 
1099       *outWidth = (*outWidth > inContext->texture.width)
1100 	? *outWidth : inContext->texture.width;
1101       *outHeight = (*outHeight > inContext->texture.heigth)
1102 	? *outHeight : inContext->texture.heigth;
1103 
1104       if (*outWidth - width <= 1) *outWidth <<= 1;
1105       if (*outHeight - height <= 1) *outHeight <<= 1;
1106 
1107       /* If the texture size is too small then give up */
1108       if ((*outWidth < 4) || (*outHeight < 4))
1109         return GL_FALSE;
1110 
1111       outPixBoundingBox[0] = GLC_FLOOR_26_6(boundingBox.xMin)
1112 	- (((*outWidth - width) >> 1 ) << 6);
1113       outPixBoundingBox[1] = GLC_FLOOR_26_6(boundingBox.yMin)
1114 	- (((*outHeight - height) >> 1) << 6);
1115       outPixBoundingBox[2] = outPixBoundingBox[0] + ((*outWidth - 1) << 6);
1116       outPixBoundingBox[3] = outPixBoundingBox[1] + ((*outHeight - 1) << 6);
1117     }
1118   }
1119 
1120   return GL_TRUE;
1121 }
1122 
1123 
1124 
1125 /* Render the glyph in a bitmap */
1126 GLboolean __glcFaceDescGetBitmap(__GLCfaceDescriptor* This, GLint inWidth,
1127                                  GLint inHeight, void* inBuffer,
1128                                  __GLCcontext* inContext)
1129 {
1130   FT_Outline outline;
1131   FT_BBox boundingBox;
1132   FT_Bitmap pixmap;
1133   FT_Matrix matrix;
1134   FT_Pos dx = 0, dy = 0;
1135   FT_Face face = This->face;
1136   FT_Pos width = 0, height = 0;
1137 
1138   assert(face);
1139 
1140   outline = face->glyph->outline;
1141   FT_Outline_Get_CBox(&outline, &boundingBox);
1142 
1143   if ((inContext->renderState.renderStyle == GLC_BITMAP)
1144       || (!inContext->enableState.glObjects)) {
1145     dx = GLC_FLOOR_26_6(boundingBox.xMin);
1146     dy = GLC_FLOOR_26_6(boundingBox.yMin);
1147     if (inContext->renderState.renderStyle == GLC_TEXTURE) {
1148       width = (GLC_CEIL_26_6(boundingBox.xMax) - dx) >> 6;
1149       height = (GLC_CEIL_26_6(boundingBox.yMax) - dy) >> 6;
1150       dx -= (((inWidth - width) >> 1) << 6);
1151       dy -= (((inHeight - height) >> 1) << 6);
1152     }
1153   }
1154   else {
1155     dx = boundingBox.xMin;
1156     dy = boundingBox.yMin;
1157     width = boundingBox.xMax - dx;
1158     height = boundingBox.yMax - dy;
1159     dx -= (inWidth << 5) - (width >> 1);
1160     dy -= (inHeight << 5) - (height >> 1);
1161   }
1162 
1163   pixmap.width = inWidth;
1164   pixmap.rows = inHeight;
1165   pixmap.buffer = (unsigned char*)inBuffer;
1166 
1167   if (inContext->renderState.renderStyle == GLC_BITMAP) {
1168     /* Calculate pitch to upper 8 byte boundary for 1 bit/pixel, i.e. ceil() */
1169     pixmap.pitch = -(pixmap.width >> 3);
1170 
1171     /* Fill the pixmap descriptor and the pixmap buffer */
1172     pixmap.pixel_mode = ft_pixel_mode_mono;	/* Monochrome rendering */
1173   }
1174   else {
1175     /* Flip the picture */
1176     pixmap.pitch = -pixmap.width; /* 8 bits/pixel */
1177 
1178     /* Fill the pixmap descriptor and the pixmap buffer */
1179     pixmap.pixel_mode = ft_pixel_mode_grays; /* Anti-aliased rendering */
1180     pixmap.num_grays = 256;
1181   }
1182 
1183   /* fill the pixmap buffer with the background color */
1184   memset(pixmap.buffer, 0, - pixmap.rows * pixmap.pitch);
1185 
1186   /* translate the outline to match (0,0) with the glyph's lower left
1187    * corner
1188    */
1189   FT_Outline_Translate(&outline, -dx, -dy);
1190 
1191   /* render the glyph */
1192   if (FT_Outline_Get_Bitmap(inContext->library, &outline, &pixmap)) {
1193     __glcRaiseError(GLC_RESOURCE_ERROR);
1194     return GL_FALSE;
1195   }
1196 
1197   if (inContext->renderState.renderStyle != GLC_BITMAP) {
1198     /* Prepare the outline for the next mipmap level :
1199      * a. Restore the outline initial position
1200      */
1201     FT_Outline_Translate(&outline, dx, dy);
1202 
1203     /* b. Divide the character size by 2. */
1204     matrix.xx = 32768; /* 0.5 in FT_Fixed type */
1205     matrix.xy = 0;
1206     matrix.yx = 0;
1207     matrix.yy = 32768;
1208     FT_Outline_Transform(&outline, &matrix);
1209   }
1210 
1211   return GL_TRUE;
1212 }
1213 
1214 
1215 
1216 /* Chek if the outline of the glyph is empty (which means it is a spacing
1217  * character).
1218  */
1219 GLboolean __glcFaceDescOutlineEmpty(__GLCfaceDescriptor* This)
1220 {
1221   FT_Outline outline = This->face->glyph->outline;
1222 
1223   return outline.n_points ? GL_TRUE : GL_FALSE;
1224 }
1225 
1226 
1227 
1228 /* Get the CharMap of the face descriptor */
1229 __GLCcharMap* __glcFaceDescGetCharMap(__GLCfaceDescriptor* This,
1230 				      __GLCcontext* inContext)
1231 {
1232   FcResult result = FcResultMatch;
1233   FcCharSet* charSet = NULL;
1234   FcCharSet* newCharSet = NULL;
1235   __GLCcharMap* charMap = __glcCharMapCreate(NULL, inContext);
1236 
1237   if (!charMap)
1238     return NULL;
1239 
1240   result = FcPatternGetCharSet(This->pattern, FC_CHARSET, 0, &charSet);
1241   assert(result != FcResultTypeMismatch);
1242 
1243   newCharSet = FcCharSetCopy(charSet);
1244   if (!newCharSet) {
1245     __glcCharMapDestroy(charMap);
1246     return NULL;
1247   }
1248 
1249   FcCharSetDestroy(charMap->charSet);
1250   charMap->charSet = newCharSet;
1251 
1252   return charMap;
1253 }
1254