aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/engines/common/evas_font_draw.c
diff options
context:
space:
mode:
authorDavid Walter Seikel2012-01-04 18:41:13 +1000
committerDavid Walter Seikel2012-01-04 18:41:13 +1000
commitdd7595a3475407a7fa96a97393bae8c5220e8762 (patch)
treee341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/evas/src/lib/engines/common/evas_font_draw.c
parentAdd the skeleton. (diff)
downloadSledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz
Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
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.c615
1 files changed, 615 insertions, 0 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
new file mode 100644
index 0000000..94aa085
--- /dev/null
+++ b/libraries/evas/src/lib/engines/common/evas_font_draw.c
@@ -0,0 +1,615 @@
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 if ((j > 0) && (chr_x + w > ext_x))
253 {
254 if ((fg->ext_dat) && (dc->font_ext.func.gl_draw))
255 {
256 /* ext glyph draw */
257 dc->font_ext.func.gl_draw(dc->font_ext.data,
258 (void *)dst,
259 dc, fg, chr_x,
260 y - (chr_y - y));
261 }
262 else
263 {
264 if ((fg->glyph_out->bitmap.num_grays == 256) &&
265 (fg->glyph_out->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY))
266 {
267 for (i = 0; i < h; i++)
268 {
269 int dx, dy;
270 int in_x, in_w;
271
272 in_x = 0;
273 in_w = 0;
274 dx = chr_x;
275 dy = y - (chr_y - i - y);
276#ifdef EVAS_SLI
277 if (((dy) % dc->sli.h) == dc->sli.y)
278#endif
279 {
280 if ((dx < (ext_x + ext_w)) &&
281 (dy >= (ext_y)) &&
282 (dy < (ext_y + ext_h)))
283 {
284 if (dx + w > (ext_x + ext_w))
285 in_w += (dx + w) - (ext_x + ext_w);
286 if (dx < ext_x)
287 {
288 in_w += ext_x - dx;
289 in_x = ext_x - dx;
290 dx = ext_x;
291 }
292 if (in_w < w)
293 {
294 func(NULL, data + (i * j) + in_x, dc->col.col,
295 im + (dy * im_w) + dx, w - in_w);
296 }
297 }
298 }
299 }
300 }
301 else
302 {
303 DATA8 *tmpbuf = NULL, *dp, *tp, bits;
304 int bi, bj;
305 const DATA8 bitrepl[2] = {0x0, 0xff};
306
307 tmpbuf = alloca(w);
308 for (i = 0; i < h; i++)
309 {
310 int dx, dy;
311 int in_x, in_w, end;
312
313 in_x = 0;
314 in_w = 0;
315 dx = chr_x;
316 dy = y - (chr_y - i - y);
317#ifdef EVAS_SLI
318 if (((dy) % dc->sli.h) == dc->sli.y)
319#endif
320 {
321 tp = tmpbuf;
322 dp = data + (i * fg->glyph_out->bitmap.pitch);
323 for (bi = 0; bi < w; bi += 8)
324 {
325 bits = *dp;
326 if ((w - bi) < 8) end = w - bi;
327 else end = 8;
328 for (bj = 0; bj < end; bj++)
329 {
330 *tp = bitrepl[(bits >> (7 - bj)) & 0x1];
331 tp++;
332 }
333 dp++;
334 }
335 if ((dx < (ext_x + ext_w)) &&
336 (dy >= (ext_y)) &&
337 (dy < (ext_y + ext_h)))
338 {
339 if (dx + w > (ext_x + ext_w))
340 in_w += (dx + w) - (ext_x + ext_w);
341 if (dx < ext_x)
342 {
343 in_w += ext_x - dx;
344 in_x = ext_x - dx;
345 dx = ext_x;
346 }
347 if (in_w < w)
348 {
349 func(NULL, tmpbuf + in_x, dc->col.col,
350 im + (dy * im_w) + dx, w - in_w);
351 }
352 }
353 }
354 }
355 }
356 }
357 }
358 }
359 }
360 else
361 break;
362 }
363 EVAS_FONT_WALK_TEXT_END();
364 evas_common_font_int_use_trim();
365}
366
367EAPI void
368evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int x, int y, const Evas_Text_Props *text_props)
369{
370 int ext_x, ext_y, ext_w, ext_h;
371 int im_w, im_h;
372 RGBA_Gfx_Func func;
373 Cutout_Rects *rects;
374 Cutout_Rect *r;
375 int c, cx, cy, cw, ch;
376 int i;
377
378 im_w = dst->cache_entry.w;
379 im_h = dst->cache_entry.h;
380
381 ext_x = 0; ext_y = 0; ext_w = im_w; ext_h = im_h;
382 if (dc->clip.use)
383 {
384 ext_x = dc->clip.x;
385 ext_y = dc->clip.y;
386 ext_w = dc->clip.w;
387 ext_h = dc->clip.h;
388 if (ext_x < 0)
389 {
390 ext_w += ext_x;
391 ext_x = 0;
392 }
393 if (ext_y < 0)
394 {
395 ext_h += ext_y;
396 ext_y = 0;
397 }
398 if ((ext_x + ext_w) > im_w)
399 ext_w = im_w - ext_x;
400 if ((ext_y + ext_h) > im_h)
401 ext_h = im_h - ext_y;
402 }
403 if (ext_w <= 0) return;
404 if (ext_h <= 0) return;
405
406#ifdef EVAS_FRAME_QUEUING
407 LKL(fn->lock);
408#endif
409// evas_common_font_size_use(fn);
410 func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst, 1, dc->render_op);
411
412 if (!dc->cutout.rects)
413 {
414 evas_common_font_draw_internal(dst, dc, fn, x, y, text_props,
415 func, ext_x, ext_y, ext_w, ext_h,
416 im_w, im_h);
417 }
418 else
419 {
420 c = dc->clip.use; cx = dc->clip.x; cy = dc->clip.y; cw = dc->clip.w; ch = dc->clip.h;
421 evas_common_draw_context_clip_clip(dc, 0, 0, dst->cache_entry.w, dst->cache_entry.h);
422 /* our clip is 0 size.. abort */
423 if ((dc->clip.w > 0) && (dc->clip.h > 0))
424 {
425 rects = evas_common_draw_context_apply_cutouts(dc);
426 for (i = 0; i < rects->active; ++i)
427 {
428 r = rects->rects + i;
429 evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h);
430 evas_common_font_draw_internal(dst, dc, fn, x, y, text_props,
431 func, r->x, r->y, r->w, r->h,
432 im_w, im_h);
433 }
434 evas_common_draw_context_apply_clear_cutouts(rects);
435 }
436 dc->clip.use = c; dc->clip.x = cx; dc->clip.y = cy; dc->clip.w = cw; dc->clip.h = ch;
437 }
438#ifdef EVAS_FRAME_QUEUING
439 LKU(fn->lock);
440#endif
441}
442
443/* Only used if cache is on */
444#if defined(METRIC_CACHE) || defined(WORD_CACHE)
445
446static Eina_Bool
447_evas_font_word_prerender_text_props_equal(const Evas_Text_Props *_a, const Evas_Text_Props *_b)
448{
449 Evas_Font_Glyph_Info *gl1, *gl2;
450 size_t i;
451
452 if ((_a->len != _b->len) ||
453 (_a->font_instance != _b->font_instance))
454 return EINA_FALSE;
455
456 gl1 = _a->info->glyph + _a->start;
457 gl2 = _b->info->glyph + _b->start;
458 i = _a->len;
459 for ( ; (i > 0) && (gl1->index == gl2->index) ; i--, gl1++, gl2++)
460 ;
461
462 return (i == 0);
463}
464
465static struct prword *
466evas_font_word_prerender(RGBA_Draw_Context *dc, const Evas_Text_Props *text_props)
467{
468 struct cinfo *metrics;
469 unsigned char *im;
470 int width;
471 int height, above, below, baseline, descent;
472 unsigned int i,j;
473 struct prword *w;
474 int last_delta = 0;
475 Eina_Unicode gl;
476 struct cinfo *ci;
477 unsigned int len = text_props->len;
478 RGBA_Font_Int *fi = (RGBA_Font_Int *) text_props->font_instance;
479 EVAS_FONT_WALK_TEXT_INIT();
480
481# ifndef METRIC_CACHE
482 gl = dc->font_ext.func.gl_new ? 1: 0;
483 if (gl) return NULL;
484# endif
485
486 LKL(lock_words);
487 EINA_INLIST_FOREACH(words,w)
488 {
489 if (_evas_font_word_prerender_text_props_equal(&w->text_props,
490 text_props))
491 {
492 words = eina_inlist_promote(words, EINA_INLIST_GET(w));
493 LKU(lock_words);
494 return w;
495 }
496 }
497 LKU(lock_words);
498
499 gl = dc->font_ext.func.gl_new ? 1: 0;
500
501 above = 0; below = 0; baseline = 0; height = 0; descent = 0;
502
503 /* First pass: Work out how big and populate */
504 metrics = malloc(sizeof(struct cinfo) * len);
505 ci = metrics;
506 EVAS_FONT_WALK_TEXT_START()
507 {
508 FT_UInt index;
509 RGBA_Font_Glyph *fg;
510 index = EVAS_FONT_WALK_INDEX;
511 LKL(fi->ft_mutex);
512 fg = evas_common_font_int_cache_glyph_get(fi, index);
513 if (!fg)
514 {
515 LKU(fi->ft_mutex);
516 continue;
517 }
518
519 LKU(fi->ft_mutex);
520 EVAS_FONT_WALK_TEXT_WORK();
521 /* Currently broken with invisible chars if (!EVAS_FONT_WALK_IS_VISIBLE) continue; */
522 ci->index = index;
523 ci->fg = fg;
524
525 if (gl)
526 {
527 ci->fg->ext_dat =dc->font_ext.func.gl_new(dc->font_ext.data,ci->fg);
528 ci->fg->ext_dat_free = dc->font_ext.func.gl_free;
529 }
530 ci->bm.data = ci->fg->glyph_out->bitmap.buffer;
531 ci->bm.w = MAX(ci->fg->glyph_out->bitmap.pitch,
532 ci->fg->glyph_out->bitmap.width);
533 ci->bm.rows = ci->fg->glyph_out->bitmap.rows;
534 ci->bm.h = ci->fg->glyph_out->top;
535 above = ci->bm.rows - (ci->bm.rows - ci->bm.h);
536 below = ci->bm.rows - ci->bm.h;
537 if (below > descent) descent = below;
538 if (above > baseline) baseline = above;
539 ci->pos.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
540 ci->pos.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
541 last_delta = EVAS_FONT_WALK_X_ADV -
542 (ci->bm.w + ci->fg->glyph_out->left);
543 ci++;
544 }
545 EVAS_FONT_WALK_TEXT_END();
546
547 /* First loop done */
548 width = EVAS_FONT_WALK_PEN_X;
549 if (last_delta < 0)
550 width -= last_delta;
551 width = (width & 0x7) ? width + (8 - (width & 0x7)) : width;
552
553 height = baseline + descent;
554 if (!gl)
555 {
556 im = calloc(height, width);
557 for (i = 0 ; i < len ; i ++)
558 {
559 struct cinfo *cin = metrics + i;
560
561 for (j = 0 ; j < cin->bm.rows ; j ++)
562 {
563 int correction; /* Used to remove negative inset and such */
564 if (cin->pos.x < 0)
565 correction = -cin->pos.x;
566 else
567 correction = 0;
568
569 memcpy(im + cin->pos.x + (j + baseline - cin->bm.h) * width +
570 correction,
571 cin->bm.data + j * cin->bm.w + correction,
572 cin->bm.w - correction);
573 }
574 }
575 }
576 else
577 {
578 im = NULL;
579 }
580
581 /* Save it */
582 struct prword *save;
583
584 save = malloc(sizeof(struct prword));
585 save->cinfo = metrics;
586 evas_common_text_props_content_copy_and_ref(&save->text_props, text_props);
587 save->im = im;
588 save->width = EVAS_FONT_WALK_PEN_X;
589 if (last_delta < 0)
590 save->width += last_delta;
591 save->roww = width;
592 save->height = height;
593 save->baseline = baseline;
594 LKL(lock_words);
595 words = eina_inlist_prepend(words, EINA_INLIST_GET(save));
596
597 /* Clean up if too long */
598 if (eina_inlist_count(words) > max_cached_words)
599 {
600 struct prword *last = (struct prword *)(words->last);
601
602 if (last)
603 {
604 if (last->im) free(last->im);
605 if (last->cinfo) free(last->cinfo);
606 evas_common_text_props_content_unref(&last->text_props);
607 words = eina_inlist_remove(words, EINA_INLIST_GET(last));
608 free(last);
609 }
610 }
611 LKU(lock_words);
612
613 return save;
614}
615#endif