Evas font-engine: Cache pen position instead of advance.

We only really use adavnce for calculating the pen position, so it makes more
sense to just cache the pen_position instead and calculate advance from
that if ever needed.
This means size/advance calculations are now O(1) because we don't need to
walk the strings anymore.

SVN revision: 58756
This commit is contained in:
Tom Hacohen 2011-04-20 14:20:51 +00:00
parent 2f86580227
commit 543c0cafc0
5 changed files with 98 additions and 60 deletions

View File

@ -13,6 +13,9 @@
*/
# define EVAS_FONT_WALK_TEXT_INIT() \
int _pen_x = 0, _pen_y = 0; \
Evas_Coord _start_pen = (text_props->info && \
(text_props->start > 0)) ? \
text_props->info->glyph[text_props -> start - 1].pen_after : 0 ; \
size_t char_index; \
(void) _pen_y; /* Sometimes it won't be used */
@ -149,13 +152,14 @@
#define EVAS_FONT_WALK_IS_VISIBLE (_glyph_itr->index != 0)
#define EVAS_FONT_WALK_X_BEAR (_glyph_itr->x_bear)
#define EVAS_FONT_WALK_Y_BEAR (fg->glyph_out->top)
#define _EVAS_FONT_WALK_X_ADV (_glyph_itr->advance)
#define EVAS_FONT_WALK_X_ADV ((_glyph_itr > text_props->info->glyph) ? \
_glyph_itr->pen_after - (_glyph_itr - 1)->pen_after : \
_glyph_itr->pen_after)
#define EVAS_FONT_WALK_WIDTH (_glyph_itr->width)
#define EVAS_FONT_WALK_INDEX (_glyph_itr->index)
#define EVAS_FONT_WALK_X_ADV \
(EVAS_FONT_ROUND_26_6_TO_INT(_EVAS_FONT_WALK_X_ADV))
#define EVAS_FONT_WALK_PEN_X (EVAS_FONT_ROUND_26_6_TO_INT(_pen_x))
#define EVAS_FONT_WALK_PEN_X (_pen_x)
#define EVAS_FONT_WALK_PEN_X_AFTER (_glyph_itr->pen_after - _start_pen)
#define EVAS_FONT_WALK_PEN_Y (EVAS_FONT_ROUND_26_6_TO_INT(_pen_y))
#define EVAS_FONT_WALK_Y_ADV (0)
#define EVAS_FONT_WALK_IS_LAST \
@ -186,7 +190,7 @@
#define EVAS_FONT_WALK_TEXT_END() \
if (EVAS_FONT_WALK_IS_VISIBLE) \
{ \
_pen_x += _EVAS_FONT_WALK_X_ADV; \
_pen_x = _glyph_itr->pen_after - _start_pen; \
} \
} \
} \

View File

@ -196,6 +196,7 @@ evas_common_font_ot_populate_text_props(void *_fn, const Eina_Unicode *text,
unsigned int i;
Evas_Font_Glyph_Info *gl_itr;
Evas_Font_OT_Info *ot_itr;
Evas_Coord pen_x = 0;
fi = fn->fonts->data;
/* Load the font needed for this script */
@ -252,11 +253,15 @@ evas_common_font_ot_populate_text_props(void *_fn, const Eina_Unicode *text,
ot_itr = props->info->ot;
for (i = 0 ; i < props->len ; i++)
{
Evas_Coord adv;
ot_itr->source_cluster = infos->cluster;
ot_itr->x_offset = positions->x_offset;
ot_itr->y_offset = positions->y_offset;
gl_itr->index = infos->codepoint;
gl_itr->advance = positions->x_advance;
adv = positions->x_advance;
pen_x += adv;
gl_itr->pen_after = EVAS_FONT_ROUND_26_6_TO_INT(pen_x);
ot_itr++;
gl_itr++;

View File

@ -79,10 +79,12 @@ evas_common_font_query_right_inset(RGBA_Font *fn __UNUSED__, const Evas_Text_Pro
if (gli->width == 0)
return 0;
return EVAS_FONT_ROUND_26_6_TO_INT(gli->advance) -
return ((gli > text_props->info->glyph) ?
gli->pen_after - (gli - 1)->pen_after : gli->pen_after) -
(gli->width + gli->x_bear
#ifdef OT_SUPPORT
+ text_props->info->ot[text_props->start + text_props->len - 1].x_offset
+ EVAS_FONT_ROUND_26_6_TO_INT(EVAS_FONT_OT_X_OFF_GET(
text_props->info->ot[text_props->start + text_props->len - 1]))
#endif
);
}
@ -97,32 +99,29 @@ evas_common_font_query_right_inset(RGBA_Font *fn __UNUSED__, const Evas_Text_Pro
EAPI void
evas_common_font_query_size(RGBA_Font *fn, const Evas_Text_Props *text_props, int *w, int *h)
{
int keep_width = 0;
int prev_pen_x = 0;
EVAS_FONT_WALK_TEXT_INIT();
Evas_Coord ret_w = 0;
EVAS_FONT_WALK_TEXT_VISUAL_START()
if (text_props->len > 0)
{
EVAS_FONT_WALK_TEXT_WORK();
if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
/* Keep the width because we'll need it for the last char */
keep_width = EVAS_FONT_WALK_WIDTH +
EVAS_FONT_WALK_X_OFF +
EVAS_FONT_WALK_X_BEAR;
/* Keep the previous EVAS_FONT_WALK_PEN_X, before it's advanced in TEXT_END */
prev_pen_x = EVAS_FONT_WALK_PEN_X;
}
EVAS_FONT_WALK_TEXT_END();
const Evas_Font_Glyph_Info *glyph = text_props->info->glyph +
text_props->start;
const Evas_Font_Glyph_Info *last_glyph = glyph;
/* If the last char is a whitespace, we use the advance as the size */
if (keep_width > 0)
{
if (w) *w = prev_pen_x + keep_width;
}
else
{
if (w) *w = EVAS_FONT_WALK_PEN_X;
if (text_props->len > 1)
{
last_glyph += text_props->len - 1;
ret_w = last_glyph[-1].pen_after;
if (text_props->start > 0)
ret_w -= glyph[-1].pen_after;
}
#ifdef OT_SUPPORT
ret_w += EVAS_FONT_ROUND_26_6_TO_INT(EVAS_FONT_OT_X_OFF_GET(
text_props->info->ot[text_props->start + text_props->len - 1]));
#endif
ret_w += last_glyph->width + last_glyph->x_bear;
}
if (w) *w = ret_w;
if (h) *h = evas_common_font_max_ascent_get(fn) + evas_common_font_max_descent_get(fn);
}
@ -135,17 +134,18 @@ evas_common_font_query_size(RGBA_Font *fn, const Evas_Text_Props *text_props, in
EAPI void
evas_common_font_query_advance(RGBA_Font *fn, const Evas_Text_Props *text_props, int *h_adv, int *v_adv)
{
EVAS_FONT_WALK_TEXT_INIT();
EVAS_FONT_WALK_TEXT_LOGICAL_START()
Evas_Coord ret_adv = 0;
if (text_props->len > 0)
{
EVAS_FONT_WALK_TEXT_WORK();
if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
const Evas_Font_Glyph_Info *glyph = text_props->info->glyph +
text_props->start;
ret_adv = glyph[text_props->len - 1].pen_after;
if (text_props->start > 0)
ret_adv -= glyph[-1].pen_after;
}
EVAS_FONT_WALK_TEXT_END();
if (h_adv) *h_adv = ret_adv;
if (v_adv) *v_adv = evas_common_font_get_line_advance(fn);
if (h_adv) *h_adv = EVAS_FONT_WALK_PEN_X;
}
/* x y w h for char at char pos for null it returns the position right after
@ -430,8 +430,8 @@ evas_common_font_query_char_at_coords(RGBA_Font *fn, const Evas_Text_Props *text
/* we need to see if the char at the visual position is the char,
* we check that by checking if it's before the current pen
* position and the next */
if ((x >= EVAS_FONT_WALK_PEN_X) && (x <= (EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_ADV)) &&
(y >= -asc) && (y <= desc))
if ((x >= EVAS_FONT_WALK_PEN_X) &&
(x <= (EVAS_FONT_WALK_PEN_X_AFTER)) && (y >= -asc) && (y <= desc))
{
#ifdef OT_SUPPORT
items = evas_common_font_ot_cluster_size_get(text_props,
@ -496,8 +496,8 @@ evas_common_font_query_last_up_to_pos(RGBA_Font *fn, const Evas_Text_Props *text
EVAS_FONT_WALK_TEXT_WORK();
if (!EVAS_FONT_WALK_IS_VISIBLE) continue;
if ((x >= EVAS_FONT_WALK_PEN_X) && (x <= (EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_ADV)) &&
(y >= -asc) && (y <= desc))
if ((x >= EVAS_FONT_WALK_PEN_X) &&
(x <= (EVAS_FONT_WALK_PEN_X_AFTER)) && (y >= -asc) && (y <= desc))
{
ret = EVAS_FONT_WALK_POS;
goto end;

View File

@ -5,9 +5,6 @@
#include "language/evas_language_utils.h"
#include "evas_font_ot.h"
/* Used for showing "malformed" or missing chars */
#define REPLACEMENT_CHAR 0xFFFD
void
evas_common_text_props_bidi_set(Evas_Text_Props *props,
Evas_BiDi_Paragraph_Props *bidi_par_props, size_t start)
@ -207,6 +204,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
size_t char_index;
Evas_Font_Glyph_Info *gl_itr;
const Eina_Unicode *base_char;
Evas_Coord pen_x = 0, adjust_x = 0;
(void) par_props;
(void) par_pos;
@ -248,14 +246,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
continue;
}
LKU(fi->ft_mutex);
if (is_replacement)
{
/* Update the advance accordingly */
gl_itr->advance =
fg->glyph->advance.x >> 10;
/* FIXME: reload fi, a bit slow, but I have no choice. */
evas_common_font_glyph_search(fn, &fi, *base_char);
}
gl_itr->x_bear = fg->glyph_out->left;
gl_itr->width = fg->glyph_out->bitmap.width;
/* text_props->info->glyph[char_index].advance =
@ -263,7 +254,32 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
* already done by the ot function */
if (EVAS_FONT_CHARACTER_IS_INVISIBLE(
text[text_props->info->ot[char_index].source_cluster]))
gl_itr->index = 0;
{
gl_itr->index = 0;
/* Reduce the current advance */
if (gl_itr > text_props->info->glyph)
{
adjust_x -= gl_itr->pen_after - (gl_itr - 1)->pen_after;
}
else
{
adjust_x -= gl_itr->pen_after;
}
}
else
{
if (is_replacement)
{
/* Update the advance accordingly */
adjust_x += (pen_x + (fg->glyph->advance.x >> 16)) -
gl_itr->pen_after;
/* FIXME: reload fi, a bit slow, but I have no choice. */
evas_common_font_glyph_search(fn, &fi, *base_char);
}
pen_x = gl_itr->pen_after;
}
gl_itr->pen_after += adjust_x;
gl_itr++;
}
@ -273,6 +289,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
Eina_Bool use_kerning;
FT_UInt prev_index;
FT_Face pface = NULL;
Evas_Coord pen_x = 0;
int adv_d, i;
#if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT)
text = text_props->info->shaped_text = eina_unicode_strndup(text, len);
@ -308,6 +325,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
FT_UInt index;
RGBA_Font_Glyph *fg;
int _gl, kern;
Evas_Coord adv;
_gl = *text;
if (_gl == 0) break;
@ -351,7 +369,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
{
if (evas_common_font_query_kerning(fi, index, prev_index, &kern))
{
(gl_itr - 1)->advance += kern;
(gl_itr - 1)->pen_after += kern;
}
}
else
@ -359,7 +377,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
{
if (evas_common_font_query_kerning(fi, prev_index, index, &kern))
{
(gl_itr - 1)->advance += kern;
(gl_itr - 1)->pen_after += kern;
}
}
}
@ -367,14 +385,22 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
pface = fi->src->ft.face;
LKU(fi->ft_mutex);
if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl))
gl_itr->index = 0;
gl_itr->index = index;
gl_itr->x_bear = fg->glyph_out->left;
gl_itr->advance = fg->glyph->advance.x >> 10;
adv = fg->glyph->advance.x >> 10;
gl_itr->width = fg->glyph_out->bitmap.width;
if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl))
{
gl_itr->index = 0;
}
else
{
pen_x += adv;
}
gl_itr->pen_after = EVAS_FONT_ROUND_26_6_TO_INT(pen_x);
prev_index = index;
}
text_props->len = len;

View File

@ -9,6 +9,9 @@ typedef struct _Evas_Font_Glyph_Info Evas_Font_Glyph_Info;
# include "language/evas_bidi_utils.h"
# include "language/evas_language_utils.h"
/* Used for showing "malformed" or missing chars */
#define REPLACEMENT_CHAR 0xFFFD
struct _Evas_Text_Props
{
/* Start and len represent the start offset and the length in the
@ -44,7 +47,7 @@ struct _Evas_Font_Glyph_Info
Evas_Coord y_bear;
#endif
Evas_Coord width;
Evas_Coord advance;
Evas_Coord pen_after;
};