aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/engines/common/evas_font_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/lib/engines/common/evas_font_draw.c')
-rw-r--r--libraries/evas/src/lib/engines/common/evas_font_draw.c658
1 files changed, 0 insertions, 658 deletions
diff --git a/libraries/evas/src/lib/engines/common/evas_font_draw.c b/libraries/evas/src/lib/engines/common/evas_font_draw.c
deleted file mode 100644
index 638cdfe..0000000
--- a/libraries/evas/src/lib/engines/common/evas_font_draw.c
+++ /dev/null
@@ -1,658 +0,0 @@
1#include "evas_common.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
10/* Forcibly disable the broken word/metric caching. */
11#ifdef METRIC_CACHE
12# undef METRIC_CACHE
13#endif
14
15#ifdef WORD_CACHE
16# undef WORD_CACHE
17#endif
18
19#define WORD_CACHE_MAXLEN 50
20/* How many to cache */
21#define WORD_CACHE_NWORDS 40
22
23static int max_cached_words = WORD_CACHE_NWORDS;
24
25struct prword
26{
27 EINA_INLIST;
28 struct cinfo *cinfo;
29 Evas_Text_Props text_props;
30 DATA8 *im;
31 int roww;
32 int width;
33 int height;
34 int baseline;
35};
36
37struct cinfo
38{
39 FT_UInt index;
40 struct
41 {
42 int x, y;
43 } pos;
44 int posx;
45 RGBA_Font_Glyph *fg;
46 struct
47 {
48 int w,h;
49 int rows;
50 unsigned char *data;
51 } bm;
52};
53
54
55#if defined(METRIC_CACHE) || defined(WORD_CACHE)
56LK(lock_words); // for word cache call
57static Eina_Inlist *words = NULL;
58static struct prword *evas_font_word_prerender(RGBA_Draw_Context *dc, const Evas_Text_Props *text_props);
59#endif
60
61EAPI void
62evas_common_font_draw_init(void)
63{
64 char *p;
65 int tmp;
66
67 if ((p = getenv("EVAS_WORD_CACHE_MAX_WORDS")))
68 {
69 tmp = strtol(p,NULL,10);
70 /* 0 to disable of course */
71 if (tmp > -1 && tmp < 500){
72 max_cached_words = tmp;
73 }
74 }
75}
76
77#ifdef EVAS_FRAME_QUEUING
78EAPI void
79evas_common_font_draw_finish(void)
80{
81}
82#endif
83
84/*
85 * BiDi handling: We receive the shaped string + other props from text_props,
86 * we need to reorder it so we'll have the visual string (the way we draw)
87 * and then for kerning we have to switch the order of the kerning query (as the prev
88 * is on the right, and not on the left).
89 */
90static void
91evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn __UNUSED__, int x, int y,
92 const Evas_Text_Props *text_props, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w,
93 int ext_h, int im_w, int im_h __UNUSED__)
94{
95 DATA32 *im;
96 RGBA_Font_Int *fi;
97 EVAS_FONT_WALK_TEXT_INIT();
98
99 fi = text_props->font_instance;
100 if (!fi) return;
101
102 evas_common_font_int_reload(fi);
103
104 if (fi->src->current_size != fi->size)
105 {
106 FTLOCK();
107 FT_Activate_Size(fi->ft.size);
108 FTUNLOCK();
109 fi->src->current_size = fi->size;
110 }
111
112
113#if defined(METRIC_CACHE) || defined(WORD_CACHE)
114 unsigned int len;
115
116 len = text_props->len;
117
118 if (len > 2 && (len < WORD_CACHE_MAXLEN))
119 {
120 struct prword *word;
121
122 word =
123 evas_font_word_prerender(dc, text_props);
124 if (word)
125 {
126 int j, rowstart, rowend, xstart, xrun;
127
128 im = dst->image.data;
129 xrun = word->width;
130 y -= word->baseline;
131 xstart = 0;
132 rowstart = 0;
133 rowend = word->height;
134 /* Clip to extent */
135 if (x + xrun > ext_x + ext_w)
136 {
137 xrun -= x + xrun - ext_x - ext_w;
138 }
139 if (x < ext_x)
140 {
141 int excess = ext_x - x;
142 xstart = excess - 1;
143 xrun -= excess;
144 x = ext_x;
145 }
146 if (y + rowend > ext_y + ext_h)
147 {
148 rowend -= (y - ext_y + rowend - ext_h);
149 }
150 if (y < ext_y)
151 {
152 int excess = ext_y - y;
153 rowstart += excess;
154 //rowend -= excess;
155 // y = ext_y;
156 }
157
158 if (xrun < 1) return;
159/* For some reason, metric and word chache are exactly the same except for
160 * this piece of code that makes metric go nuts. ATM, we'll just go the
161 * WORD_CACHE path. */
162#if defined(METRIC_CACHE) || defined(WORD_CACHE)
163 if (word->im)
164 {
165 for (j = rowstart ; j < rowend ; j ++)
166 {
167 func(NULL, word->im + (word->roww * j) + xstart, dc->col.col,
168 im + ((y + j) * im_w) + x, xrun);
169 }
170 return;
171 }
172# elif defined(METRIC_CACHE)
173 unsigned int ind;
174
175 y += word->baseline;
176 for (ind = 0 ; ind < len ; ind ++)
177 {
178 // FIXME Do we need to draw?
179 struct cinfo *ci = word->cinfo + ind;
180 for (j = rowstart ; j < rowend ; j ++)
181 {
182 if ((ci->fg->ext_dat) && (dc->font_ext.func.gl_draw))
183 {
184 /* ext glyph draw */
185 dc->font_ext.func.gl_draw(dc->font_ext.data,
186 (void *)dst,
187 dc, ci->fg,
188 x + ci->pos.x,
189 y - ci->bm.h + j);
190 }
191 else
192 {
193 func(NULL, word->im + (word->roww * j) + xstart,
194 dc->col.col, im + ((y + j) * im_w) + x, xrun);
195 }
196 }
197 }
198 return;
199# endif
200 }
201 }
202#endif
203
204 im = dst->image.data;
205
206 EVAS_FONT_WALK_TEXT_START()
207 {
208 FT_UInt idx;
209 RGBA_Font_Glyph *fg;
210 int chr_x, chr_y;
211
212 if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
213
214 idx = EVAS_FONT_WALK_INDEX;
215
216 LKL(fi->ft_mutex);
217 fg = evas_common_font_int_cache_glyph_get(fi, idx);
218 if (!fg)
219 {
220 LKU(fi->ft_mutex);
221 continue;
222 }
223
224 LKU(fi->ft_mutex);
225
226 if (dc->font_ext.func.gl_new)
227 {
228 /* extension calls */
229 fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg);
230 fg->ext_dat_free = dc->font_ext.func.gl_free;
231 }
232
233 chr_x = x + EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
234 chr_y = y + EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
235
236 if (chr_x < (ext_x + ext_w))
237 {
238 DATA8 *data;
239 int i, j, w, h;
240
241 data = fg->glyph_out->bitmap.buffer;
242 j = fg->glyph_out->bitmap.pitch;
243 w = fg->glyph_out->bitmap.width;
244 if (j < w) j = w;
245 h = fg->glyph_out->bitmap.rows;
246 /*
247 if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays)
248 && (fg->glyph_out->bitmap.num_grays == 256)
249 )
250 */
251
252#ifdef HAVE_PIXMAN
253# ifdef PIXMAN_FONT
254 int index;
255 DATA32 *font_alpha_buffer;
256 pixman_image_t *font_mask_image;
257
258 font_alpha_buffer = alloca(w * h * sizeof(DATA32));
259 for (index = 0; index < (w * h); index++)
260 font_alpha_buffer[index] = data[index] << 24;
261
262 font_mask_image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h,
263 font_alpha_buffer,
264 w * sizeof(DATA32));
265
266 if (!font_mask_image) return;
267# endif
268#endif
269
270 {
271 if ((j > 0) && (chr_x + w > ext_x))
272 {
273 if ((fg->ext_dat) && (dc->font_ext.func.gl_draw))
274 {
275 /* ext glyph draw */
276 dc->font_ext.func.gl_draw(dc->font_ext.data,
277 (void *)dst,
278 dc, fg, chr_x,
279 y - (chr_y - y));
280 }
281 else
282 {
283 if ((fg->glyph_out->bitmap.num_grays == 256) &&
284 (fg->glyph_out->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY))
285 {
286#ifdef HAVE_PIXMAN
287# ifdef PIXMAN_FONT
288 if ((dst->pixman.im) &&
289 (dc->col.pixman_color_image))
290 pixman_image_composite(PIXMAN_OP_OVER,
291 dc->col.pixman_color_image,
292 font_mask_image,
293 dst->pixman.im,
294 chr_x,
295 y - (chr_y - y),
296 0, 0,
297 chr_x,
298 y - (chr_y - y),
299 w, h);
300 else
301# endif
302#endif
303 {
304 for (i = 0; i < h; i++)
305 {
306 int dx, dy;
307 int in_x, in_w;
308
309 in_x = 0;
310 in_w = 0;
311 dx = chr_x;
312 dy = y - (chr_y - i - y);
313#ifdef EVAS_SLI
314 if (((dy) % dc->sli.h) == dc->sli.y)
315#endif
316 {
317 if ((dx < (ext_x + ext_w)) &&
318 (dy >= (ext_y)) &&
319 (dy < (ext_y + ext_h)))
320 {
321 if (dx + w > (ext_x + ext_w))
322 in_w += (dx + w) - (ext_x + ext_w);
323 if (dx < ext_x)
324 {
325 in_w += ext_x - dx;
326 in_x = ext_x - dx;
327 dx = ext_x;
328 }
329 if (in_w < w)
330 {
331 func(NULL, data + (i * j) + in_x, dc->col.col,
332 im + (dy * im_w) + dx, w - in_w);
333 }
334 }
335 }
336 }
337 }
338 }
339 else
340 {
341 DATA8 *tmpbuf = NULL, *dp, *tp, bits;
342 int bi, bj;
343 const DATA8 bitrepl[2] = {0x0, 0xff};
344
345 tmpbuf = alloca(w);
346 for (i = 0; i < h; i++)
347 {
348 int dx, dy;
349 int in_x, in_w, end;
350
351 in_x = 0;
352 in_w = 0;
353 dx = chr_x;
354 dy = y - (chr_y - i - y);
355#ifdef EVAS_SLI
356 if (((dy) % dc->sli.h) == dc->sli.y)
357#endif
358 {
359 tp = tmpbuf;
360 dp = data + (i * fg->glyph_out->bitmap.pitch);
361 for (bi = 0; bi < w; bi += 8)
362 {
363 bits = *dp;
364 if ((w - bi) < 8) end = w - bi;
365 else end = 8;
366 for (bj = 0; bj < end; bj++)
367 {
368 *tp = bitrepl[(bits >> (7 - bj)) & 0x1];
369 tp++;
370 }
371 dp++;
372 }
373 if ((dx < (ext_x + ext_w)) &&
374 (dy >= (ext_y)) &&
375 (dy < (ext_y + ext_h)))
376 {
377 if (dx + w > (ext_x + ext_w))
378 in_w += (dx + w) - (ext_x + ext_w);
379 if (dx < ext_x)
380 {
381 in_w += ext_x - dx;
382 in_x = ext_x - dx;
383 dx = ext_x;
384 }
385 if (in_w < w)
386 {
387 func(NULL, tmpbuf + in_x, dc->col.col,
388 im + (dy * im_w) + dx, w - in_w);
389 }
390 }
391 }
392 }
393 }
394 }
395 }
396 }
397#ifdef HAVE_PIXMAN
398# ifdef PIXMAN_FONT
399 pixman_image_unref(font_mask_image);
400# endif
401#endif
402 }
403 else
404 break;
405 }
406 EVAS_FONT_WALK_TEXT_END();
407 evas_common_font_int_use_trim();
408}
409
410EAPI void
411evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int x, int y, const Evas_Text_Props *text_props)
412{
413 int ext_x, ext_y, ext_w, ext_h;
414 int im_w, im_h;
415 RGBA_Gfx_Func func;
416 Cutout_Rects *rects;
417 Cutout_Rect *r;
418 int c, cx, cy, cw, ch;
419 int i;
420
421 im_w = dst->cache_entry.w;
422 im_h = dst->cache_entry.h;
423
424 ext_x = 0; ext_y = 0; ext_w = im_w; ext_h = im_h;
425 if (dc->clip.use)
426 {
427 ext_x = dc->clip.x;
428 ext_y = dc->clip.y;
429 ext_w = dc->clip.w;
430 ext_h = dc->clip.h;
431 if (ext_x < 0)
432 {
433 ext_w += ext_x;
434 ext_x = 0;
435 }
436 if (ext_y < 0)
437 {
438 ext_h += ext_y;
439 ext_y = 0;
440 }
441 if ((ext_x + ext_w) > im_w)
442 ext_w = im_w - ext_x;
443 if ((ext_y + ext_h) > im_h)
444 ext_h = im_h - ext_y;
445 }
446 if (ext_w <= 0) return;
447 if (ext_h <= 0) return;
448
449#ifdef EVAS_FRAME_QUEUING
450 LKL(fn->lock);
451#endif
452// evas_common_font_size_use(fn);
453 func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst, 1, dc->render_op);
454
455 if (!dc->cutout.rects)
456 {
457 evas_common_font_draw_internal(dst, dc, fn, x, y, text_props,
458 func, ext_x, ext_y, ext_w, ext_h,
459 im_w, im_h);
460 }
461 else
462 {
463 c = dc->clip.use; cx = dc->clip.x; cy = dc->clip.y; cw = dc->clip.w; ch = dc->clip.h;
464 evas_common_draw_context_clip_clip(dc, 0, 0, dst->cache_entry.w, dst->cache_entry.h);
465 /* our clip is 0 size.. abort */
466 if ((dc->clip.w > 0) && (dc->clip.h > 0))
467 {
468 rects = evas_common_draw_context_apply_cutouts(dc);
469 for (i = 0; i < rects->active; ++i)
470 {
471 r = rects->rects + i;
472 evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h);
473 evas_common_font_draw_internal(dst, dc, fn, x, y, text_props,
474 func, r->x, r->y, r->w, r->h,
475 im_w, im_h);
476 }
477 evas_common_draw_context_apply_clear_cutouts(rects);
478 }
479 dc->clip.use = c; dc->clip.x = cx; dc->clip.y = cy; dc->clip.w = cw; dc->clip.h = ch;
480 }
481#ifdef EVAS_FRAME_QUEUING
482 LKU(fn->lock);
483#endif
484}
485
486/* Only used if cache is on */
487#if defined(METRIC_CACHE) || defined(WORD_CACHE)
488
489static Eina_Bool
490_evas_font_word_prerender_text_props_equal(const Evas_Text_Props *_a, const Evas_Text_Props *_b)
491{
492 Evas_Font_Glyph_Info *gl1, *gl2;
493 size_t i;
494
495 if ((_a->len != _b->len) ||
496 (_a->font_instance != _b->font_instance))
497 return EINA_FALSE;
498
499 gl1 = _a->info->glyph + _a->start;
500 gl2 = _b->info->glyph + _b->start;
501 i = _a->len;
502 for ( ; (i > 0) && (gl1->index == gl2->index) ; i--, gl1++, gl2++)
503 ;
504
505 return (i == 0);
506}
507
508static struct prword *
509evas_font_word_prerender(RGBA_Draw_Context *dc, const Evas_Text_Props *text_props)
510{
511 struct cinfo *metrics;
512 unsigned char *im;
513 int width;
514 int height, above, below, baseline, descent;
515 unsigned int i,j;
516 struct prword *w;
517 int last_delta = 0;
518 Eina_Unicode gl;
519 struct cinfo *ci;
520 unsigned int len = text_props->len;
521 RGBA_Font_Int *fi = (RGBA_Font_Int *) text_props->font_instance;
522 EVAS_FONT_WALK_TEXT_INIT();
523
524# ifndef METRIC_CACHE
525 gl = dc->font_ext.func.gl_new ? 1: 0;
526 if (gl) return NULL;
527# endif
528
529 LKL(lock_words);
530 EINA_INLIST_FOREACH(words,w)
531 {
532 if (_evas_font_word_prerender_text_props_equal(&w->text_props,
533 text_props))
534 {
535 words = eina_inlist_promote(words, EINA_INLIST_GET(w));
536 LKU(lock_words);
537 return w;
538 }
539 }
540 LKU(lock_words);
541
542 gl = dc->font_ext.func.gl_new ? 1: 0;
543
544 above = 0; below = 0; baseline = 0; height = 0; descent = 0;
545
546 /* First pass: Work out how big and populate */
547 metrics = malloc(sizeof(struct cinfo) * len);
548 ci = metrics;
549 EVAS_FONT_WALK_TEXT_START()
550 {
551 FT_UInt index;
552 RGBA_Font_Glyph *fg;
553 index = EVAS_FONT_WALK_INDEX;
554 LKL(fi->ft_mutex);
555 fg = evas_common_font_int_cache_glyph_get(fi, index);
556 if (!fg)
557 {
558 LKU(fi->ft_mutex);
559 continue;
560 }
561
562 LKU(fi->ft_mutex);
563 EVAS_FONT_WALK_TEXT_WORK();
564 /* Currently broken with invisible chars if (!EVAS_FONT_WALK_IS_VISIBLE) continue; */
565 ci->index = index;
566 ci->fg = fg;
567
568 if (gl)
569 {
570 ci->fg->ext_dat =dc->font_ext.func.gl_new(dc->font_ext.data,ci->fg);
571 ci->fg->ext_dat_free = dc->font_ext.func.gl_free;
572 }
573 ci->bm.data = ci->fg->glyph_out->bitmap.buffer;
574 ci->bm.w = MAX(ci->fg->glyph_out->bitmap.pitch,
575 ci->fg->glyph_out->bitmap.width);
576 ci->bm.rows = ci->fg->glyph_out->bitmap.rows;
577 ci->bm.h = ci->fg->glyph_out->top;
578 above = ci->bm.rows - (ci->bm.rows - ci->bm.h);
579 below = ci->bm.rows - ci->bm.h;
580 if (below > descent) descent = below;
581 if (above > baseline) baseline = above;
582 ci->pos.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
583 ci->pos.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
584 last_delta = EVAS_FONT_WALK_X_ADV -
585 (ci->bm.w + ci->fg->glyph_out->left);
586 ci++;
587 }
588 EVAS_FONT_WALK_TEXT_END();
589
590 /* First loop done */
591 width = EVAS_FONT_WALK_PEN_X;
592 if (last_delta < 0)
593 width -= last_delta;
594 width = (width & 0x7) ? width + (8 - (width & 0x7)) : width;
595
596 height = baseline + descent;
597 if (!gl)
598 {
599 im = calloc(height, width);
600 for (i = 0 ; i < len ; i ++)
601 {
602 struct cinfo *cin = metrics + i;
603
604 for (j = 0 ; j < cin->bm.rows ; j ++)
605 {
606 int correction; /* Used to remove negative inset and such */
607 if (cin->pos.x < 0)
608 correction = -cin->pos.x;
609 else
610 correction = 0;
611
612 memcpy(im + cin->pos.x + (j + baseline - cin->bm.h) * width +
613 correction,
614 cin->bm.data + j * cin->bm.w + correction,
615 cin->bm.w - correction);
616 }
617 }
618 }
619 else
620 {
621 im = NULL;
622 }
623
624 /* Save it */
625 struct prword *save;
626
627 save = malloc(sizeof(struct prword));
628 save->cinfo = metrics;
629 evas_common_text_props_content_copy_and_ref(&save->text_props, text_props);
630 save->im = im;
631 save->width = EVAS_FONT_WALK_PEN_X;
632 if (last_delta < 0)
633 save->width += last_delta;
634 save->roww = width;
635 save->height = height;
636 save->baseline = baseline;
637 LKL(lock_words);
638 words = eina_inlist_prepend(words, EINA_INLIST_GET(save));
639
640 /* Clean up if too long */
641 if (eina_inlist_count(words) > max_cached_words)
642 {
643 struct prword *last = (struct prword *)(words->last);
644
645 if (last)
646 {
647 if (last->im) free(last->im);
648 if (last->cinfo) free(last->cinfo);
649 evas_common_text_props_content_unref(&last->text_props);
650 words = eina_inlist_remove(words, EINA_INLIST_GET(last));
651 free(last);
652 }
653 }
654 LKU(lock_words);
655
656 return save;
657}
658#endif