1 | #include "register_font.h"
|
2 |
|
3 | #include <pango/pangocairo.h>
|
4 | #include <pango/pango-fontmap.h>
|
5 | #include <pango/pango.h>
|
6 |
|
7 | #ifdef __APPLE__
|
8 | #include <CoreText/CoreText.h>
|
9 | #elif defined(_WIN32)
|
10 | #include <windows.h>
|
11 | #else
|
12 | #include <fontconfig/fontconfig.h>
|
13 | #endif
|
14 |
|
15 | #include <ft2build.h>
|
16 | #include FT_FREETYPE_H
|
17 | #include FT_TRUETYPE_TABLES_H
|
18 | #include FT_SFNT_NAMES_H
|
19 | #include FT_TRUETYPE_IDS_H
|
20 | #ifndef FT_SFNT_OS2
|
21 | #define FT_SFNT_OS2 ft_sfnt_os2
|
22 | #endif
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | #ifdef __APPLE__
|
28 | #define PREFERRED_PLATFORM_ID TT_PLATFORM_MACINTOSH
|
29 | #define PREFERRED_ENCODING_ID TT_MAC_ID_ROMAN
|
30 | #else
|
31 | #define PREFERRED_PLATFORM_ID TT_PLATFORM_MICROSOFT
|
32 | #define PREFERRED_ENCODING_ID TT_MS_ID_UNICODE_CS
|
33 | #endif
|
34 |
|
35 | #define IS_PREFERRED_ENC(X) \
|
36 | X.platform_id == PREFERRED_PLATFORM_ID && X.encoding_id == PREFERRED_ENCODING_ID
|
37 |
|
38 | #define GET_NAME_RANK(X) \
|
39 | (IS_PREFERRED_ENC(X) ? 1 : 0) + (X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0)
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | char *
|
47 | to_utf8(FT_Byte* buf, FT_UInt len, FT_UShort pid, FT_UShort eid) {
|
48 | size_t ret_len = len * 4;
|
49 | char *ret = (char*)malloc(ret_len + 1);
|
50 |
|
51 | if (!ret) return NULL;
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | char const *fromcode;
|
58 |
|
59 | if (pid == TT_PLATFORM_MACINTOSH && eid == TT_MAC_ID_ROMAN) {
|
60 | fromcode = "MAC";
|
61 | } else if (pid == TT_PLATFORM_MICROSOFT && eid == TT_MS_ID_UNICODE_CS) {
|
62 | fromcode = "UTF-16BE";
|
63 | } else {
|
64 | free(ret);
|
65 | return NULL;
|
66 | }
|
67 |
|
68 | GIConv cd = g_iconv_open("UTF-8", fromcode);
|
69 |
|
70 | if (cd == (GIConv)-1) {
|
71 | free(ret);
|
72 | return NULL;
|
73 | }
|
74 |
|
75 | size_t inbytesleft = len;
|
76 | size_t outbytesleft = ret_len;
|
77 |
|
78 | size_t n_converted = g_iconv(cd, (char**)&buf, &inbytesleft, &ret, &outbytesleft);
|
79 |
|
80 | ret -= ret_len - outbytesleft;
|
81 | buf -= len - inbytesleft;
|
82 |
|
83 | if (n_converted == (size_t)-1) {
|
84 | free(ret);
|
85 | return NULL;
|
86 | } else {
|
87 | ret[ret_len - outbytesleft] = '\0';
|
88 | return ret;
|
89 | }
|
90 | }
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | typedef struct _NameDef {
|
98 | const char *buf;
|
99 | int rank;
|
100 | } NameDef;
|
101 |
|
102 | gint
|
103 | _name_def_compare(gconstpointer a, gconstpointer b) {
|
104 | return ((NameDef*)a)->rank > ((NameDef*)b)->rank ? -1 : 1;
|
105 | }
|
106 |
|
107 |
|
108 |
|
109 | void
|
110 | _free_g_list_item(gpointer data, gpointer user_data) {
|
111 | NameDef *d = (NameDef *)data;
|
112 | free((void *)(d->buf));
|
113 | }
|
114 |
|
115 | void
|
116 | _g_list_free_full(GList *list) {
|
117 | g_list_foreach(list, _free_g_list_item, NULL);
|
118 | g_list_free(list);
|
119 | }
|
120 |
|
121 | char *
|
122 | get_family_name(FT_Face face) {
|
123 | FT_SfntName name;
|
124 | GList *list = NULL;
|
125 | char *utf8name = NULL;
|
126 |
|
127 | for (unsigned i = 0; i < FT_Get_Sfnt_Name_Count(face); ++i) {
|
128 | FT_Get_Sfnt_Name(face, i, &name);
|
129 |
|
130 | if (name.name_id == TT_NAME_ID_FONT_FAMILY || name.name_id == TT_NAME_ID_PREFERRED_FAMILY) {
|
131 | char *buf = to_utf8(name.string, name.string_len, name.platform_id, name.encoding_id);
|
132 |
|
133 | if (buf) {
|
134 | NameDef *d = (NameDef*)malloc(sizeof(NameDef));
|
135 | d->buf = (const char*)buf;
|
136 | d->rank = GET_NAME_RANK(name);
|
137 |
|
138 | list = g_list_insert_sorted(list, (gpointer)d, _name_def_compare);
|
139 | }
|
140 | }
|
141 | }
|
142 |
|
143 | GList *best_def = g_list_first(list);
|
144 | if (best_def) utf8name = (char*) strdup(((NameDef*)best_def->data)->buf);
|
145 | if (list) _g_list_free_full(list);
|
146 |
|
147 | return utf8name;
|
148 | }
|
149 |
|
150 | PangoWeight
|
151 | get_pango_weight(FT_UShort weight) {
|
152 | switch (weight) {
|
153 | case 100: return PANGO_WEIGHT_THIN;
|
154 | case 200: return PANGO_WEIGHT_ULTRALIGHT;
|
155 | case 300: return PANGO_WEIGHT_LIGHT;
|
156 | #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 36, 7)
|
157 | case 350: return PANGO_WEIGHT_SEMILIGHT;
|
158 | #endif
|
159 | case 380: return PANGO_WEIGHT_BOOK;
|
160 | case 400: return PANGO_WEIGHT_NORMAL;
|
161 | case 500: return PANGO_WEIGHT_MEDIUM;
|
162 | case 600: return PANGO_WEIGHT_SEMIBOLD;
|
163 | case 700: return PANGO_WEIGHT_BOLD;
|
164 | case 800: return PANGO_WEIGHT_ULTRABOLD;
|
165 | case 900: return PANGO_WEIGHT_HEAVY;
|
166 | case 1000: return PANGO_WEIGHT_ULTRAHEAVY;
|
167 | default: return PANGO_WEIGHT_NORMAL;
|
168 | }
|
169 | }
|
170 |
|
171 | PangoStretch
|
172 | get_pango_stretch(FT_UShort width) {
|
173 | switch (width) {
|
174 | case 1: return PANGO_STRETCH_ULTRA_CONDENSED;
|
175 | case 2: return PANGO_STRETCH_EXTRA_CONDENSED;
|
176 | case 3: return PANGO_STRETCH_CONDENSED;
|
177 | case 4: return PANGO_STRETCH_SEMI_CONDENSED;
|
178 | case 5: return PANGO_STRETCH_NORMAL;
|
179 | case 6: return PANGO_STRETCH_SEMI_EXPANDED;
|
180 | case 7: return PANGO_STRETCH_EXPANDED;
|
181 | case 8: return PANGO_STRETCH_EXTRA_EXPANDED;
|
182 | case 9: return PANGO_STRETCH_ULTRA_EXPANDED;
|
183 | default: return PANGO_STRETCH_NORMAL;
|
184 | }
|
185 | }
|
186 |
|
187 | PangoStyle
|
188 | get_pango_style(FT_Long flags) {
|
189 | if (flags & FT_STYLE_FLAG_ITALIC) {
|
190 | return PANGO_STYLE_ITALIC;
|
191 | } else {
|
192 | return PANGO_STYLE_NORMAL;
|
193 | }
|
194 | }
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | PangoFontDescription *
|
201 | get_pango_font_description(unsigned char* filepath) {
|
202 | FT_Library library;
|
203 | FT_Face face;
|
204 | PangoFontDescription *desc = pango_font_description_new();
|
205 |
|
206 | if (!FT_Init_FreeType(&library) && !FT_New_Face(library, (const char*)filepath, 0, &face)) {
|
207 | TT_OS2 *table = (TT_OS2*)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
|
208 | if (table) {
|
209 | char *family = get_family_name(face);
|
210 |
|
211 | if (!family) {
|
212 | pango_font_description_free(desc);
|
213 | FT_Done_Face(face);
|
214 | FT_Done_FreeType(library);
|
215 |
|
216 | return NULL;
|
217 | }
|
218 |
|
219 | pango_font_description_set_family_static(desc, family);
|
220 | pango_font_description_set_weight(desc, get_pango_weight(table->usWeightClass));
|
221 | pango_font_description_set_stretch(desc, get_pango_stretch(table->usWidthClass));
|
222 | pango_font_description_set_style(desc, get_pango_style(face->style_flags));
|
223 |
|
224 | FT_Done_Face(face);
|
225 | FT_Done_FreeType(library);
|
226 |
|
227 | return desc;
|
228 | }
|
229 | }
|
230 |
|
231 | pango_font_description_free(desc);
|
232 |
|
233 | return NULL;
|
234 | }
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 | bool
|
241 | register_font(unsigned char *filepath) {
|
242 | bool success;
|
243 |
|
244 | #ifdef __APPLE__
|
245 | CFURLRef filepathUrl = CFURLCreateFromFileSystemRepresentation(NULL, filepath, strlen((char*)filepath), false);
|
246 | success = CTFontManagerRegisterFontsForURL(filepathUrl, kCTFontManagerScopeProcess, NULL);
|
247 | #elif defined(_WIN32)
|
248 | success = AddFontResourceEx((LPCSTR)filepath, FR_PRIVATE, 0) != 0;
|
249 | #else
|
250 | success = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(filepath));
|
251 | #endif
|
252 |
|
253 | if (!success) return false;
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | pango_cairo_font_map_set_default(NULL);
|
259 |
|
260 | return true;
|
261 | }
|
262 |
|