Evas font-engine: Cache pen position instead of advance.
authortasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 20 Apr 2011 14:20:51 +0000 (14:20 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 20 Apr 2011 14:20:51 +0000 (14:20 +0000)
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.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@58756 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/engines/common/evas_font_default_walk.x
src/lib/engines/common/evas_font_ot.c
src/lib/engines/common/evas_font_query.c
src/lib/engines/common/evas_text_utils.c
src/lib/engines/common/evas_text_utils.h

index 704db21..a1f60f2 100644 (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 */
 
 #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 \
 #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; \
                } \
           } \
      } \
index 6a6a4e4..ba7da6b 100644 (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++;
index 8fc1cd9..4a32062 100644 (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;
index 8cd5ccc..8c2482f 100644 (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;
index 76efa14..21f8f38 100644 (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;
 };