1 /*
2  * FTGL - OpenGL font library
3  *
4  * Copyright (c) 2001-2004 Henry Maddocks <ftgl@opengl.geek.nz>
5  * Copyright (c) 2008 Sam Hocevar <sam@hocevar.net>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 #include "config.h"
28 
29 #include "FTFace.h"
30 #include "FTCleanup.h"
31 #include "FTGL/FTLibrary.h"
32 
33 #include FT_TRUETYPE_TABLES_H
34 
FTFace(const char * fontFilePath,bool precomputeKerning)35 FTFace::FTFace(const char* fontFilePath, bool precomputeKerning)
36 :   numGlyphs(0),
37     fontEncodingList(0),
38     kerningCache(0),
39     err(0)
40 {
41     const FT_Long DEFAULT_FACE_INDEX = 0;
42     ftFace = new FT_Face;
43 
44     err = FT_New_Face(*FTLibrary::Instance().GetLibrary(), fontFilePath,
45                       DEFAULT_FACE_INDEX, ftFace);
46     if(err)
47     {
48         delete ftFace;
49         ftFace = 0;
50         return;
51     }
52 
53     FTCleanup::Instance()->RegisterObject(&ftFace);
54 
55     numGlyphs = (*ftFace)->num_glyphs;
56     hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0);
57 
58     if(hasKerningTable && precomputeKerning)
59     {
60         BuildKerningCache();
61     }
62 }
63 
64 
FTFace(const unsigned char * pBufferBytes,size_t bufferSizeInBytes,bool precomputeKerning)65 FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes,
66                bool precomputeKerning)
67 :   numGlyphs(0),
68     fontEncodingList(0),
69     kerningCache(0),
70     err(0)
71 {
72     const FT_Long DEFAULT_FACE_INDEX = 0;
73     ftFace = new FT_Face;
74 
75     err = FT_New_Memory_Face(*FTLibrary::Instance().GetLibrary(),
76                              (FT_Byte const *)pBufferBytes, (FT_Long)bufferSizeInBytes,
77                              DEFAULT_FACE_INDEX, ftFace);
78     if(err)
79     {
80         delete ftFace;
81         ftFace = 0;
82         return;
83     }
84 
85     FTCleanup::Instance()->RegisterObject(&ftFace);
86 
87     numGlyphs = (*ftFace)->num_glyphs;
88     hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0);
89 
90     if(hasKerningTable && precomputeKerning)
91     {
92         BuildKerningCache();
93     }
94 }
95 
96 
~FTFace()97 FTFace::~FTFace()
98 {
99     delete[] kerningCache;
100 
101     if(ftFace)
102     {
103         FTCleanup::Instance()->UnregisterObject(&ftFace);
104 
105         FT_Done_Face(*ftFace);
106         delete ftFace;
107         ftFace = 0;
108     }
109 }
110 
111 
Attach(const char * fontFilePath)112 bool FTFace::Attach(const char* fontFilePath)
113 {
114     err = FT_Attach_File(*ftFace, fontFilePath);
115     return !err;
116 }
117 
118 
Attach(const unsigned char * pBufferBytes,size_t bufferSizeInBytes)119 bool FTFace::Attach(const unsigned char *pBufferBytes,
120                     size_t bufferSizeInBytes)
121 {
122     FT_Open_Args open;
123 
124     open.flags = FT_OPEN_MEMORY;
125     open.memory_base = (FT_Byte const *)pBufferBytes;
126     open.memory_size = (FT_Long)bufferSizeInBytes;
127 
128     err = FT_Attach_Stream(*ftFace, &open);
129     return !err;
130 }
131 
132 
Size(const unsigned int size,const unsigned int res)133 const FTSize& FTFace::Size(const unsigned int size, const unsigned int res)
134 {
135     charSize.CharSize(ftFace, size, res, res);
136     err = charSize.Error();
137 
138     return charSize;
139 }
140 
141 
CharMapCount() const142 unsigned int FTFace::CharMapCount() const
143 {
144     return (*ftFace)->num_charmaps;
145 }
146 
147 
CharMapList()148 FT_Encoding* FTFace::CharMapList()
149 {
150     if(0 == fontEncodingList)
151     {
152         fontEncodingList = new FT_Encoding[CharMapCount()];
153         for(size_t i = 0; i < CharMapCount(); ++i)
154         {
155             fontEncodingList[i] = (*ftFace)->charmaps[i]->encoding;
156         }
157     }
158 
159     return fontEncodingList;
160 }
161 
162 
KernAdvance(unsigned int index1,unsigned int index2)163 FTPoint FTFace::KernAdvance(unsigned int index1, unsigned int index2)
164 {
165     FTGL_DOUBLE x, y;
166 
167     if(!hasKerningTable || !index1 || !index2)
168     {
169         return FTPoint(0.0, 0.0);
170     }
171 
172     if(kerningCache && index1 < FTFace::MAX_PRECOMPUTED
173         && index2 < FTFace::MAX_PRECOMPUTED)
174     {
175         x = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1)];
176         y = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1) + 1];
177         return FTPoint(x, y);
178     }
179 
180     FT_Vector kernAdvance;
181     kernAdvance.x = kernAdvance.y = 0;
182 
183     err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted,
184                          &kernAdvance);
185     if(err)
186     {
187         return FTPoint(0.0f, 0.0f);
188     }
189 
190     x = static_cast<float>(kernAdvance.x) / 64.0f;
191     y = static_cast<float>(kernAdvance.y) / 64.0f;
192 
193     return FTPoint(x, y);
194 }
195 
196 
Glyph(unsigned int index,FT_Int load_flags)197 FT_GlyphSlot FTFace::Glyph(unsigned int index, FT_Int load_flags)
198 {
199     err = FT_Load_Glyph(*ftFace, index, load_flags);
200     if(err)
201     {
202         return NULL;
203     }
204 
205     return (*ftFace)->glyph;
206 }
207 
208 
BuildKerningCache()209 void FTFace::BuildKerningCache()
210 {
211     FT_Vector kernAdvance;
212     kernAdvance.x = 0;
213     kernAdvance.y = 0;
214     kerningCache = new FTGL_DOUBLE[FTFace::MAX_PRECOMPUTED
215                                     * FTFace::MAX_PRECOMPUTED * 2];
216     for(unsigned int j = 0; j < FTFace::MAX_PRECOMPUTED; j++)
217     {
218         for(unsigned int i = 0; i < FTFace::MAX_PRECOMPUTED; i++)
219         {
220             err = FT_Get_Kerning(*ftFace, i, j, ft_kerning_unfitted,
221                                  &kernAdvance);
222             if(err)
223             {
224                 delete[] kerningCache;
225                 kerningCache = NULL;
226                 return;
227             }
228 
229             kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i)] =
230                                 static_cast<FTGL_DOUBLE>(kernAdvance.x) / 64.0;
231             kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i) + 1] =
232                                 static_cast<FTGL_DOUBLE>(kernAdvance.y) / 64.0;
233         }
234     }
235 }
236 
237