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