]> icculus.org git repositories - divverent/darkplaces.git/blob - ft2.c
some comments and structuring
[divverent/darkplaces.git] / ft2.c
1 /* FreeType 2 and UTF-8 encoding support for
2  * DarkPlaces
3  */
4 #include "quakedef.h"
5
6 #include "ft2.h"
7
8 #include "ft2_defs.h"
9
10 /*
11 ================================================================================
12 Function definitions. Taken from the freetype2 headers.
13 ================================================================================
14 */
15
16
17 FT_EXPORT( FT_Error )
18 (*qFT_Init_FreeType)( FT_Library  *alibrary );
19 FT_EXPORT( FT_Error )
20 (*qFT_Done_FreeType)( FT_Library  library );
21 FT_EXPORT( FT_Error )
22 (*qFT_New_Face)( FT_Library   library,
23                  const char*  filepathname,
24                  FT_Long      face_index,
25                  FT_Face     *aface );
26 FT_EXPORT( FT_Error )
27 (*qFT_New_Memory_Face)( FT_Library      library,
28                         const FT_Byte*  file_base,
29                         FT_Long         file_size,
30                         FT_Long         face_index,
31                         FT_Face        *aface );
32 FT_EXPORT( FT_Error )
33 (*qFT_Done_Face)( FT_Face  face );
34 FT_EXPORT( FT_Error )
35 (*qFT_Select_Size)( FT_Face  face,
36                     FT_Int   strike_index );
37 FT_EXPORT( FT_Error )
38 (*qFT_Request_Size)( FT_Face          face,
39                      FT_Size_Request  req );
40 FT_EXPORT( FT_Error )
41 (*qFT_Set_Char_Size)( FT_Face     face,
42                       FT_F26Dot6  char_width,
43                       FT_F26Dot6  char_height,
44                       FT_UInt     horz_resolution,
45                       FT_UInt     vert_resolution );
46 FT_EXPORT( FT_Error )
47 (*qFT_Set_Pixel_Sizes)( FT_Face  face,
48                         FT_UInt  pixel_width,
49                         FT_UInt  pixel_height );
50 FT_EXPORT( FT_Error )
51 (*qFT_Load_Glyph)( FT_Face   face,
52                    FT_UInt   glyph_index,
53                    FT_Int32  load_flags );
54 FT_EXPORT( FT_Error )
55 (*qFT_Load_Char)( FT_Face   face,
56                   FT_ULong  char_code,
57                   FT_Int32  load_flags );
58 FT_EXPORT( FT_UInt )
59 (*qFT_Get_Char_Index)( FT_Face   face,
60                        FT_ULong  charcode );
61 FT_EXPORT( FT_Error )
62 (*qFT_Render_Glyph)( FT_GlyphSlot    slot,
63                      FT_Render_Mode  render_mode );
64
65 /*
66 ================================================================================
67 Support for dynamically loading the FreeType2 library
68 ================================================================================
69 */
70
71 static dllfunction_t ft2funcs[] =
72 {
73         {"FT_Init_FreeType",            (void **) &qFT_Init_FreeType},
74         {"FT_Done_FreeType",            (void **) &qFT_Done_FreeType},
75         {"FT_New_Face",                 (void **) &qFT_New_Face},
76         {"FT_New_Memory_Face",          (void **) &qFT_New_Memory_Face},
77         {"FT_Done_Face",                (void **) &qFT_Done_Face},
78         {"FT_Select_Size",              (void **) &qFT_Select_Size},
79         {"FT_Request_Size",             (void **) &qFT_Request_Size},
80         {"FT_Set_Char_Size",            (void **) &qFT_Set_Char_Size},
81         {"FT_Set_Pixel_Sizes",          (void **) &qFT_Set_Pixel_Sizes},
82         {"FT_Load_Glyph",               (void **) &qFT_Load_Glyph},
83         {"FT_Load_Char",                (void **) &qFT_Load_Char},
84         {"FT_Get_Char_Index",           (void **) &qFT_Get_Char_Index},
85         {"FT_Render_Glyph",             (void **) &qFT_Render_Glyph},
86         {NULL, NULL}
87 };
88
89 /// Handle for FreeType2 DLL
90 static dllhandle_t ft2_dll = NULL;
91
92 /*
93 ====================
94 FT2_CloseLibrary
95
96 Unload the FreeType2 DLL
97 ====================
98 */
99 void FT2_CloseLibrary (void)
100 {
101         Sys_UnloadLibrary (&ft2_dll);
102 }
103
104
105 /*
106 ====================
107 FT2_OpenLibrary
108
109 Try to load the FreeType2 DLL
110 ====================
111 */
112 qboolean FT2_OpenLibrary (void)
113 {
114         const char* dllnames [] =
115         {
116 #if defined(WIN64)
117                 #error path for freetype 2 dll
118 #elif defined(WIN32)
119                 #error path for freetype 2 dll
120 #elif defined(MACOSX)
121                 "libfreetype.dylib",
122 #else
123                 "libfreetype.so.6",
124                 "libfreetype.so",
125 #endif
126                 NULL
127         };
128
129         // Already loaded?
130         if (ft2_dll)
131                 return true;
132
133         // Load the DLL
134         return Sys_LoadLibrary (dllnames, &ft2_dll, ft2funcs);
135 }
136
137 /*
138 ================================================================================
139 UTF-8 encoding and decoding functions follow.
140 ================================================================================
141 */
142
143 /** Get the number of characters in in an UTF-8 string.
144  * @param _s    An utf-8 encoded null-terminated string.
145  * @return      The number of unicode characters in the string.
146  */
147 size_t u8_strlen(const char *_s)
148 {
149         size_t len = 0;
150         unsigned char *s = (unsigned char*)_s;
151         while (*s)
152         {
153                 // ascii char
154                 if (*s <= 0x7F)
155                 {
156                         ++len;
157                         ++s;
158                         continue;
159                 }
160
161                 // start of a wide character
162                 if (*s & 0xC0)
163                 {
164                         ++len;
165                         for (++s; *s >= 0x80 && *s <= 0xC0; ++s);
166                         continue;
167                 }
168
169                 // part of a wide character, we ignore that one
170                 if (*s <= 0xBF) // 10111111
171                 {
172                         ++s;
173                         continue;
174                 }
175         }
176         return len;
177 }
178
179 /** Fetch a character from an utf-8 encoded string.
180  * @param _s      The start of an utf-8 encoded multi-byte character.
181  * @param _end    Will point to after the first multi-byte character.
182  * @return        The 32-bit integer representation of the first multi-byte character.
183  */
184 Uchar u8_getchar(const char *_s, const char **_end)
185 {
186         const unsigned char *s = (unsigned char*)_s;
187         Uchar u;
188         unsigned char mask;
189         unsigned char v;
190
191         if (*s < 0x80)
192         {
193                 if (_end)
194                         *_end = _s + 1;
195                 return (U_int32)*s;
196         }
197
198         if (*s < 0xC0)
199         {
200                 // starting within a wide character - skip it and retrieve the one after it
201                 for (++s; *s >= 0x80 && *s < 0xC0; ++s);
202                 // or we could return '?' here?
203         }
204
205         u = 0;
206         mask = 0x7F;
207         v = *s & mask;
208         for (mask >>= 1; v > (*s & mask); mask >>= 1)
209                 v = (*s & mask);
210         u = (Uchar)(*s & mask);
211         for (++s; *s >= 0x80 && *s < 0xC0; ++s)
212                 u = (u << 6) | (*s & 0x3F);
213
214         if (_end)
215                 *_end = (const char*)s;
216
217         return u;
218 }
219
220 /** Encode a wide-character into utf-8.
221  * @param w        The wide character to encode.
222  * @param to       The target buffer the utf-8 encoded string is stored to.
223  * @param maxlen   The maximum number of bytes that fit into the target buffer.
224  * @return         Number of bytes written to the buffer, or less or equal to 0 if the buffer is too small.
225  */
226 int u8_fromchar(Uchar w, char *to, size_t maxlen)
227 {
228         size_t i, j;
229         char bt;
230         char tmp[16];
231
232         if (maxlen < 1)
233                 return -2;
234
235         if (w < 0x80)
236         {
237                 to[0] = (char)w;
238                 if (maxlen < 2)
239                         return -1;
240                 to[1] = 0;
241                 return 1;
242         }
243
244         // check how much space we need and store data into a
245         // temp buffer - this is faster than recalculating again
246         i = 0;
247         bt = 0;
248         while (w)
249         {
250                 tmp[i++] = 0x80 | (w & 0x3F);
251                 bt = (bt >> 1) | 0x80;
252                 w >>= 6;
253                 // see if we still fit into the target buffer
254                 if (i+1 >= maxlen) // +1 for the \0
255                         return -i;
256
257                 // there are no characters which take up that much space yet
258                 // and there won't be for the next many many years, still... let's be safe
259                 if (i >= sizeof(tmp))
260                         return -1;
261         }
262         tmp[i-1] |= bt;
263         for (j = 0; j < i; ++j)
264         {
265                 to[i-j-1] = tmp[j];
266         }
267
268         to[i] = 0;
269         return i;
270 }
271
272 /** Convert a utf-8 multibyte string to a wide character string.
273  * @param wcs       The target wide-character buffer.
274  * @param mb        The utf-8 encoded multibyte string to convert.
275  * @param maxlen    The maximum number of wide-characters that fit into the target buffer.
276  * @return          The number of characters written to the target buffer.
277  */
278 size_t u8_mbstowcs(Uchar *wcs, const char *mb, size_t maxlen)
279 {
280         size_t i;
281         for (i = 0; *mb && i < maxlen; ++i)
282                 *wcs++ = u8_getchar(mb, &mb);
283         if (i < maxlen)
284                 *wcs = 0;
285         return i;
286 }
287
288 /** Convert a wide-character string to a utf-8 multibyte string.
289  * @param mb      The target buffer the utf-8 string is written to.
290  * @param wcs     The wide-character string to convert.
291  * @param maxlen  The number bytes that fit into the multibyte target buffer.
292  * @return        The number of bytes written, not including the terminating \0
293  */
294 size_t u8_wcstombs(char *mb, const Uchar *wcs, size_t maxlen)
295 {
296         size_t i;
297         const char *start = mb;
298         for (i = 0; *wcs && i < maxlen; ++i)
299         {
300                 int len;
301                 if ( (len = u8_fromchar(*wcs++, mb, maxlen - i)) < 0)
302                         return (mb - start);
303                 mb += len;
304         }
305         if (i < maxlen)
306                 *mb = 0;
307         return (mb - start);
308 }