Fix issue when using word-cache: Make sure we have a 'last' word

before trying to free it, else we segfault.

Fix compiler warnings wrt const vs non-const of Evas_BiDi_Props.
Fix formatting and remove whitespace also.

NB: The major change here is in evas_font_word_prerender wrt freeing
the 'last' word of the cache.



SVN revision: 53166
This commit is contained in:
Christopher Michael 2010-10-07 21:07:53 +00:00
parent 9910581b1c
commit 2f3b2b99e5
1 changed files with 362 additions and 352 deletions

View File

@ -5,37 +5,43 @@
#include "evas_bidi_utils.h" /*defines BIDI_SUPPORT if possible */ #include "evas_bidi_utils.h" /*defines BIDI_SUPPORT if possible */
#include "evas_font_private.h" /* for Frame-Queuing support */ #include "evas_font_private.h" /* for Frame-Queuing support */
#define WORD_CACHE_MAXLEN 50 #define WORD_CACHE_MAXLEN 50
/* How many to cache */ /* How many to cache */
#define WORD_CACHE_NWORDS 40 #define WORD_CACHE_NWORDS 40
static int max_cached_words = WORD_CACHE_NWORDS; static int max_cached_words = WORD_CACHE_NWORDS;
struct prword { struct prword
EINA_INLIST; {
/* FIXME: Need to save font/size et al */ EINA_INLIST;
int size; /* FIXME: Need to save font/size et al */
struct cinfo *cinfo; int size;
RGBA_Font *font; struct cinfo *cinfo;
const Eina_Unicode *str; RGBA_Font *font;
int len; const Eina_Unicode *str;
DATA8 *im; int len;
int roww; DATA8 *im;
int width; int roww;
int height; int width;
int baseline; int height;
int baseline;
}; };
struct cinfo { struct cinfo
int gl; {
FT_UInt index; int gl;
struct { int x, y; } pos; FT_UInt index;
int posx; struct
RGBA_Font_Glyph *fg; {
struct { int x, y;
int w,h; } pos;
int rows; int posx;
unsigned char *data; RGBA_Font_Glyph *fg;
} bm; struct
{
int w,h;
int rows;
unsigned char *data;
} bm;
}; };
@ -50,6 +56,7 @@ evas_common_font_draw_init(void)
{ {
char *p; char *p;
int tmp; int tmp;
if ((p = getenv("EVAS_WORD_CACHE_MAX_WORDS"))) if ((p = getenv("EVAS_WORD_CACHE_MAX_WORDS")))
{ {
tmp = strtol(p,NULL,10); tmp = strtol(p,NULL,10);
@ -71,7 +78,7 @@ static void
_fash_int_free(Fash_Int *fash) _fash_int_free(Fash_Int *fash)
{ {
int i; int i;
for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]); for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]);
free(fash); free(fash);
} }
@ -100,7 +107,7 @@ static void
_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int index) _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int index)
{ {
int maj, min; int maj, min;
item &= 0xffff; // fixme: to do > 65k item &= 0xffff; // fixme: to do > 65k
maj = (item >> 8) & 0xff; maj = (item >> 8) & 0xff;
min = item & 0xff; min = item & 0xff;
@ -110,15 +117,11 @@ _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int index)
fash->bucket[maj]->item[min].index = index; fash->bucket[maj]->item[min].index = index;
} }
static void static void
_fash_gl_free(Fash_Glyph *fash) _fash_gl_free(Fash_Glyph *fash)
{ {
int i; int i;
for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]); for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]);
free(fash); free(fash);
} }
@ -147,7 +150,7 @@ static void
_fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph) _fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph)
{ {
int maj, min; int maj, min;
item &= 0xffff; // fixme: to do > 65k item &= 0xffff; // fixme: to do > 65k
maj = (item >> 8) & 0xff; maj = (item >> 8) & 0xff;
min = item & 0xff; min = item & 0xff;
@ -156,10 +159,6 @@ _fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph)
fash->bucket[maj]->item[min] = glyph; fash->bucket[maj]->item[min] = glyph;
} }
EAPI RGBA_Font_Glyph * EAPI RGBA_Font_Glyph *
evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index) evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
{ {
@ -175,9 +174,9 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
if (fg == (void *)(-1)) return NULL; if (fg == (void *)(-1)) return NULL;
else if (fg) return fg; else if (fg) return fg;
} }
hindex = index + (fi->hinting * 500000000); hindex = index + (fi->hinting * 500000000);
// fg = eina_hash_find(fi->glyphs, &hindex); // fg = eina_hash_find(fi->glyphs, &hindex);
// if (fg) return fg; // if (fg) return fg;
@ -214,22 +213,21 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
if (error) if (error)
{ {
FT_Done_Glyph(fg->glyph); FT_Done_Glyph(fg->glyph);
FTUNLOCK(); FTUNLOCK();
free(fg); free(fg);
if (!fi->fash) fi->fash = _fash_gl_new(); if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, index, (void *)(-1)); if (fi->fash) _fash_gl_add(fi->fash, index, (void *)(-1));
return NULL; return NULL;
} }
FTUNLOCK(); FTUNLOCK();
} }
fg->glyph_out = (FT_BitmapGlyph)fg->glyph; fg->glyph_out = (FT_BitmapGlyph)fg->glyph;
fg->index = hindex; fg->index = hindex;
fg->fi = fi; fg->fi = fi;
if (!fi->fash) fi->fash = _fash_gl_new(); if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, index, fg); if (fi->fash) _fash_gl_add(fi->fash, index, fg);
// eina_hash_direct_add(fi->glyphs, &fg->index, fg); // eina_hash_direct_add(fi->glyphs, &fg->index, fg);
return fg; return fg;
} }
@ -295,7 +293,7 @@ evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, int gl)
else if (fm->index == -1) return 0; else if (fm->index == -1) return 0;
} }
} }
for (l = fn->fonts; l; l = l->next) for (l = fn->fonts; l; l = l->next)
{ {
RGBA_Font_Int *fi; RGBA_Font_Int *fi;
@ -318,9 +316,9 @@ evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, int gl)
*fi_ret = fi; *fi_ret = fi;
return index; return index;
} }
} }
else else
*/ */
#endif #endif
if (!fi->src->ft.face) /* Charmap not loaded, FI/FS blank */ if (!fi->src->ft.face) /* Charmap not loaded, FI/FS blank */
@ -333,8 +331,8 @@ evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, int gl)
if (index == 0) if (index == 0)
{ {
// Load Hash // Load Hash
FT_ULong charcode; FT_ULong charcode;
FT_UInt gindex; FT_UInt gindex;
fi->src->charmap = evas_array_hash_new(); fi->src->charmap = evas_array_hash_new();
charcode = FT_Get_First_Char(fi->src->ft.face, &gindex); charcode = FT_Get_First_Char(fi->src->ft.face, &gindex);
@ -380,7 +378,6 @@ evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, int gl)
return 0; return 0;
} }
/* /*
* BiDi handling: We receive the shaped string + other props from intl_props, * BiDi handling: We receive the shaped string + other props from intl_props,
* we need to reorder it so we'll have the visual string (the way we draw) * we need to reorder it so we'll have the visual string (the way we draw)
@ -402,83 +399,94 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font
int c; int c;
int char_index = 0; /* the index of the current char */ int char_index = 0; /* the index of the current char */
#if defined(METRIC_CACHE) || defined(WORD_CACHE) #if defined(METRIC_CACHE) || defined(WORD_CACHE)
unsigned int len; unsigned int len;
/* A fast strNlen would be nice (there is a wcsnlen strangely) */ /* A fast strNlen would be nice (there is a wcsnlen strangely) */
len = eina_unicode_strnlen(text,WORD_CACHE_MAXLEN); len = eina_unicode_strnlen(text,WORD_CACHE_MAXLEN);
if (len > 2 && len < WORD_CACHE_MAXLEN){ if (len > 2 && len < WORD_CACHE_MAXLEN)
struct prword *word = evas_font_word_prerender(dc, text, intl_props, len, fn, fi, {
use_kerning); struct prword *word;
if (word){
int j,rowstart,rowend,xstart,xrun;
im = dst->image.data;
xrun = word->width;
y -= word->baseline;
xstart = 0;
rowstart = 0;
rowend = word->height;
/* Clip to extent */
if (x + xrun > ext_x + ext_w){
xrun -= x + xrun - ext_x - ext_w;
}
if (x < ext_x) {
int excess = ext_x - x;
xstart = excess - 1;
xrun -= excess;
x = ext_x;
}
if (y + rowend > ext_y + ext_h){
rowend -= (y - ext_y + rowend - ext_h);
}
if (y < ext_y){
int excess = ext_y - y;
rowstart += excess;
//rowend -= excess;
// y = ext_y;
}
if (xrun < 1) return; word =
evas_font_word_prerender(dc, text, (Evas_BiDi_Props *)intl_props,
len, fn, fi, use_kerning);
if (word)
{
int j, rowstart, rowend, xstart, xrun;
im = dst->image.data;
xrun = word->width;
y -= word->baseline;
xstart = 0;
rowstart = 0;
rowend = word->height;
/* Clip to extent */
if (x + xrun > ext_x + ext_w)
{
xrun -= x + xrun - ext_x - ext_w;
}
if (x < ext_x)
{
int excess = ext_x - x;
xstart = excess - 1;
xrun -= excess;
x = ext_x;
}
if (y + rowend > ext_y + ext_h)
{
rowend -= (y - ext_y + rowend - ext_h);
}
if (y < ext_y)
{
int excess = ext_y - y;
rowstart += excess;
//rowend -= excess;
// y = ext_y;
}
if (xrun < 1) return;
# ifdef WORD_CACHE # ifdef WORD_CACHE
if (word->im){ if (word->im)
for (j = rowstart ; j < rowend ; j ++){ {
func(NULL, word->im + (word->roww * j) + xstart, dc->col.col, for (j = rowstart ; j < rowend ; j ++)
im + ((y + j) * im_w) + x, xrun); {
} func(NULL, word->im + (word->roww * j) + xstart, dc->col.col,
return; im + ((y + j) * im_w) + x, xrun);
} }
return;
}
# elif defined(METRIC_CACHE) # elif defined(METRIC_CACHE)
int ind; int ind;
y += word->baseline;
for (ind = 0 ; ind < len ; ind ++){
// FIXME Do we need to draw?
struct cinfo *ci = word->cinfo + ind;
for (j = rowstart ; j < rowend ; j ++)
{
if ((ci->fg->ext_dat) && (dc->font_ext.func.gl_draw))
{
/* ext glyph draw */
dc->font_ext.func.gl_draw(dc->font_ext.data,
(void *)dst,
dc, ci->fg,
x + ci->pos.x,
y - ci->bm.h + j
);
}
else
{
func(NULL, word->im + (word->roww * j) + xstart,
dc->col.col, im + ((y + j) * im_w) + x, xrun);
}
}
}
return;
# endif
}
} y += word->baseline;
for (ind = 0 ; ind < len ; ind ++)
{
// FIXME Do we need to draw?
struct cinfo *ci = word->cinfo + ind;
for (j = rowstart ; j < rowend ; j ++)
{
if ((ci->fg->ext_dat) && (dc->font_ext.func.gl_draw))
{
/* ext glyph draw */
dc->font_ext.func.gl_draw(dc->font_ext.data,
(void *)dst,
dc, ci->fg,
x + ci->pos.x,
y - ci->bm.h + j);
}
else
{
func(NULL, word->im + (word->roww * j) + xstart,
dc->col.col, im + ((y + j) * im_w) + x, xrun);
}
}
}
return;
# endif
}
}
#endif #endif
#ifdef BIDI_SUPPORT #ifdef BIDI_SUPPORT
@ -499,7 +507,6 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font
intl_props = NULL; intl_props = NULL;
#endif #endif
pen_x = x; pen_x = x;
pen_y = y; pen_y = y;
last_adv = 0; last_adv = 0;
@ -532,169 +539,166 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font
/* hmmm kerning means i can't sanely do my own cached metric tables! */ /* hmmm kerning means i can't sanely do my own cached metric tables! */
/* grrr - this means font face sharing is kinda... not an option if */ /* grrr - this means font face sharing is kinda... not an option if */
/* you want performance */ /* you want performance */
if ((use_kerning) && (prev_index) && (index) && if ((use_kerning) && (prev_index) && (index) &&
(pface == fi->src->ft.face)) (pface == fi->src->ft.face))
{ {
if (evas_common_font_query_kerning(fi, prev_index, index, &kern)) if (evas_common_font_query_kerning(fi, prev_index, index, &kern))
pen_x += kern; pen_x += kern;
} }
pface = fi->src->ft.face; pface = fi->src->ft.face;
LKU(fi->ft_mutex); LKU(fi->ft_mutex);
if (dc->font_ext.func.gl_new) if (dc->font_ext.func.gl_new)
{ {
/* extension calls */ /* extension calls */
fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg); fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg);
fg->ext_dat_free = dc->font_ext.func.gl_free; fg->ext_dat_free = dc->font_ext.func.gl_free;
} }
/* If the current one is not a compositing char, do the previous advance /* If the current one is not a compositing char, do the previous advance
* and set the current advance as the next advance to do */ * and set the current advance as the next advance to do */
if (fg->glyph->advance.x >> 16 > 0) if (fg->glyph->advance.x >> 16 > 0)
{ {
pen_x += last_adv; pen_x += last_adv;
last_adv = fg->glyph->advance.x >> 16; last_adv = fg->glyph->advance.x >> 16;
} }
chr_x = (pen_x + (fg->glyph_out->left)); chr_x = (pen_x + (fg->glyph_out->left));
chr_y = (pen_y + (fg->glyph_out->top)); chr_y = (pen_y + (fg->glyph_out->top));
if (chr_x < (ext_x + ext_w)) if (chr_x < (ext_x + ext_w))
{ {
DATA8 *data; DATA8 *data;
int i, j, w, h; int i, j, w, h;
data = fg->glyph_out->bitmap.buffer; data = fg->glyph_out->bitmap.buffer;
j = fg->glyph_out->bitmap.pitch; j = fg->glyph_out->bitmap.pitch;
w = fg->glyph_out->bitmap.width; w = fg->glyph_out->bitmap.width;
if (j < w) j = w; if (j < w) j = w;
h = fg->glyph_out->bitmap.rows; h = fg->glyph_out->bitmap.rows;
/* /*
if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays) if ((fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays)
&& (fg->glyph_out->bitmap.num_grays == 256) && (fg->glyph_out->bitmap.num_grays == 256)
) )
*/ */
{ {
if ((j > 0) && (chr_x + w > ext_x)) if ((j > 0) && (chr_x + w > ext_x))
{ {
if ((fg->ext_dat) && (dc->font_ext.func.gl_draw)) if ((fg->ext_dat) && (dc->font_ext.func.gl_draw))
{ {
/* ext glyph draw */ /* ext glyph draw */
dc->font_ext.func.gl_draw(dc->font_ext.data, dc->font_ext.func.gl_draw(dc->font_ext.data,
(void *)dst, (void *)dst,
dc, fg, dc, fg, chr_x,
chr_x, y - (chr_y - y));
y - (chr_y - y) }
); else
} {
else if ((fg->glyph_out->bitmap.num_grays == 256) &&
{ (fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays))
if ((fg->glyph_out->bitmap.num_grays == 256) && {
(fg->glyph_out->bitmap.pixel_mode == ft_pixel_mode_grays)) for (i = 0; i < h; i++)
{ {
for (i = 0; i < h; i++) int dx, dy;
{ int in_x, in_w;
int dx, dy;
int in_x, in_w;
in_x = 0; in_x = 0;
in_w = 0; in_w = 0;
dx = chr_x; dx = chr_x;
dy = y - (chr_y - i - y); dy = y - (chr_y - i - y);
#ifdef EVAS_SLI #ifdef EVAS_SLI
if (((dy) % dc->sli.h) == dc->sli.y) if (((dy) % dc->sli.h) == dc->sli.y)
#endif #endif
{ {
if ((dx < (ext_x + ext_w)) && if ((dx < (ext_x + ext_w)) &&
(dy >= (ext_y)) && (dy >= (ext_y)) &&
(dy < (ext_y + ext_h))) (dy < (ext_y + ext_h)))
{ {
if (dx + w > (ext_x + ext_w)) if (dx + w > (ext_x + ext_w))
in_w += (dx + w) - (ext_x + ext_w); in_w += (dx + w) - (ext_x + ext_w);
if (dx < ext_x) if (dx < ext_x)
{ {
in_w += ext_x - dx; in_w += ext_x - dx;
in_x = ext_x - dx; in_x = ext_x - dx;
dx = ext_x; dx = ext_x;
} }
if (in_w < w) if (in_w < w)
{ {
func(NULL, data + (i * j) + in_x, dc->col.col, func(NULL, data + (i * j) + in_x, dc->col.col,
im + (dy * im_w) + dx, w - in_w); im + (dy * im_w) + dx, w - in_w);
} }
} }
} }
} }
} }
else else
{ {
DATA8 *tmpbuf = NULL, *dp, *tp, bits; DATA8 *tmpbuf = NULL, *dp, *tp, bits;
int bi, bj; int bi, bj;
const DATA8 bitrepl[2] = {0x0, 0xff}; const DATA8 bitrepl[2] = {0x0, 0xff};
tmpbuf = alloca(w); tmpbuf = alloca(w);
for (i = 0; i < h; i++) for (i = 0; i < h; i++)
{ {
int dx, dy; int dx, dy;
int in_x, in_w, end; int in_x, in_w, end;
in_x = 0; in_x = 0;
in_w = 0; in_w = 0;
dx = chr_x; dx = chr_x;
dy = y - (chr_y - i - y); dy = y - (chr_y - i - y);
#ifdef EVAS_SLI #ifdef EVAS_SLI
if (((dy) % dc->sli.h) == dc->sli.y) if (((dy) % dc->sli.h) == dc->sli.y)
#endif #endif
{ {
tp = tmpbuf; tp = tmpbuf;
dp = data + (i * fg->glyph_out->bitmap.pitch); dp = data + (i * fg->glyph_out->bitmap.pitch);
for (bi = 0; bi < w; bi += 8) for (bi = 0; bi < w; bi += 8)
{ {
bits = *dp; bits = *dp;
if ((w - bi) < 8) end = w - bi; if ((w - bi) < 8) end = w - bi;
else end = 8; else end = 8;
for (bj = 0; bj < end; bj++) for (bj = 0; bj < end; bj++)
{ {
*tp = bitrepl[(bits >> (7 - bj)) & 0x1]; *tp = bitrepl[(bits >> (7 - bj)) & 0x1];
tp++; tp++;
} }
dp++; dp++;
} }
if ((dx < (ext_x + ext_w)) && if ((dx < (ext_x + ext_w)) &&
(dy >= (ext_y)) && (dy >= (ext_y)) &&
(dy < (ext_y + ext_h))) (dy < (ext_y + ext_h)))
{ {
if (dx + w > (ext_x + ext_w)) if (dx + w > (ext_x + ext_w))
in_w += (dx + w) - (ext_x + ext_w); in_w += (dx + w) - (ext_x + ext_w);
if (dx < ext_x) if (dx < ext_x)
{ {
in_w += ext_x - dx; in_w += ext_x - dx;
in_x = ext_x - dx; in_x = ext_x - dx;
dx = ext_x; dx = ext_x;
} }
if (in_w < w) if (in_w < w)
{ {
func(NULL, tmpbuf + in_x, dc->col.col, func(NULL, tmpbuf + in_x, dc->col.col,
im + (dy * im_w) + dx, w - in_w); im + (dy * im_w) + dx, w - in_w);
} }
} }
} }
} }
} }
} }
c++; c++;
} }
} }
} }
else else
break; break;
prev_index = index; prev_index = index;
} }
#ifdef BIDI_SUPPORT #ifdef BIDI_SUPPORT
if (visual_text) free(visual_text); if (visual_text) free(visual_text);
#endif #endif
} }
EAPI void EAPI void
evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int x, int y, const Eina_Unicode *text, evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int x, int y, const Eina_Unicode *text,
const Evas_BiDi_Props *intl_props) const Evas_BiDi_Props *intl_props)
@ -706,8 +710,8 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int
RGBA_Font_Int *fi; RGBA_Font_Int *fi;
Cutout_Rects *rects; Cutout_Rects *rects;
Cutout_Rect *r; Cutout_Rect *r;
int c, cx, cy, cw, ch; int c, cx, cy, cw, ch;
int i; int i;
fi = fn->fonts->data; fi = fn->fonts->data;
@ -750,8 +754,7 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int
{ {
evas_common_font_draw_internal(dst, dc, fn, x, y, text, intl_props, evas_common_font_draw_internal(dst, dc, fn, x, y, text, intl_props,
func, ext_x, ext_y, ext_w, ext_h, fi, func, ext_x, ext_y, ext_w, ext_h, fi,
im_w, im_h, use_kerning im_w, im_h, use_kerning);
);
} }
else else
{ {
@ -767,8 +770,7 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int
evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h); evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h);
evas_common_font_draw_internal(dst, dc, fn, x, y, text, intl_props, evas_common_font_draw_internal(dst, dc, fn, x, y, text, intl_props,
func, r->x, r->y, r->w, r->h, fi, func, r->x, r->y, r->w, r->h, fi,
im_w, im_h, use_kerning im_w, im_h, use_kerning);
);
} }
evas_common_draw_context_apply_clear_cutouts(rects); evas_common_draw_context_apply_clear_cutouts(rects);
} }
@ -779,12 +781,12 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int
#endif #endif
} }
/* FIXME: Where is it freed at? */ /* FIXME: Where is it freed at? */
/* Only used if cache is on */ /* Only used if cache is on */
#if defined(METRIC_CACHE) || defined(WORD_CACHE) #if defined(METRIC_CACHE) || defined(WORD_CACHE)
struct prword * struct prword *
evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Evas_BiDi_Props *intl_props, int len, RGBA_Font *fn, RGBA_Font_Int *fi,int use_kerning){ evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Evas_BiDi_Props *intl_props, int len, RGBA_Font *fn, RGBA_Font_Int *fi,int use_kerning)
{
int pen_x, pen_y; int pen_x, pen_y;
struct cinfo *metrics; struct cinfo *metrics;
const Eina_Unicode *text = in_text; const Eina_Unicode *text = in_text;
@ -805,16 +807,16 @@ evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Eva
if (gl) return NULL; if (gl) return NULL;
# endif # endif
LKL(lock_words); LKL(lock_words);
EINA_INLIST_FOREACH(words,w){ EINA_INLIST_FOREACH(words,w)
{
if (w->len == len && w->font == fn && fi->size == w->size && if (w->len == len && w->font == fn && fi->size == w->size &&
(w->str == in_text || memcmp(w->str, in_text, len * sizeof(Eina_Unicode)) == 0)){ (w->str == in_text || memcmp(w->str, in_text, len * sizeof(Eina_Unicode)) == 0)){
words = eina_inlist_promote(words, EINA_INLIST_GET(w)); words = eina_inlist_promote(words, EINA_INLIST_GET(w));
LKU(lock_words); LKU(lock_words);
return w; return w;
} }
} }
LKU(lock_words); LKU(lock_words);
gl = dc->font_ext.func.gl_new ? 1: 0; gl = dc->font_ext.func.gl_new ? 1: 0;
@ -822,8 +824,10 @@ evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Eva
pen_x = pen_y = 0; pen_x = pen_y = 0;
above = 0; below = 0; baseline = 0; height = 0; descent = 0; above = 0; below = 0; baseline = 0; height = 0; descent = 0;
metrics = malloc(sizeof(struct cinfo) * len); metrics = malloc(sizeof(struct cinfo) * len);
/* First pass: Work out how big */ /* First pass: Work out how big */
for (char_index = 0, c = 0, chr = 0 ; *text ; text++, char_index ++){ for (char_index = 0, c = 0, chr = 0 ; *text ; text++, char_index ++)
{
struct cinfo *ci = metrics + char_index; struct cinfo *ci = metrics + char_index;
ci->gl = *text; ci->gl = *text;
ci->index = evas_common_font_glyph_search(fn, &fi, ci->gl); ci->index = evas_common_font_glyph_search(fn, &fi, ci->gl);
@ -843,75 +847,79 @@ evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Eva
} }
if ((use_kerning) && (prev_index) && (ci->index) && if ((use_kerning) && (prev_index) && (ci->index) &&
(pface == fi->src->ft.face)) (pface == fi->src->ft.face))
{ {
int kern = 0; int kern = 0;
# ifdef BIDI_SUPPORT # ifdef BIDI_SUPPORT
/* if it's rtl, the kerning matching should be reversed, i.e prev /* if it's rtl, the kerning matching should be reversed, i.e prev
* index is now the index and the other way around. * index is now the index and the other way around.
* There is a slight exception when there are compositing chars * There is a slight exception when there are compositing chars
* involved.*/ * involved.*/
if (intl_props && intl_props->props && if (intl_props && intl_props->props &&
evas_bidi_is_rtl_char(intl_props, char_index) && evas_bidi_is_rtl_char(intl_props, char_index) &&
ci->fg->glyph->advance.x >> 16 > 0) ci->fg->glyph->advance.x >> 16 > 0)
{ {
if (evas_common_font_query_kerning(fi, ci->index, prev_index, &kern)) if (evas_common_font_query_kerning(fi, ci->index, prev_index, &kern))
pen_x += kern; pen_x += kern;
} }
else else
{ {
if (evas_common_font_query_kerning(fi, prev_index, ci->index, &kern)) if (evas_common_font_query_kerning(fi, prev_index, ci->index, &kern))
pen_x += kern; pen_x += kern;
} }
# else # else
if (evas_common_font_query_kerning(fi, prev_index, ci->index, &kern)) if (evas_common_font_query_kerning(fi, prev_index, ci->index, &kern))
pen_x += kern; pen_x += kern;
# endif # endif
} }
pface = fi->src->ft.face;
LKU(fi->ft_mutex); pface = fi->src->ft.face;
if (gl){
ci->fg->ext_dat =dc->font_ext.func.gl_new(dc->font_ext.data,ci->fg);
ci->fg->ext_dat_free = dc->font_ext.func.gl_free;
}
ci->bm.data = ci->fg->glyph_out->bitmap.buffer;
ci->bm.w = MAX(ci->fg->glyph_out->bitmap.pitch,
ci->fg->glyph_out->bitmap.width);
ci->bm.rows = ci->fg->glyph_out->bitmap.rows;
ci->bm.h = ci->fg->glyph_out->top;
above = ci->bm.rows - (ci->bm.rows - ci->bm.h);
below = ci->bm.rows - ci->bm.h;
if (below > descent) descent = below;
if (above > baseline) baseline = above;
ci->pos.x = pen_x + ci->fg->glyph_out->left;
ci->pos.y = pen_y + ci->fg->glyph_out->top;
pen_x += ci->fg->glyph->advance.x >> 16;
prev_index = ci->index;
}
/* First loop done */
width = pen_x;
width = (width & 0x7) ? width + (8 - (width & 0x7)) : width;
height = baseline + descent;
if (!gl){
im = calloc(height, width);
for (i = 0 ; i < char_index ; i ++){
struct cinfo *ci = metrics + i;
for (j = 0 ; j < ci->bm.rows ; j ++){
memcpy(im + ci->pos.x + (j + baseline - ci->bm.h) * width, ci->bm.data + j * ci->bm.w, ci->bm.w);
}
LKU(fi->ft_mutex);
if (gl)
{
ci->fg->ext_dat =dc->font_ext.func.gl_new(dc->font_ext.data,ci->fg);
ci->fg->ext_dat_free = dc->font_ext.func.gl_free;
}
ci->bm.data = ci->fg->glyph_out->bitmap.buffer;
ci->bm.w = MAX(ci->fg->glyph_out->bitmap.pitch,
ci->fg->glyph_out->bitmap.width);
ci->bm.rows = ci->fg->glyph_out->bitmap.rows;
ci->bm.h = ci->fg->glyph_out->top;
above = ci->bm.rows - (ci->bm.rows - ci->bm.h);
below = ci->bm.rows - ci->bm.h;
if (below > descent) descent = below;
if (above > baseline) baseline = above;
ci->pos.x = pen_x + ci->fg->glyph_out->left;
ci->pos.y = pen_y + ci->fg->glyph_out->top;
pen_x += ci->fg->glyph->advance.x >> 16;
prev_index = ci->index;
} }
} else {
im = NULL; /* First loop done */
} width = pen_x;
width = (width & 0x7) ? width + (8 - (width & 0x7)) : width;
height = baseline + descent;
if (!gl)
{
im = calloc(height, width);
for (i = 0 ; i < char_index ; i ++)
{
struct cinfo *ci = metrics + i;
for (j = 0 ; j < ci->bm.rows ; j ++)
memcpy(im + ci->pos.x + (j + baseline - ci->bm.h) * width, ci->bm.data + j * ci->bm.w, ci->bm.w);
}
}
else
{
im = NULL;
}
/* Save it */ /* Save it */
struct prword *save; struct prword *save;
save = malloc(sizeof(struct prword)); save = malloc(sizeof(struct prword));
save->cinfo = metrics; save->cinfo = metrics;
save->str = eina_ustringshare_add(in_text); save->str = eina_ustringshare_add(in_text);
@ -927,19 +935,21 @@ evas_font_word_prerender(RGBA_Draw_Context *dc, const Eina_Unicode *in_text, Eva
words = eina_inlist_prepend(words, EINA_INLIST_GET(save)); words = eina_inlist_prepend(words, EINA_INLIST_GET(save));
/* Clean up if too long */ /* Clean up if too long */
if (eina_inlist_count(words) > max_cached_words){ if (eina_inlist_count(words) > max_cached_words)
{
struct prword *last = (struct prword *)(words->last); struct prword *last = (struct prword *)(words->last);
if (last->im) free(last->im);
if (last->cinfo) free(last->cinfo); if (last)
eina_ustringshare_del(last->str); {
words = eina_inlist_remove(words,EINA_INLIST_GET(last)); if (last->im) free(last->im);
free(last); if (last->cinfo) free(last->cinfo);
} eina_ustringshare_del(last->str);
words = eina_inlist_remove(words, EINA_INLIST_GET(last));
free(last);
}
}
LKU(lock_words); LKU(lock_words);
return save; return save;
} }
#endif #endif