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