move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_font_draw.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include "evas_common.h"
6 #include "evas_blend_private.h"
7
8 EAPI RGBA_Font_Glyph *
9 evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
10 {
11    RGBA_Font_Glyph *fg;
12    char key[6];
13    FT_UInt hindex;
14    FT_Error error;
15    const FT_Int32 hintflags[3] =
16      { FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
17
18    hindex = index + (fi->hinting * 500000000);
19
20    key[0] = ((hindex       ) & 0x7f) + 1;
21    key[1] = ((hindex >> 7  ) & 0x7f) + 1;
22    key[2] = ((hindex >> 14 ) & 0x7f) + 1;
23    key[3] = ((hindex >> 21 ) & 0x7f) + 1;
24    key[4] = ((hindex >> 28 ) & 0x0f) + 1;
25    key[5] = 0;
26
27    fg = evas_hash_find(fi->glyphs, key);
28    if (fg) return fg;
29
30 //   error = FT_Load_Glyph(fi->src->ft.face, index, FT_LOAD_NO_BITMAP);
31    error = FT_Load_Glyph(fi->src->ft.face, index,
32                          FT_LOAD_RENDER | hintflags[fi->hinting]);
33    if (error) return NULL;
34
35    fg = malloc(sizeof(struct _RGBA_Font_Glyph));
36    if (!fg) return NULL;
37    memset(fg, 0, (sizeof(struct _RGBA_Font_Glyph)));
38
39    error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph));
40    if (error)
41      {
42         free(fg);
43         return NULL;
44      }
45    if (fg->glyph->format != FT_GLYPH_FORMAT_BITMAP)
46      {
47         error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
48         if (error)
49           {
50              FT_Done_Glyph(fg->glyph);
51              free(fg);
52              return NULL;
53           }
54      }
55    fg->glyph_out = (FT_BitmapGlyph)fg->glyph;
56
57    fi->glyphs = evas_hash_add(fi->glyphs, key, fg);
58    return fg;
59 }
60
61 EAPI int
62 evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, int gl)
63 {
64    Evas_List *l;
65
66    for (l = fn->fonts; l; l = l->next)
67      {
68         RGBA_Font_Int *fi;
69         int index;
70
71         fi = l->data;
72
73         if (fi->src->charmap) /* Charmap loaded, FI/FS blank */
74           {
75              index = evas_array_hash_search(fi->src->charmap, gl);
76              if (index != 0)
77                {
78                   evas_common_font_source_load_complete(fi->src);
79                   evas_common_font_int_load_complete(fi);
80
81                   evas_array_hash_free(fi->src->charmap);
82                   fi->src->charmap = NULL;
83
84                   *fi_ret = fi;
85                   return index;
86                }
87           }
88         else if (!fi->src->ft.face) /* Charmap not loaded, FI/FS blank */
89           {
90              if (evas_common_font_source_load_complete(fi->src))
91                return 0;
92 #if 0 /* FIXME: disable this. this can eat a LOT of memory and in my tests with expedite at any rate shows no visible improvements */
93              index = FT_Get_Char_Index(fi->src->ft.face, gl);
94              if (index == 0)
95                {
96                   /* Load Hash */
97                   FT_ULong  charcode;
98                   FT_UInt   gindex;
99
100                   fi->src->charmap = evas_array_hash_new();
101                   charcode = FT_Get_First_Char(fi->src->ft.face, &gindex);
102                   while (gindex != 0)
103                     {
104                        evas_array_hash_add(fi->src->charmap, charcode, gindex);
105                        charcode = FT_Get_Next_Char(fi->src->ft.face, charcode, &gindex);
106                     }
107
108                   /* Free face */
109                   FT_Done_Face(fi->src->ft.face);
110                   fi->src->ft.face = NULL;
111                }
112              else
113                {
114                   evas_common_font_int_load_complete(fi);
115
116                   *fi_ret = fi;
117                   return index;
118                }
119 #endif
120           }
121         else /* Charmap not loaded, FS loaded */
122           {
123              index = FT_Get_Char_Index(fi->src->ft.face, gl);
124              if (index != 0)
125                {
126                   if (!fi->ft.size)
127                     evas_common_font_int_load_complete(fi);
128
129                   *fi_ret = fi;
130                   return index;
131                }
132           }
133      }
134    return 0;
135 }
136
137 EAPI void
138 evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int x, int y, const char *text)
139 {
140    int use_kerning;
141    int pen_x, pen_y;
142    int chr;
143    FT_UInt prev_index;
144    RGBA_Gfx_Func func;
145    int ext_x, ext_y, ext_w, ext_h;
146    DATA32 *im;
147    int im_w, im_h;
148    int c;
149    RGBA_Font_Int *fi;
150    FT_Face pface = NULL;
151
152    fi = fn->fonts->data;
153
154    im = dst->image.data;
155    im_w = dst->cache_entry.w;
156    im_h = dst->cache_entry.h;
157
158    ext_x = 0; ext_y = 0; ext_w = im_w; ext_h = im_h;
159    if (dc->clip.use)
160      {
161         ext_x = dc->clip.x;
162         ext_y = dc->clip.y;
163         ext_w = dc->clip.w;
164         ext_h = dc->clip.h;
165         if (ext_x < 0)
166           {
167              ext_w += ext_x;
168              ext_x = 0;
169           }
170         if (ext_y < 0)
171           {
172              ext_h += ext_y;
173              ext_y = 0;
174           }
175         if ((ext_x + ext_w) > im_w)
176           ext_w = im_w - ext_x;
177         if ((ext_y + ext_h) > im_h)
178           ext_h = im_h - ext_y;
179      }
180    if (ext_w <= 0) return;
181    if (ext_h <= 0) return;
182
183    pen_x = x;
184    pen_y = y;
185    LKL(fn->lock);
186    evas_common_font_size_use(fn);
187    use_kerning = FT_HAS_KERNING(fi->src->ft.face);
188    prev_index = 0;
189    func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst, 1, dc->render_op);
190    for (c = 0, chr = 0; text[chr];)
191      {
192         FT_UInt index;
193         RGBA_Font_Glyph *fg;
194         int chr_x, chr_y;
195         int gl;
196
197         gl = evas_common_font_utf8_get_next((unsigned char *)text, &chr);
198         if (gl == 0) break;
199         index = evas_common_font_glyph_search(fn, &fi, gl);
200         /* hmmm kerning means i can't sanely do my own cached metric tables! */
201         /* grrr - this means font face sharing is kinda... not an option if */
202         /* you want performance */
203         if ((use_kerning) && (prev_index) && (index) &&
204             (pface == fi->src->ft.face))
205           {
206              FT_Vector delta;
207
208              if (FT_Get_Kerning(fi->src->ft.face, prev_index, index,
209                                 ft_kerning_default, &delta) == 0)
210                pen_x += delta.x >> 6;
211           }
212         pface = fi->src->ft.face;
213         fg = evas_common_font_int_cache_glyph_get(fi, index);
214         if (!fg) continue;
215
216         if (dc->font_ext.func.gl_new)
217           {
218              /* extension calls */
219              fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg);
220              fg->ext_dat_free = dc->font_ext.func.gl_free;
221           }
222
223         chr_x = (pen_x + (fg->glyph_out->left));
224         chr_y = (pen_y + (fg->glyph_out->top));
225
226         if (chr_x < (ext_x + ext_w))
227           {
228              DATA8 *data;
229              int i, j, w, h;
230
231              data = fg->glyph_out->bitmap.buffer;
232              j = fg->glyph_out->bitmap.pitch;
233              w = fg->glyph_out->bitmap.width;
234              if (j < w) j = w;
235              h = fg->glyph_out->bitmap.rows;
236 /*
237              if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays)
238                  && (fg->glyph_out->bitmap.num_grays == 256)
239                  )
240  */
241                {
242                   if ((j > 0) && (chr_x + w > ext_x))
243                     {
244                        if ((fg->ext_dat) && (dc->font_ext.func.gl_draw))
245                          {
246                             /* ext glyph draw */
247                             dc->font_ext.func.gl_draw(dc->font_ext.data,
248                                                       (void *)dst,
249                                                       dc, fg,
250                                                       chr_x,
251                                                       y - (chr_y - y)
252                                                       );
253                          }
254                        else
255                          {
256                             if ((fg->glyph_out->bitmap.num_grays == 256) &&
257                                 (fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays))
258                               {
259                                  for (i = 0; i < h; i++)
260                                    {
261                                       int dx, dy;
262                                       int in_x, in_w;
263
264                                       in_x = 0;
265                                       in_w = 0;
266                                       dx = chr_x;
267                                       dy = y - (chr_y - i - y);
268 #ifdef EVAS_SLI
269                                       if (((dy) % dc->sli.h) == dc->sli.y)
270 #endif
271                                         {
272                                            if ((dx < (ext_x + ext_w)) &&
273                                                (dy >= (ext_y)) &&
274                                                (dy < (ext_y + ext_h)))
275                                              {
276                                                 if (dx + w > (ext_x + ext_w))
277                                                   in_w += (dx + w) - (ext_x + ext_w);
278                                                 if (dx < ext_x)
279                                                   {
280                                                      in_w += ext_x - dx;
281                                                      in_x = ext_x - dx;
282                                                      dx = ext_x;
283                                                   }
284                                                 if (in_w < w)
285                                                   {
286                                                      func(NULL, data + (i * j) + in_x, dc->col.col,
287                                                           im + (dy * im_w) + dx, w - in_w);
288                                                   }
289                                              }
290                                         }
291                                    }
292                               }
293                             else
294                               {
295                                  DATA8 *tmpbuf = NULL, *dp, *tp, bits;
296                                  int bi, bj;
297                                  const DATA8 bitrepl[2] = {0x0, 0xff};
298
299                                  tmpbuf = alloca(w);
300                                  for (i = 0; i < h; i++)
301                                    {
302                                       int dx, dy;
303                                       int in_x, in_w, end;
304
305                                       in_x = 0;
306                                       in_w = 0;
307                                       dx = chr_x;
308                                       dy = y - (chr_y - i - y);
309 #ifdef EVAS_SLI
310                                       if (((dy) % dc->sli.h) == dc->sli.y)
311 #endif
312                                         {
313                                            tp = tmpbuf;
314                                            dp = data + (i * fg->glyph_out->bitmap.pitch);
315                                            for (bi = 0; bi < w; bi += 8)
316                                              {
317                                                 bits = *dp;
318                                                 if ((w - bi) < 8) end = w - bi;
319                                                 else end = 8;
320                                                 for (bj = 0; bj < end; bj++)
321                                                   {
322                                                      *tp = bitrepl[(bits >> (7 - bj)) & 0x1];
323                                                      tp++;
324                                                   }
325                                                 dp++;
326                                              }
327                                            if ((dx < (ext_x + ext_w)) &&
328                                                (dy >= (ext_y)) &&
329                                                (dy < (ext_y + ext_h)))
330                                              {
331                                                 if (dx + w > (ext_x + ext_w))
332                                                   in_w += (dx + w) - (ext_x + ext_w);
333                                                 if (dx < ext_x)
334                                                   {
335                                                      in_w += ext_x - dx;
336                                                      in_x = ext_x - dx;
337                                                      dx = ext_x;
338                                                   }
339                                                 if (in_w < w)
340                                                   {
341                                                      func(NULL, tmpbuf + in_x, dc->col.col,
342                                                           im + (dy * im_w) + dx, w - in_w);
343                                                   }
344                                              }
345                                         }
346                                    }
347                               }
348                          }
349                        c++;
350                     }
351                }
352           }
353         else
354           break;
355         pen_x += fg->glyph->advance.x >> 16;
356         prev_index = index;
357      }
358    LKU(fn->lock);
359 }