main
font.c
1/* wld: font.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "wld-private.h"
25
26#include <fontconfig/fcfreetype.h>
27
28EXPORT
29struct wld_font_context *
30wld_font_create_context()
31{
32 struct wld_font_context *context;
33
34 context = malloc(sizeof *context);
35
36 if (!context)
37 goto error0;
38
39 if (FT_Init_FreeType(&context->library) != 0) {
40 DEBUG("Failed to initialize FreeType library\n");
41
42 goto error1;
43 }
44
45 return context;
46
47error1:
48 free(context);
49error0:
50 return NULL;
51}
52
53EXPORT
54void
55wld_font_destroy_context(struct wld_font_context *context)
56{
57 FT_Done_FreeType(context->library);
58 free(context);
59}
60
61EXPORT
62struct wld_font *
63wld_font_open_name(struct wld_font_context *context, const char *name)
64{
65 FcPattern *pattern, *match;
66 FcResult result;
67
68 DEBUG("Opening font with name: %s\n", name);
69
70 pattern = FcNameParse((const FcChar8 *)name);
71 FcConfigSubstitute(NULL, pattern, FcMatchPattern);
72 FcDefaultSubstitute(pattern);
73
74 match = FcFontMatch(NULL, pattern, &result);
75
76 if (!match)
77 return NULL;
78
79 return wld_font_open_pattern(context, match);
80}
81
82EXPORT
83struct wld_font *
84wld_font_open_pattern(struct wld_font_context *context, FcPattern *match)
85{
86 char *filename;
87 struct font *font;
88 FcResult result;
89 double pixel_size, aspect;
90
91 font = malloc(sizeof *font);
92
93 if (!font)
94 goto error0;
95
96 font->context = context;
97
98 result = FcPatternGetString(match, FC_FILE, 0, (FcChar8 **)&filename);
99
100 if (result == FcResultMatch) {
101 FT_Error error;
102
103 DEBUG("Loading font file: %s\n", filename);
104
105 error = FT_New_Face(context->library, filename, 0, &font->face);
106
107 if (error == 0)
108 goto load_face;
109 }
110
111 result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &font->face);
112
113 if (result != FcResultMatch) {
114 DEBUG("Couldn't determine font filename or FreeType face\n");
115 goto error1;
116 }
117
118load_face:
119 result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixel_size);
120
121 result = FcPatternGetDouble(match, FC_ASPECT, 0, &aspect);
122
123 if (result == FcResultNoMatch)
124 aspect = 1.0;
125
126 if (font->face->face_flags & FT_FACE_FLAG_SCALABLE) {
127 FT_F26Dot6 width, height;
128
129 width = ((unsigned int)pixel_size) << 6;
130 height = ((unsigned int)(pixel_size * aspect)) << 6;
131
132 FT_Set_Char_Size(font->face, width, height, 0, 0);
133 } else {
134 FT_Set_Pixel_Sizes(font->face, (unsigned int)pixel_size,
135 (unsigned int)(pixel_size * aspect));
136 }
137
138 font->base.ascent = font->face->size->metrics.ascender >> 6;
139 font->base.descent = -font->face->size->metrics.descender >> 6;
140 font->base.height = font->base.ascent + font->base.descent;
141 font->base.max_advance = font->face->size->metrics.max_advance >> 6;
142
143 font->glyphs = calloc(font->face->num_glyphs, sizeof(struct glyph *));
144
145 return &font->base;
146
147error1:
148 free(font);
149error0:
150 return NULL;
151}
152
153EXPORT
154void
155wld_font_close(struct wld_font *font_base)
156{
157 struct font *font = (void *)font_base;
158
159 FT_Done_Face(font->face);
160 free(font);
161}
162
163bool
164font_ensure_glyph(struct font *font, FT_UInt glyph_index)
165{
166 if (glyph_index) {
167 if (!font->glyphs[glyph_index]) {
168 struct glyph *glyph;
169
170 glyph = malloc(sizeof *glyph);
171
172 if (!glyph)
173 return false;
174
175 FT_Load_Glyph(font->face, glyph_index,
176 FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
177
178 FT_Bitmap_New(&glyph->bitmap);
179
180 FT_Bitmap_Copy(font->context->library,
181 &font->face->glyph->bitmap, &glyph->bitmap);
182
183 glyph->advance = font->face->glyph->metrics.horiAdvance >> 6;
184 glyph->x = font->face->glyph->bitmap_left;
185 glyph->y = -font->face->glyph->bitmap_top;
186
187 font->glyphs[glyph_index] = glyph;
188 }
189
190 return true;
191 }
192
193 return false;
194}
195
196EXPORT
197bool
198wld_font_ensure_char(struct wld_font *font_base, uint32_t character)
199{
200 struct font *font = (void *)font_base;
201 FT_UInt glyph_index;
202
203 glyph_index = FT_Get_Char_Index(font->face, character);
204
205 return font_ensure_glyph(font, glyph_index);
206}
207
208EXPORT
209void
210wld_font_text_extents_n(struct wld_font *font_base,
211 const char *text, int32_t length,
212 struct wld_extents *extents)
213{
214 struct font *font = (void *)font_base;
215 int ret;
216 uint32_t c;
217 FT_UInt glyph_index;
218
219 extents->advance = 0;
220
221 while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length)) > 0 && c != '\0') {
222 length -= ret;
223 text += ret;
224 glyph_index = FT_Get_Char_Index(font->face, c);
225
226 if (!font_ensure_glyph(font, glyph_index))
227 continue;
228
229 extents->advance += font->glyphs[glyph_index]->advance;
230 }
231}