1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 #include "evas_blend_private.h"
4 
5 #include "language/evas_bidi_utils.h" /*defines BIDI_SUPPORT if possible */
6 #include "evas_font_private.h" /* for Frame-Queuing support */
7 
8 #include "evas_font_ot.h"
9 #include "draw.h"
10 
11 struct _Evas_Glyph
12 {
13    RGBA_Font_Glyph *fg;
14    int x, y;
15    FT_UInt idx;
16 };
17 
18 EAPI void
evas_common_font_draw_init(void)19 evas_common_font_draw_init(void)
20 {
21 }
22 
23 static void *
_evas_font_image_new(RGBA_Font_Glyph * fg,int alpha,Evas_Colorspace cspace)24 _evas_font_image_new(RGBA_Font_Glyph *fg, int alpha, Evas_Colorspace cspace)
25 {
26    DATA32 *image_data;
27    int src_w, src_h;
28 
29    if (!fg) return NULL;
30 
31    image_data = (DATA32 *)fg->glyph_out->bitmap.buffer;
32    src_w = fg->glyph_out->bitmap.width;
33    src_h = fg->glyph_out->bitmap.rows;
34 
35    return evas_cache_image_data(evas_common_image_cache_get(), src_w, src_h, image_data, alpha, cspace);
36 }
37 
38 static void
_evas_font_image_draw(void * context,void * surface,void * image,RGBA_Font_Glyph * fg,int x,int y,int w,int h,int smooth)39 _evas_font_image_draw(void *context, void *surface, void *image, RGBA_Font_Glyph *fg, int x, int y, int w, int h, int smooth)
40 {
41    RGBA_Image *im;
42    int src_w, src_h;
43 
44    if (!image || !fg) return;
45    im = image;
46    src_w = fg->glyph_out->bitmap.width;
47    src_h = fg->glyph_out->bitmap.rows;
48 
49 #ifdef BUILD_PIPE_RENDER
50    if ((eina_cpu_count() > 1))
51      {
52         evas_common_rgba_image_scalecache_prepare((Image_Entry *)(im),
53                                                   surface, context, smooth,
54                                                   0, 0, src_w, src_h,
55                                                   x, y, w, h);
56 
57         evas_common_pipe_image_draw(im, surface, context, smooth,
58                                     0, 0, src_w, src_h,
59                                     x, y, w, h);
60      }
61    else
62 #endif
63      {
64         evas_common_rgba_image_scalecache_prepare
65           (&im->cache_entry, surface, context, smooth,
66            0, 0, src_w, src_h,
67            x, y, w, h);
68         evas_common_rgba_image_scalecache_do
69           (&im->cache_entry, surface, context, smooth,
70            0, 0, src_w, src_h,
71            x, y, w, h);
72 
73         evas_common_cpu_end_opt();
74      }
75 }
76 
77 /*
78  * BiDi handling: We receive the shaped string + other props from text_props,
79  * we need to reorder it so we'll have the visual string (the way we draw)
80  * and then for kerning we have to switch the order of the kerning query (as the prev
81  * is on the right, and not on the left).
82  */
83 EAPI Eina_Bool
evas_common_font_rgba_draw(RGBA_Image * dst,RGBA_Draw_Context * dc,int x,int y,Evas_Glyph_Array * glyphs,RGBA_Gfx_Func func EINA_UNUSED,int ext_x,int ext_y,int ext_w,int ext_h,int im_w,int im_h EINA_UNUSED)84 evas_common_font_rgba_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y,
85                            Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func EINA_UNUSED, int ext_x, int ext_y, int ext_w,
86                            int ext_h, int im_w, int im_h EINA_UNUSED)
87 {
88    Evas_Glyph *glyph;
89 
90    if (!glyphs) return EINA_FALSE;
91    if (!glyphs->array) return EINA_FALSE;
92 
93    EINA_INARRAY_FOREACH(glyphs->array, glyph)
94      {
95         RGBA_Font_Glyph *fg;
96         int chr_x, chr_y, w, h;
97 
98         fg = glyph->fg;
99 
100         w = fg->glyph_out->bitmap.width;
101         h = fg->glyph_out->bitmap.rows;
102 
103         if (FT_HAS_FIXED_SIZES(fg->fi->src->ft.face))
104           {
105              if ((fg->fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR) &&
106                  FT_HAS_COLOR(fg->fi->src->ft.face))
107                {
108                   if ( !fg->fi->is_resized )
109                     {
110                        w *= fg->fi->scale_factor;
111                        h *= fg->fi->scale_factor;
112                     }
113 
114                }
115           }
116 
117         if ((!fg->ext_dat) && (dc->font_ext.func.gl_new))
118           {
119              /* extension calls */
120              fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg);
121              fg->ext_dat_free = dc->font_ext.func.gl_free;
122           }
123 
124         if (dc->font_ext.func.gl_image_new)
125           {
126              if ((!fg->ext_dat) && FT_HAS_COLOR(fg->fi->src->ft.face))
127                {
128                   /* extension calls */
129                   fg->ext_dat = dc->font_ext.func.gl_image_new
130                     (dc->font_ext.data, fg, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
131                   fg->ext_dat_free = dc->font_ext.func.gl_image_free;
132                }
133           }
134         else
135           {
136              if ((!fg->col_dat) && FT_HAS_COLOR(fg->fi->src->ft.face))
137                {
138                   fg->col_dat = _evas_font_image_new(fg, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
139                }
140           }
141 
142         chr_x = x + glyph->x;
143         chr_y = y + glyph->y;
144         if (chr_x < (ext_x + ext_w))
145           {
146              if ((w > 0) && ((chr_x + w) > ext_x))
147                {
148                   if (fg->glyph_out->rle)
149                     {
150                        if ((fg->ext_dat) && (dc->font_ext.func.gl_draw))
151                          dc->font_ext.func.gl_draw(dc->font_ext.data, dst,
152                                                    dc, fg,
153                                                    chr_x, y - (chr_y - y), w, h);
154                        else
155                          // TODO: scale with evas_font_compress_draw.c...
156                          evas_common_font_glyph_draw(fg, dc, dst, im_w,
157                                                      chr_x, y - (chr_y - y), w, h,
158                                                      ext_x, ext_y,
159                                                      ext_w, ext_h);
160                     }
161                   else if (FT_HAS_COLOR(fg->fi->src->ft.face))
162                     {
163                        if ((fg->ext_dat) && (dc->font_ext.func.gl_image_draw))
164                          dc->font_ext.func.gl_image_draw
165                            (dc->font_ext.data, fg->ext_dat,
166                             chr_x, y - (chr_y - y), w, h, EINA_TRUE);
167                        else if (fg->col_dat)
168                          _evas_font_image_draw
169                            (dc, dst, fg->col_dat, fg,
170                             chr_x, y - (chr_y - y), w, h, EINA_TRUE);
171                     }
172                }
173           }
174         else
175           break;
176      }
177 
178    return EINA_TRUE;
179 }
180 
181 void
evas_common_font_glyphs_ref(Evas_Glyph_Array * array)182 evas_common_font_glyphs_ref(Evas_Glyph_Array *array)
183 {
184    array->refcount++;
185 }
186 
187 void
evas_common_font_glyphs_unref(Evas_Glyph_Array * array)188 evas_common_font_glyphs_unref(Evas_Glyph_Array *array)
189 {
190    if (--array->refcount) return;
191 
192    eina_inarray_free(array->array);
193    evas_common_font_int_unref(array->fi);
194    free(array);
195 }
196 
197 void
evas_common_font_fonts_ref(Evas_Font_Array * array)198 evas_common_font_fonts_ref(Evas_Font_Array *array)
199 {
200    array->refcount++;
201 }
202 
203 void
evas_common_font_fonts_unref(Evas_Font_Array * array)204 evas_common_font_fonts_unref(Evas_Font_Array *array)
205 {
206    if (--array->refcount) return;
207 
208    eina_inarray_free(array->array);
209    free(array);
210 }
211 
212 EAPI void
evas_common_font_draw_prepare(Evas_Text_Props * text_props)213 evas_common_font_draw_prepare(Evas_Text_Props *text_props)
214 {
215    RGBA_Font_Int *fi;
216    RGBA_Font_Glyph *fg = NULL;
217    Eina_Inarray *glyphs;
218    size_t unit = 32;
219    Eina_Bool reused_glyphs;
220    EVAS_FONT_WALK_TEXT_INIT();
221 
222    fi = text_props->font_instance;
223    if (!fi) return;
224 
225    if ((!text_props->changed) &&
226        (text_props->generation == fi->generation) &&
227        text_props->glyphs)
228      return;
229 
230    if (text_props->len < unit) unit = text_props->len;
231    if (text_props->glyphs && text_props->glyphs->refcount == 1)
232      {
233         glyphs = text_props->glyphs->array;
234         glyphs->len = 0;
235         reused_glyphs = EINA_TRUE;
236      }
237    else
238      {
239         glyphs = eina_inarray_new(sizeof(Evas_Glyph), unit);
240         reused_glyphs = EINA_FALSE;
241      }
242    evas_common_font_int_reload(fi);
243 
244    if (fi->src->current_size != fi->size)
245      {
246         evas_common_font_source_reload(fi->src);
247         FTLOCK();
248         FT_Activate_Size(fi->ft.size);
249         FTUNLOCK();
250         fi->src->current_size = fi->size;
251      }
252 
253    EVAS_FONT_WALK_TEXT_START()
254      {
255         Evas_Glyph *glyph;
256         FT_UInt idx;
257 
258         if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
259         idx = EVAS_FONT_WALK_INDEX;
260 
261         fg = evas_common_font_int_cache_glyph_get(fi, idx);
262         if (!fg) continue;
263         if (!evas_common_font_int_cache_glyph_render(fg))
264           {
265              fg = NULL;
266              goto error;
267           }
268 
269         glyph = eina_inarray_grow(glyphs, 1);
270         if (!glyph) goto error;
271 
272         glyph->fg = fg;
273         glyph->idx = idx;
274         glyph->x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
275         glyph->y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
276      }
277    EVAS_FONT_WALK_TEXT_END();
278 
279    if (!reused_glyphs)
280      {
281         if (text_props->glyphs) evas_common_font_glyphs_unref(text_props->glyphs);
282 
283         text_props->glyphs = malloc(sizeof(*text_props->glyphs));
284         if (!text_props->glyphs) goto error;
285         text_props->glyphs->refcount = 1;
286         text_props->glyphs->array = glyphs;
287         text_props->glyphs->fi = fi;
288         fi->references++;
289      }
290 
291    /* check if there's a request queue in fi, if so ask cserve2 to render
292     * those glyphs
293     */
294 
295    text_props->generation = fi->generation;
296    text_props->changed = EINA_FALSE;
297 
298    return;
299 
300 error:
301    eina_inarray_free(glyphs);
302 }
303 
304 EAPI Eina_Bool
evas_common_font_draw_cb(RGBA_Image * dst,RGBA_Draw_Context * dc,int x,int y,Evas_Glyph_Array * glyphs,Evas_Common_Font_Draw_Cb cb)305 evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, Evas_Common_Font_Draw_Cb cb)
306 {
307    int ext_x, ext_y, ext_w, ext_h;
308    int im_w, im_h;
309    RGBA_Gfx_Func func;
310    Cutout_Rect  *r;
311    int c, cx, cy, cw, ch;
312    int i;
313 
314    if (!glyphs) return EINA_FALSE;
315 
316    im_w = dst->cache_entry.w;
317    im_h = dst->cache_entry.h;
318 
319 //   evas_common_font_size_use(fn);
320    func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, 1, dc->render_op);
321 
322    if (!dc->cutout.rects)
323      {
324         ext_x = 0; ext_y = 0; ext_w = im_w; ext_h = im_h;
325         if (dc->clip.use)
326           {
327              ext_x = dc->clip.x;
328              ext_y = dc->clip.y;
329              ext_w = dc->clip.w;
330              ext_h = dc->clip.h;
331              if (ext_x < 0)
332                {
333                   ext_w += ext_x;
334                   ext_x = 0;
335                }
336              if (ext_y < 0)
337                {
338                   ext_h += ext_y;
339                   ext_y = 0;
340                }
341              if ((ext_x + ext_w) > im_w)
342                ext_w = im_w - ext_x;
343              if ((ext_y + ext_h) > im_h)
344                ext_h = im_h - ext_y;
345           }
346         if (ext_w <= 0) return EINA_FALSE;
347         if (ext_h <= 0) return EINA_FALSE;
348 
349         return cb(dst, dc, x, y, glyphs,
350                   func, ext_x, ext_y, ext_w, ext_h,
351                   im_w, im_h);
352      }
353    else
354      {
355         Eina_Bool ret = EINA_FALSE;
356         c = dc->clip.use; cx = dc->clip.x; cy = dc->clip.y; cw = dc->clip.w; ch = dc->clip.h;
357         evas_common_draw_context_clip_clip(dc, 0, 0, dst->cache_entry.w, dst->cache_entry.h);
358         /* our clip is 0 size.. abort */
359         if ((dc->clip.w > 0) && (dc->clip.h > 0))
360           {
361              dc->cache.rects = evas_common_draw_context_apply_cutouts(dc, dc->cache.rects);
362              for (i = 0; i < dc->cache.rects->active; ++i)
363                {
364                   r = dc->cache.rects->rects + i;
365                   evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h);
366                   ret |= cb(dst, dc, x, y, glyphs,
367                             func, r->x, r->y, r->w, r->h,
368                             im_w, im_h);
369                }
370              evas_common_draw_context_cache_update(dc);
371           }
372         dc->clip.use = c; dc->clip.x = cx; dc->clip.y = cy; dc->clip.w = cw; dc->clip.h = ch;
373 
374         return ret;
375      }
376 }
377 
378 EAPI void
evas_common_font_draw(RGBA_Image * dst,RGBA_Draw_Context * dc,int x,int y,Evas_Glyph_Array * glyphs)379 evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs)
380 {
381    evas_common_font_draw_cb(dst, dc, x, y, glyphs,
382                             evas_common_font_rgba_draw);
383 }
384 
385 EAPI void
evas_common_font_draw_do(const Cutout_Rects * reuse,const Eina_Rectangle * clip,RGBA_Gfx_Func func,RGBA_Image * dst,RGBA_Draw_Context * dc,int x,int y,const Evas_Text_Props * text_props)386 evas_common_font_draw_do(const Cutout_Rects *reuse, const Eina_Rectangle *clip, RGBA_Gfx_Func func,
387                          RGBA_Image *dst, RGBA_Draw_Context *dc,
388                          int x, int y, const Evas_Text_Props *text_props)
389 {
390    Eina_Rectangle area;
391    Cutout_Rect *r;
392    int i;
393    int im_w, im_h;
394 
395    im_w = dst->cache_entry.w;
396    im_h = dst->cache_entry.h;
397 
398    if (!reuse)
399      {
400         evas_common_draw_context_clip_clip(dc,
401                                            clip->x, clip->y,
402                                            clip->w, clip->h);
403         evas_common_font_rgba_draw(dst, dc, x, y, text_props->glyphs,
404                                    func,
405                                    dc->clip.x, dc->clip.y,
406                                    dc->clip.w, dc->clip.h,
407                                    im_w, im_h);
408         return;
409      }
410 
411    for (i = 0; i < reuse->active; ++i)
412      {
413         r = reuse->rects + i;
414 
415         EINA_RECTANGLE_SET(&area, r->x, r->y, r->w - 1, r->h - 1);
416         if (!eina_rectangle_intersection(&area, clip)) continue ;
417         evas_common_draw_context_set_clip(dc, area.x, area.y, area.w, area.h);
418         evas_common_font_rgba_draw(dst, dc, x, y, text_props->glyphs,
419                                    func, area.x, area.y, area.w, area.h,
420                                    im_w, im_h);
421      }
422 }
423 
424 EAPI Eina_Bool
evas_common_font_draw_prepare_cutout(Cutout_Rects ** reuse,RGBA_Image * dst,RGBA_Draw_Context * dc,RGBA_Gfx_Func * func)425 evas_common_font_draw_prepare_cutout(Cutout_Rects **reuse, RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Gfx_Func *func)
426 {
427    int im_w, im_h;
428 
429    im_w = dst->cache_entry.w;
430    im_h = dst->cache_entry.h;
431 
432    *func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, 1, dc->render_op);
433 
434    evas_common_draw_context_clip_clip(dc, 0, 0, im_w, im_h);
435    if (dc->clip.w <= 0) return EINA_FALSE;
436    if (dc->clip.h <= 0) return EINA_FALSE;
437 
438    if (dc->cutout.rects)
439      {
440         *reuse = evas_common_draw_context_apply_cutouts(dc, *reuse);
441      }
442 
443    return EINA_TRUE;
444 }
445 
446 // this draws a compressed font glyph and decompresses on the fly as it
447 // draws, saving memory bandwidth and providing speedups
448 EAPI void
evas_common_font_glyph_draw(RGBA_Font_Glyph * fg,RGBA_Draw_Context * dc,RGBA_Image * dst_image,int dst_pitch,int dx,int dy,int dw,int dh,int cx,int cy,int cw,int ch)449 evas_common_font_glyph_draw(RGBA_Font_Glyph *fg,
450                             RGBA_Draw_Context *dc,
451                             RGBA_Image *dst_image, int dst_pitch,
452                             int dx, int dy, int dw, int dh, int cx, int cy, int cw, int ch)
453 {
454    RGBA_Font_Glyph_Out *fgo = fg->glyph_out;
455    int x, y, w, h, x1, x2, y1, y2, i, *iptr;
456    DATA32 *dst = dst_image->image.data;
457    DATA32 coltab[16], col;
458    DATA16 mtab[16], v;
459 
460    if (!dst) return;
461 
462    // FIXME: Use dw, dh for scaling glyphs...
463    (void) dw;
464    (void) dh;
465    x = dx;
466    y = dy;
467    w = fgo->bitmap.width; h = fgo->bitmap.rows;
468    // skip if totally clipped out
469    if ((y >= (cy + ch)) || ((y + h) <= cy) ||
470        (x >= (cx + cw)) || ((x + w) <= cx)) return;
471    // figure y1/y2 limit range
472    y1 = 0; y2 = h;
473    if ((y + y1) < cy) y1 = cy - y;
474    if ((y + y2) > (cy + ch)) y2 = cy + ch - y;
475    // figure x1/x2 limit range
476    x1 = 0; x2 = w;
477    if ((x + x1) < cx) x1 = cx - x;
478    if ((x + x2) > (cx + cw)) x2 = cx + cw - x;
479    col = dc->col.col;
480    if (dst_image->cache_entry.space == EVAS_COLORSPACE_GRY8)
481      {
482         // FIXME: Font draw not optimized for Alpha targets! SLOW!
483         // This is not pretty :)
484 
485         DATA8 *src8, *dst8;
486         Draw_Func_Alpha func;
487         int row;
488 
489         if (EINA_UNLIKELY(x < 0))
490           {
491              x1 += (-x);
492              x = 0;
493              if ((x2 - x1) <= 0) return;
494           }
495         if (EINA_UNLIKELY(y < 0))
496           {
497              y1 += (-y);
498              y = 0;
499              if ((y2 - y1) <= 0) return;
500           }
501 
502         dst8 = dst_image->image.data8 + x + (y * dst_pitch);
503         func = efl_draw_alpha_func_get(dc->render_op, EINA_FALSE);
504         src8 = evas_common_font_glyph_uncompress(fg, NULL, NULL);
505         if (!src8) return;
506 
507         for (row = y1; row < y2; row++)
508           {
509              DATA8 *d = dst8 + ((row - y1) * dst_pitch);
510              DATA8 *s = src8 + (row * w) + x1;
511              func(d, s, x2 - x1);
512           }
513         free(src8);
514      }
515    else if (dc->clip.mask)
516      {
517         RGBA_Gfx_Func func;
518         DATA8 *src8, *mask;
519         DATA32 *buf, *ptr, *buf_ptr;
520         RGBA_Image *im = dc->clip.mask;
521         int row;
522 
523         buf = alloca(sizeof(DATA32) * w * h);
524 
525         // Adjust clipping info
526         if (EINA_UNLIKELY((x + x1) < dc->clip.mask_x))
527           x1 = dc->clip.mask_x - x;
528         if (EINA_UNLIKELY((y + y1) < dc->clip.mask_y))
529           y1 = dc->clip.mask_y - y;
530         if (EINA_UNLIKELY((x + x2) > (int)(x + x1 + im->cache_entry.w)))
531           x2 = x1 + im->cache_entry.w;
532         if (EINA_UNLIKELY((y + y2) > (int)(y + y1 + im->cache_entry.h)))
533           y2 = y1 + im->cache_entry.h;
534 
535         // Step 1: alpha glyph drawing
536         src8 = evas_common_font_glyph_uncompress(fg, NULL, NULL);
537         if (!src8) return;
538 
539         // Step 2: color blending to buffer
540         func = evas_common_gfx_func_composite_mask_color_span_get(col, dst_image->cache_entry.flags.alpha, 1, EVAS_RENDER_COPY);
541         for (row = y1; row < y2; row++)
542           {
543              buf_ptr = buf + (row * w) + x1;
544              DATA8 *s = src8 + (row * w) + x1;
545              func(NULL, s, col, buf_ptr, x2 - x1);
546           }
547         free(src8);
548 
549         // Step 3: masking to destination
550         func = evas_common_gfx_func_composite_pixel_mask_span_get(im->cache_entry.flags.alpha, im->cache_entry.flags.alpha_sparse, dst_image->cache_entry.flags.alpha, dst_pitch, dc->render_op);
551         for (row = y1; row < y2; row++)
552           {
553              mask = im->image.data8
554                 + (y + row - dc->clip.mask_y) * im->cache_entry.w
555                 + (x + x1 - dc->clip.mask_x);
556 
557              ptr = dst + (x + x1) + ((y + row) * dst_pitch);
558              buf_ptr = buf + (row * w) + x1;
559              func(buf_ptr, mask, 0, ptr, x2 - x1);
560           }
561      }
562    else
563      {
564         // build fast multiply + mask color tables to avoid compute. this works
565         // because of our very limited 4bit range of alpha values
566         for (i = 0; i <= 0xf; i++)
567           {
568              v = (i << 4) | i;
569              coltab[i] = MUL_SYM(v, col);
570              mtab[i] = 256 - (coltab[i] >> 24);
571           }
572 #ifdef BUILD_MMX
573         if (evas_common_cpu_has_feature(CPU_FEATURE_MMX))
574           {
575 #define MMX 1
576 #include "evas_font_compress_draw.c"
577 #undef MMX
578           }
579         else
580 #endif
581 
582 #ifdef BUILD_NEON
583         if (evas_common_cpu_has_feature(CPU_FEATURE_NEON))
584           {
585 #define NEON 1
586 #include "evas_font_compress_draw.c"
587 #undef NEON
588           }
589         else
590 #endif
591 
592           // Plain C
593           {
594 #include "evas_font_compress_draw.c"
595           }
596      }
597 }
598 
599