evas: Use refcounted glyph arrays

This is in preparation for threaded render landing: the render thread will
hold a reference to a text object's glyphs while it hasn't been rendered
yet (and will drop that reference after drawing). This changes the internal
API a little bit (evas_common_font_rgba_draw() now takes an Evas_Glyph_Array
instead of an Evas_Text_Props).


SVN revision: 81183
This commit is contained in:
Leandro Pereira 2012-12-17 21:27:07 +00:00
parent f96a5aac5c
commit 274c9159c9
6 changed files with 255 additions and 69 deletions

View File

@ -17,11 +17,11 @@ EAPI int evas_common_font_max_descent_get (RGBA_Font *fn);
EAPI int evas_common_font_get_line_advance (RGBA_Font *fn);
/* draw */
typedef void (*Evas_Common_Font_Draw_Cb)(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h);
typedef void (*Evas_Common_Font_Draw_Cb)(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *text_props, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h);
EAPI void evas_common_font_draw_cb (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *intl_props, Evas_Common_Font_Draw_Cb cb);
EAPI void evas_common_font_draw (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *intl_props);
EAPI void 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);
EAPI void evas_common_font_draw (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs);
EAPI void evas_common_font_rgba_draw (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h);
EAPI int evas_common_font_glyph_search (RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl);
EAPI RGBA_Font_Glyph *evas_common_font_int_cache_glyph_get (RGBA_Font_Int *fi, FT_UInt index);
EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg);

View File

@ -29,32 +29,29 @@ evas_common_font_draw_init(void)
*/
static void
evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y,
const Evas_Text_Props *text_props, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w,
Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w,
int ext_h, int im_w, int im_h EINA_UNUSED)
{
DATA32 *im;
Evas_Glyph *glyphs;
unsigned int length;
unsigned int it;
Evas_Glyph *glyph;
if (!glyphs) return;
if (!glyphs->array) return;
im = dst->image.data;
if (!text_props->glyphs) return ;
glyphs = text_props->glyphs;
length = text_props->glyphs_length;
for (it = 0; it < length; ++it, ++glyphs)
EINA_INARRAY_FOREACH(glyphs->array, glyph)
{
RGBA_Font_Glyph *fg;
int chr_x, chr_y;
fg = glyphs->fg;
fg = glyph->fg;
/* FIXME: Why was that moved out of prepare ? This increase cache miss. */
glyphs->coord.w = fg->glyph_out->bitmap.width;
glyphs->coord.h = fg->glyph_out->bitmap.rows;
glyphs->j = fg->glyph_out->bitmap.pitch;
glyphs->data = fg->glyph_out->bitmap.buffer;
glyph->coord.w = fg->glyph_out->bitmap.width;
glyph->coord.h = fg->glyph_out->bitmap.rows;
glyph->j = fg->glyph_out->bitmap.pitch;
glyph->data = fg->glyph_out->bitmap.buffer;
if (dc->font_ext.func.gl_new)
{
@ -63,19 +60,19 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, in
fg->ext_dat_free = dc->font_ext.func.gl_free;
}
chr_x = x + glyphs->coord.x/* EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR */;
chr_y = y + glyphs->coord.y/* EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR */;
chr_x = x + glyph->coord.x;
chr_y = y + glyph->coord.y;
if (chr_x < (ext_x + ext_w))
{
DATA8 *data;
int i, j, w, h;
data = glyphs->data;
j = glyphs->j;
w = glyphs->coord.w;
data = glyph->data;
j = glyph->j;
w = glyph->coord.w;
if (j < w) j = w;
h = glyphs->coord.h;
h = glyph->coord.h;
#ifdef HAVE_PIXMAN
# ifdef PIXMAN_FONT
@ -225,27 +222,197 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, in
}
}
EAPI void
evas_common_font_rgba_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h EINA_UNUSED)
{
DATA32 *im;
Evas_Glyph *glyph;
if (!glyphs) return;
if (!glyphs->array) return;
im = dst->image.data;
EINA_INARRAY_FOREACH(glyphs->array, glyph)
{
RGBA_Font_Glyph *fg;
int chr_x, chr_y;
fg = glyph->fg;
/* FIXME: Why was that moved out of prepare ? This increase cache miss. */
glyph->coord.w = fg->glyph_out->bitmap.width;
glyph->coord.h = fg->glyph_out->bitmap.rows;
glyph->j = fg->glyph_out->bitmap.pitch;
glyph->data = fg->glyph_out->bitmap.buffer;
if (dc->font_ext.func.gl_new)
{
/* extension calls */
fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg);
fg->ext_dat_free = dc->font_ext.func.gl_free;
}
chr_x = x + glyph->coord.x;
chr_y = y + glyph->coord.y;
if (chr_x < (ext_x + ext_w))
{
DATA8 *data;
int i, j, w, h;
data = glyph->data;
j = glyph->j;
w = glyph->coord.w;
if (j < w) j = w;
h = glyph->coord.h;
if ((j > 0) && (chr_x + w > ext_x))
{
if ((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, fg, chr_x,
y - (chr_y - y));
}
else
{
if ((fg->glyph_out->bitmap.num_grays == 256) &&
(fg->glyph_out->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY))
{
for (i = 0; i < h; i++)
{
int dx, dy;
int in_x, in_w;
in_x = 0;
in_w = 0;
dx = chr_x;
dy = y - (chr_y - i - y);
if ((dx < (ext_x + ext_w)) &&
(dy >= (ext_y)) &&
(dy < (ext_y + ext_h)))
{
if (dx + w > (ext_x + ext_w))
in_w += (dx + w) - (ext_x + ext_w);
if (dx < ext_x)
{
in_w += ext_x - dx;
in_x = ext_x - dx;
dx = ext_x;
}
if (in_w < w)
{
func(NULL, data + (i * j) + in_x, dc->col.col,
im + (dy * im_w) + dx, w - in_w);
}
}
}
}
else
{
DATA8 *tmpbuf = NULL, *dp, *tp, bits;
int bi, bj;
const DATA8 bitrepl[2] = {0x0, 0xff};
tmpbuf = alloca(w);
for (i = 0; i < h; i++)
{
int dx, dy;
int in_x, in_w, end;
in_x = 0;
in_w = 0;
dx = chr_x;
dy = y - (chr_y - i - y);
tp = tmpbuf;
dp = data + (i * fg->glyph_out->bitmap.pitch);
for (bi = 0; bi < w; bi += 8)
{
bits = *dp;
if ((w - bi) < 8) end = w - bi;
else end = 8;
for (bj = 0; bj < end; bj++)
{
*tp = bitrepl[(bits >> (7 - bj)) & 0x1];
tp++;
}
dp++;
}
if ((dx < (ext_x + ext_w)) &&
(dy >= (ext_y)) &&
(dy < (ext_y + ext_h)))
{
if (dx + w > (ext_x + ext_w))
in_w += (dx + w) - (ext_x + ext_w);
if (dx < ext_x)
{
in_w += ext_x - dx;
in_x = ext_x - dx;
dx = ext_x;
}
if (in_w < w)
{
func(NULL, tmpbuf + in_x, dc->col.col,
im + (dy * im_w) + dx, w - in_w);
}
}
}
}
}
}
} else break;
}
}
void
evas_common_font_glyphs_ref(Evas_Glyph_Array *array)
{
if (!array) return;
eina_lock_take(&array->lock);
array->refcount++;
eina_lock_release(&array->lock);
}
void
evas_common_font_glyphs_unref(Evas_Glyph_Array *array)
{
if (!array) return;
eina_lock_take(&array->lock);
if (--array->refcount)
{
eina_lock_release(&array->lock);
return;
}
eina_lock_release(&array->lock);
eina_lock_free(&array->lock);
eina_inarray_free(array->array);
free(array);
}
EAPI void
evas_common_font_draw_prepare(Evas_Text_Props *text_props)
{
RGBA_Font_Int *fi;
RGBA_Font_Glyph *fg;
Evas_Glyph *glyphs;
int glyphs_length;
int glyphs_max;
Eina_Inarray *glyphs;
EVAS_FONT_WALK_TEXT_INIT();
fi = text_props->font_instance;
if (!fi) return;
if (!text_props->changed && text_props->generation == fi->generation && text_props->glyphs)
return ;
glyphs = text_props->glyphs;
glyphs_length = 0;
glyphs_max = text_props->glyphs_length;
text_props->glyphs_length = 0;
return;
glyphs = eina_inarray_new(sizeof(Evas_Glyph), 32);
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
@ -259,7 +426,7 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props)
EVAS_FONT_WALK_TEXT_START()
{
Evas_Glyph *glyph;
Evas_Glyph glyph;
FT_UInt idx;
if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
@ -269,37 +436,43 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props)
if (!fg) continue;
if (!fg->glyph_out) evas_common_font_int_cache_glyph_render(fg);
if (glyphs_length + 1 >= glyphs_max)
{
Evas_Glyph *tmp;
glyph.fg = fg;
glyph.idx = idx;
glyph.coord.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
glyph.coord.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
glyphs_max += 8;
tmp = realloc(glyphs, glyphs_max * sizeof (Evas_Glyph));
if (!tmp) return ;
glyphs = tmp;
text_props->glyphs = glyphs;
}
glyph = glyphs + glyphs_length++;
glyph->fg = fg;
glyph->idx = idx;
glyph->coord.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR;
glyph->coord.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR;
if (eina_inarray_push(glyphs, &glyph) < 0) goto error;
}
EVAS_FONT_WALK_TEXT_END();
text_props->glyphs_length = glyphs_length;
text_props->glyphs = glyphs;
/*
* Clearing the reference to the glyph array is fine, since this
* reference is only used to use this from another thread, which is now
* holding the reference.
*/
evas_common_font_glyphs_unref(text_props->glyphs);
text_props->glyphs = malloc(sizeof(*text_props->glyphs));
if (!text_props->glyphs) goto error;
text_props->glyphs->refcount = 1;
text_props->glyphs->array = glyphs;
if (!eina_lock_new(&text_props->glyphs->lock))
CRIT("Could not create glyph array lock");
/* check if there's a request queue in fi, if so ask cserve2 to render
* those glyphs
*/
text_props->generation = fi->generation;
return;
error:
eina_inarray_free(glyphs);
}
EAPI void
evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *text_props, Evas_Common_Font_Draw_Cb cb)
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)
{
static Cutout_Rects *rects = NULL;
int ext_x, ext_y, ext_w, ext_h;
@ -342,7 +515,7 @@ evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, c
if (!dc->cutout.rects)
{
cb(dst, dc, x, y, text_props,
cb(dst, dc, x, y, glyphs,
func, ext_x, ext_y, ext_w, ext_h,
im_w, im_h);
}
@ -358,7 +531,7 @@ evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, c
{
r = rects->rects + i;
evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h);
cb(dst, dc, x, y, text_props,
cb(dst, dc, x, y, glyphs,
func, r->x, r->y, r->w, r->h,
im_w, im_h);
}
@ -368,9 +541,9 @@ evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, c
}
EAPI void
evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *text_props)
evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs)
{
evas_common_font_draw_cb(dst, dc, x, y, text_props,
evas_common_font_draw_cb(dst, dc, x, y, glyphs,
evas_common_font_draw_internal);
}
@ -392,7 +565,7 @@ evas_common_font_draw_do(const Cutout_Rects *reuse, const Eina_Rectangle *clip,
evas_common_draw_context_clip_clip(dc,
clip->x, clip->y,
clip->w, clip->h);
evas_common_font_draw_internal(dst, dc, x, y, text_props,
evas_common_font_draw_internal(dst, dc, x, y, text_props->glyphs,
func,
dc->clip.x, dc->clip.y,
dc->clip.w, dc->clip.h,
@ -407,7 +580,7 @@ evas_common_font_draw_do(const Cutout_Rects *reuse, const Eina_Rectangle *clip,
EINA_RECTANGLE_SET(&area, r->x, r->y, r->w - 1, r->h - 1);
if (!eina_rectangle_intersection(&area, clip)) continue ;
evas_common_draw_context_set_clip(dc, area.x, area.y, area.w, area.h);
evas_common_font_draw_internal(dst, dc, x, y, text_props,
evas_common_font_draw_internal(dst, dc, x, y, text_props->glyphs,
func, area.x, area.y, area.w, area.h,
im_w, im_h);
}

View File

@ -37,7 +37,6 @@ evas_common_text_props_content_copy_and_ref(Evas_Text_Props *dst,
{
memcpy(dst, src, sizeof(Evas_Text_Props));
dst->glyphs = NULL;
dst->glyphs_length = 0;
evas_common_text_props_content_ref(dst);
}
@ -68,9 +67,10 @@ evas_common_text_props_content_nofree_unref(Evas_Text_Props *props)
props->font_instance = NULL;
}
free(props->glyphs);
evas_common_font_glyphs_unref(props->glyphs);
/* After unreferencing the glyph array, a thread will still hold
* a reference, so this can be safely set to NULL. */
props->glyphs = NULL;
props->glyphs_length = 0;
if (props->info->glyph)
free(props->info->glyph);
@ -90,9 +90,10 @@ evas_common_text_props_content_unref(Evas_Text_Props *props)
if (!props->info)
return;
free(props->glyphs);
evas_common_font_glyphs_unref(props->glyphs);
/* After unreferencing the glyph array, a thread will still hold
* a reference, so this can be safely set to NULL. */
props->glyphs = NULL;
props->glyphs_length = 0;
if (--(props->info->refcount) == 0)
{

View File

@ -19,6 +19,14 @@ typedef enum
#define REPLACEMENT_CHAR 0xFFFD
typedef struct _Evas_Glyph Evas_Glyph;
typedef struct _Evas_Glyph_Array Evas_Glyph_Array;
struct _Evas_Glyph_Array
{
Eina_Inarray *array;
unsigned int refcount;
Eina_Lock lock;
};
struct _Evas_Text_Props
{
@ -33,8 +41,7 @@ struct _Evas_Text_Props
Evas_Text_Props_Info *info;
void *font_instance;
Evas_Glyph *glyphs;
int glyphs_length;
Evas_Glyph_Array *glyphs;
int generation;
Eina_Bool changed : 1;
@ -61,6 +68,11 @@ struct _Evas_Font_Glyph_Info
Evas_Coord pen_after;
};
void
evas_common_font_glyphs_ref(Evas_Glyph_Array *array);
void
evas_common_font_glyphs_unref(Evas_Glyph_Array *array);
void
evas_common_text_props_bidi_set(Evas_Text_Props *props,
Evas_BiDi_Paragraph_Props *bidi_par_props, size_t start);

View File

@ -2625,7 +2625,7 @@ eng_font_draw(void *data, void *context, void *surface, Evas_Font_Set *font EINA
evas_gl_font_texture_free,
evas_gl_font_texture_draw);
evas_common_font_draw_prepare(intl_props);
evas_common_font_draw(im, context, x, y, intl_props);
evas_common_font_draw(im, context, x, y, intl_props->glyphs);
evas_common_draw_context_font_ext_set(context,
NULL,
NULL,

View File

@ -1260,8 +1260,8 @@ eng_font_draw(void *data EINA_UNUSED, void *context, void *surface, Evas_Font_Se
#endif
{
evas_common_font_draw_prepare(text_props);
evas_common_font_draw(surface, context, x, y, text_props);
evas_common_cpu_end_opt();
evas_common_font_draw(surface, context, x, y, text_props->glyphs);
evas_common_cpu_end_opt();
}
}