1 #include "config.h"
2
3 #include <ft2build.h>
4 #include FT_FREETYPE_H
5 #include FT_GLYPH_H
6 #include <math.h>
7 #include <string.h>
8 #include <sys/types.h>
9
10 #include "blend.h"
11 #include "colormod.h"
12 #include "common.h"
13 #include "image.h"
14 #include "font.h"
15 #include "rgbadraw.h"
16 #include "rotate.h"
17
18 extern FT_Library ft_lib;
19
20 /* string extents */
21 void
__imlib_font_query_size(ImlibFont * fn,const char * text,int * w,int * h)22 __imlib_font_query_size(ImlibFont * fn, const char *text, int *w, int *h)
23 {
24 int use_kerning;
25 int pen_x /*, pen_y */ ;
26 int start_x, end_x;
27 int chr;
28 FT_UInt prev_index;
29
30 start_x = 0;
31 end_x = 0;
32 pen_x = 0;
33 /* pen_y = 0; */
34 use_kerning = FT_HAS_KERNING(fn->ft.face);
35 prev_index = 0;
36 for (chr = 0; text[chr];)
37 {
38 FT_UInt index;
39 Imlib_Font_Glyph *fg;
40 ImlibFont *fn_in_chain;
41 int chr_x, /*chr_y, */ chr_w;
42 int gl;
43
44 gl = __imlib_font_utf8_get_next((unsigned char *)text, &chr);
45 if (gl == 0)
46 break;
47 fn_in_chain = __imlib_font_find_glyph(fn, gl, &index);
48 if ((use_kerning) && (prev_index) && (index))
49 {
50 FT_Vector delta;
51
52 FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index,
53 ft_kerning_default, &delta);
54 pen_x += delta.x << 2;
55 }
56 fg = __imlib_font_cache_glyph_get(fn_in_chain, index);
57 if (!fg)
58 continue;
59
60 chr_x = (pen_x >> 8) + fg->glyph_out->left;
61 /* chr_y = (pen_y >> 8) + fg->glyph_out->top; */
62 chr_w = fg->glyph_out->bitmap.width;
63
64 if (pen_x == 0)
65 start_x = chr_x;
66 if ((chr_x + chr_w) > end_x)
67 end_x = chr_x + chr_w;
68
69 pen_x += fg->glyph->advance.x >> 8;
70 prev_index = index;
71 }
72 if (w)
73 *w = (pen_x >> 8) - start_x;
74 if (h)
75 *h = __imlib_font_max_ascent_get(fn) - __imlib_font_max_descent_get(fn); /* TODO: compute this inside the loop since we now may be dealing with multiple fonts */
76 }
77
78 /* text x inset */
79 int
__imlib_font_query_inset(ImlibFont * fn,const char * text)80 __imlib_font_query_inset(ImlibFont * fn, const char *text)
81 {
82 FT_UInt index;
83 Imlib_Font_Glyph *fg;
84 ImlibFont *fn_in_chain;
85 int chr;
86 int gl;
87
88 chr = 0;
89 if (!text[0])
90 return 0;
91 gl = __imlib_font_utf8_get_next((unsigned char *)text, &chr);
92 if (gl == 0)
93 return 0;
94 fn_in_chain = __imlib_font_find_glyph(fn, gl, &index);
95 fg = __imlib_font_cache_glyph_get(fn_in_chain, index);
96 if (!fg)
97 return 0;
98 return -fg->glyph_out->left;
99 }
100
101 /* h & v advance */
102 void
__imlib_font_query_advance(ImlibFont * fn,const char * text,int * h_adv,int * v_adv)103 __imlib_font_query_advance(ImlibFont * fn, const char *text, int *h_adv,
104 int *v_adv)
105 {
106 int use_kerning;
107 int pen_x;
108 int start_x;
109 int chr;
110 FT_UInt prev_index;
111
112 start_x = 0;
113 pen_x = 0;
114 use_kerning = FT_HAS_KERNING(fn->ft.face);
115 prev_index = 0;
116 for (chr = 0; text[chr];)
117 {
118 FT_UInt index;
119 Imlib_Font_Glyph *fg;
120 ImlibFont *fn_in_chain;
121 int gl;
122
123 gl = __imlib_font_utf8_get_next((unsigned char *)text, &chr);
124 if (gl == 0)
125 break;
126 fn_in_chain = __imlib_font_find_glyph(fn, gl, &index);
127 if ((use_kerning) && (prev_index) && (index))
128 {
129 FT_Vector delta;
130
131 FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index,
132 ft_kerning_default, &delta);
133 pen_x += delta.x << 2;
134 }
135 fg = __imlib_font_cache_glyph_get(fn_in_chain, index);
136 if (!fg)
137 continue;
138
139 pen_x += fg->glyph->advance.x >> 8;
140 prev_index = index;
141 }
142 if (v_adv)
143 *v_adv = __imlib_font_get_line_advance(fn); /* TODO: compute this in the loop since we may be dealing with multiple fonts */
144 if (h_adv)
145 *h_adv = (pen_x >> 8) - start_x;
146 }
147
148 /* x y w h for char at char pos */
149 int
__imlib_font_query_char_coords(ImlibFont * fn,const char * text,int pos,int * cx,int * cy,int * cw,int * ch)150 __imlib_font_query_char_coords(ImlibFont * fn, const char *text, int pos,
151 int *cx, int *cy, int *cw, int *ch)
152 {
153 int use_kerning;
154 int pen_x;
155 int prev_chr_end;
156 int chr;
157 int asc, desc;
158 FT_UInt prev_index;
159
160 pen_x = 0;
161 use_kerning = FT_HAS_KERNING(fn->ft.face);
162 prev_index = 0;
163 prev_chr_end = 0;
164 asc = __imlib_font_max_ascent_get(fn);
165 desc = __imlib_font_max_descent_get(fn);
166 for (chr = 0; text[chr];)
167 {
168 int pchr;
169 FT_UInt index;
170 Imlib_Font_Glyph *fg;
171 ImlibFont *fn_in_chain;
172 int chr_x, chr_w;
173 int gl, kern;
174 FT_Vector delta;
175
176 pchr = chr;
177 gl = __imlib_font_utf8_get_next((unsigned char *)text, &chr);
178 if (gl == 0)
179 break;
180 fn_in_chain = __imlib_font_find_glyph(fn, gl, &index);
181 kern = 0;
182 if ((use_kerning) && (prev_index) && (index))
183 {
184 FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index,
185 ft_kerning_default, &delta);
186 kern = delta.x << 2;
187 pen_x += kern;
188 }
189 fg = __imlib_font_cache_glyph_get(fn_in_chain, index);
190 if (!fg)
191 continue;
192
193 if (kern < 0)
194 kern = 0;
195 chr_x = ((pen_x - kern) >> 8) + fg->glyph_out->left;
196 chr_w = fg->glyph_out->bitmap.width + (kern >> 8);
197 if (text[chr])
198 {
199 int advw;
200
201 advw = ((fg->glyph->advance.x + (kern << 8)) >> 16);
202 if (chr_w < advw)
203 chr_w = advw;
204 }
205 if (chr_x > prev_chr_end)
206 {
207 chr_w += (chr_x - prev_chr_end);
208 chr_x = prev_chr_end;
209 }
210 if (pchr == pos)
211 {
212 if (cx)
213 *cx = chr_x;
214 if (cy)
215 *cy = -asc;
216 if (cw)
217 *cw = chr_w;
218 if (ch)
219 *ch = asc + desc;
220 return 1;
221 }
222 prev_chr_end = chr_x + chr_w;
223 pen_x += fg->glyph->advance.x >> 8;
224 prev_index = index;
225 }
226 return 0;
227 }
228
229 /* char pos of text at xy pos */
230 int
__imlib_font_query_text_at_pos(ImlibFont * fn,const char * text,int x,int y,int * cx,int * cy,int * cw,int * ch)231 __imlib_font_query_text_at_pos(ImlibFont * fn, const char *text, int x, int y,
232 int *cx, int *cy, int *cw, int *ch)
233 {
234 int use_kerning;
235 int pen_x;
236 int prev_chr_end;
237 int chr;
238 int asc, desc;
239 FT_UInt prev_index;
240
241 pen_x = 0;
242 use_kerning = FT_HAS_KERNING(fn->ft.face);
243 prev_index = 0;
244 prev_chr_end = 0;
245 asc = __imlib_font_max_ascent_get(fn);
246 desc = __imlib_font_max_descent_get(fn);
247 for (chr = 0; text[chr];)
248 {
249 int pchr;
250 FT_UInt index;
251 Imlib_Font_Glyph *fg;
252 ImlibFont *fn_in_chain;
253 int chr_x, chr_w;
254 int gl, kern;
255 FT_Vector delta;
256
257 pchr = chr;
258 gl = __imlib_font_utf8_get_next((unsigned char *)text, &chr);
259 if (gl == 0)
260 break;
261 fn_in_chain = __imlib_font_find_glyph(fn, gl, &index);
262 kern = 0;
263 if ((use_kerning) && (prev_index) && (index))
264 {
265 FT_Get_Kerning(fn_in_chain->ft.face, prev_index, index,
266 ft_kerning_default, &delta);
267 kern = delta.x << 2;
268 pen_x += kern;
269 }
270 fg = __imlib_font_cache_glyph_get(fn_in_chain, index);
271 if (!fg)
272 continue;
273
274 if (kern < 0)
275 kern = 0;
276 chr_x = ((pen_x - kern) >> 8) + fg->glyph_out->left;
277 chr_w = fg->glyph_out->bitmap.width + (kern >> 8);
278 if (text[chr])
279 {
280 int advw;
281
282 advw = ((fg->glyph->advance.x + (kern << 8)) >> 16);
283 if (chr_w < advw)
284 chr_w = advw;
285 }
286 if (chr_x > prev_chr_end)
287 {
288 chr_w += (chr_x - prev_chr_end);
289 chr_x = prev_chr_end;
290 }
291 if ((x >= chr_x) && (x <= (chr_x + chr_w)) && (y > -asc) && (y < desc))
292 {
293 if (cx)
294 *cx = chr_x;
295 if (cy)
296 *cy = -asc;
297 if (cw)
298 *cw = chr_w;
299 if (ch)
300 *ch = asc + desc;
301 return pchr;
302 }
303 prev_chr_end = chr_x + chr_w;
304 pen_x += fg->glyph->advance.x >> 8;
305 prev_index = index;
306 }
307 return -1;
308 }
309