Evas font-engine: Fixed font fallback in the same script run.
authortasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 29 May 2011 09:20:18 +0000 (09:20 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 29 May 2011 09:20:18 +0000 (09:20 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@59777 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/canvas/evas_object_text.c
src/lib/canvas/evas_object_textblock.c
src/lib/engines/common/evas_font.h
src/lib/engines/common/evas_font_ot.c
src/lib/engines/common/evas_font_ot.h
src/lib/engines/common/evas_font_query.c
src/lib/engines/common/evas_text_utils.c
src/lib/engines/common/evas_text_utils.h
src/lib/include/evas_private.h
src/modules/engines/software_generic/evas_engine.c

index ac2ef15..0e7208d 100644 (file)
@@ -459,23 +459,24 @@ evas_object_text_font_get(const Evas_Object *obj, const char **font, Evas_Font_S
  */
 static Evas_Object_Text_Item *
 _evas_object_text_item_new(Evas_Object *obj, Evas_Object_Text *o,
-      const Eina_Unicode *str,
+      void *fi, const Eina_Unicode *str, Evas_Script_Type script,
       size_t pos, size_t visual_pos, size_t len)
 {
    Evas_Object_Text_Item *it;
-   const Eina_Unicode *text = str + pos;
 
    it = calloc(1, sizeof(Evas_Object_Text_Item));
    it->text_pos = pos;
    it->visual_pos = visual_pos;
    evas_common_text_props_bidi_set(&it->text_props, o->bidi_par_props,
          it->text_pos);
-   evas_common_text_props_script_set(&it->text_props, text, len);
+   evas_common_text_props_script_set(&it->text_props, script);
+
    if (o->engine_data)
      {
         ENFN->font_text_props_info_create(ENDT,
-              o->engine_data, text, &it->text_props,
+              fi, str + pos, &it->text_props,
               o->bidi_par_props, it->text_pos, len);
+
         ENFN->font_string_size_get(ENDT,
               o->engine_data,
               &it->text_props,
@@ -554,7 +555,6 @@ _evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unico
 {
    EvasBiDiStrIndex *v_to_l = NULL;
    size_t pos, visual_pos;
-   int cutoff;
    int len = eina_unicode_strlen(text);
 #ifdef BIDI_SUPPORT
    int *segment_idxs = NULL;
@@ -567,32 +567,44 @@ _evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unico
 #endif
    visual_pos = pos = 0;
 
-   do
+   while (len > 0)
      {
-        cutoff = evas_common_language_script_end_of_run_get(
+        void *script_fi = NULL;
+        int script_len = len, tmp_cut;
+        Evas_Script_Type script;
+        tmp_cut = evas_common_language_script_end_of_run_get(
               text + pos,
               o->bidi_par_props,
-              pos, len - pos);
-        if (cutoff > 0)
+              pos, len);
+        if (tmp_cut > 0)
+           script_len = tmp_cut;
+
+        script = evas_common_language_script_type_get(text, script_len);
+
+        while (script_len > 0)
           {
+             void *cur_fi;
+             int run_len = script_len;
+             if (o->engine_data)
+               {
+                  run_len = ENFN->font_run_end_get(ENDT,
+                        o->engine_data, &script_fi, &cur_fi,
+                        script, text + pos, script_len);
+               }
 #ifdef BIDI_SUPPORT
              visual_pos = evas_bidi_position_logical_to_visual(
-                   v_to_l, len, pos);
+                   v_to_l, run_len, pos);
 #else
              visual_pos = pos;
 #endif
-             _evas_object_text_item_new(obj, o, text, pos, visual_pos, cutoff);
-             pos += cutoff;
+             _evas_object_text_item_new(obj, o, cur_fi, text, script,
+                   pos, visual_pos, run_len);
+
+             pos += run_len;
+             script_len -= run_len;
+             len -= run_len;
           }
      }
-   while (cutoff > 0);
-#ifdef BIDI_SUPPORT
-   visual_pos = evas_bidi_position_logical_to_visual(
-         v_to_l, len, pos);
-#else
-   visual_pos = pos;
-#endif
-   _evas_object_text_item_new(obj, o, text, pos, visual_pos, len - pos);
 
    _evas_object_text_item_order(obj, o);
 
index 8bdb0af..1a26a94 100644 (file)
@@ -2816,43 +2816,75 @@ skip:
    empty_item = 0;
 
 
+   /* If there's no parent text node, only create an empty item */
+   if (!n)
+     {
+        ti = _layout_text_item_new(c, fmt);
+        ti->parent.text_node = NULL;
+        ti->parent.text_pos = 0;
+        _layout_text_add_logical_item(c, ti, NULL);
+
+        goto end;
+     }
+
    while (str)
      {
-        int tmp_len;
+        void *script_fi = NULL;
+        int script_len, tmp_cut;
+        Evas_Script_Type script;
 
-        ti = _layout_text_item_new(c, fmt);
-        ti->parent.text_node = n;
-        ti->parent.text_pos = start + str - tbase;
-        tmp_len = off - (str - tbase);
-        if (ti->parent.text_node)
-          {
-             int tmp_cut;
-             tmp_cut = evas_common_language_script_end_of_run_get(str,
-                   c->par->bidi_props, ti->parent.text_pos, tmp_len);
-             if (tmp_cut > 0)
+        script_len = off - (str - tbase);
+
+        tmp_cut = evas_common_language_script_end_of_run_get(str,
+              c->par->bidi_props, start + str - tbase, script_len);
+        if (tmp_cut > 0)
+          {
+             script_len = tmp_cut;
+          }
+
+        script = evas_common_language_script_type_get(str, script_len);
+
+
+        while (script_len > 0)
+          {
+             void *cur_fi;
+             int run_len = script_len;
+             ti = _layout_text_item_new(c, fmt);
+             ti->parent.text_node = n;
+             ti->parent.text_pos = start + str - tbase;
+
+             if (ti->parent.format->font.font)
                {
-                  tmp_len = tmp_cut;
+                  run_len = c->ENFN->font_run_end_get(c->ENDT,
+                        ti->parent.format->font.font, &script_fi, &cur_fi,
+                        script, str, script_len);
                }
+
              evas_common_text_props_bidi_set(&ti->text_props,
                    c->par->bidi_props, ti->parent.text_pos);
-             evas_common_text_props_script_set(&ti->text_props, str, tmp_len);
+             evas_common_text_props_script_set(&ti->text_props, script);
+
              if (ti->parent.format->font.font)
                {
                   c->ENFN->font_text_props_info_create(c->ENDT,
-                        ti->parent.format->font.font, str, &ti->text_props,
-                        c->par->bidi_props, ti->parent.text_pos, tmp_len);
+                        cur_fi, str, &ti->text_props, c->par->bidi_props,
+                        ti->parent.text_pos, run_len);
                }
+             str += run_len;
+             cur_len -= run_len;
+             script_len -= run_len;
+
+             _layout_text_add_logical_item(c, ti, NULL);
           }
-        str += tmp_len;
-        cur_len -= tmp_len;
 
-        _layout_text_add_logical_item(c, ti, NULL);
 
-        /* Break if we reached the end. */
+        /* Break if we reached the end. We do it here
+         * because we want at least one run if it's an empty string. */
         if (!*str)
           break;
      }
 
+end:
    if (alloc_str) free(alloc_str);
 }
 
@@ -3283,21 +3315,33 @@ static Evas_Object_Textblock_Text_Item *
 _layout_ellipsis_item_new(Ctxt *c, const Evas_Object_Textblock_Item *cur_it)
 {
    Evas_Object_Textblock_Text_Item *ellip_ti;
+   Evas_Script_Type script;
+   void *script_fi = NULL, *cur_fi;
    size_t len = 1; /* The length of _ellip_str */
    ellip_ti = _layout_text_item_new(c,
          eina_list_data_get(eina_list_last(c->format_stack)));
    ellip_ti->parent.text_node = cur_it->text_node;
    ellip_ti->parent.text_pos = cur_it->text_pos;
+   script = evas_common_language_script_type_get(_ellip_str, len);
 
    evas_common_text_props_bidi_set(&ellip_ti->text_props,
          c->par->bidi_props, ellip_ti->parent.text_pos);
-   evas_common_text_props_script_set (&ellip_ti->text_props,
-         _ellip_str, len);
-   c->ENFN->font_text_props_info_create(c->ENDT,
-         ellip_ti->parent.format->font.font,
-         _ellip_str, &ellip_ti->text_props,
-         c->par->bidi_props,
-         ellip_ti->parent.text_pos, len);
+   evas_common_text_props_script_set (&ellip_ti->text_props, script);
+
+   if (ellip_ti->parent.format->font.font)
+     {
+        /* It's only 1 char anyway, we don't need the run end. */
+        (void) c->ENFN->font_run_end_get(c->ENDT,
+              ellip_ti->parent.format->font.font, &script_fi, &cur_fi,
+              script, _ellip_str, len);
+
+        c->ENFN->font_text_props_info_create(c->ENDT,
+              ellip_ti->parent.format->font.font,
+              _ellip_str, &ellip_ti->text_props,
+              c->par->bidi_props,
+              ellip_ti->parent.text_pos, len);
+     }
+
    _text_item_update_sizes(c, ellip_ti);
 
    if (cur_it->type == EVAS_TEXTBLOCK_ITEM_TEXT)
index 62e2597..533d897 100644 (file)
@@ -64,6 +64,7 @@ EAPI int               evas_common_font_query_char_coords    (RGBA_Font *fn, con
 EAPI int               evas_common_font_query_pen_coords     (RGBA_Font *fn, const Evas_Text_Props *intl_props, int pos, int *cpen_x, int *cy, int *cadv, int *ch);
 EAPI int               evas_common_font_query_char_at_coords (RGBA_Font *fn, const Evas_Text_Props *intl_props, int x, int y, int *cx, int *cy, int *cw, int *ch);
 EAPI int               evas_common_font_query_last_up_to_pos (RGBA_Font *fn, const Evas_Text_Props *intl_props, int x, int y);
+EAPI int               evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi, RGBA_Font_Int **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len);
 
 #ifdef EVAS_FRAME_QUEUING
 EAPI void evas_common_font_draw_finish(void);
index 5a1f2d9..fe704a3 100644 (file)
@@ -262,8 +262,8 @@ _evas_common_font_ot_shape(hb_buffer_t *buffer, RGBA_Font_Int *fi)
 }
 
 EAPI Eina_Bool
-evas_common_font_ot_populate_text_props(void *_fn __UNUSED__,
-      const Eina_Unicode *text, Evas_Text_Props *props, int len)
+evas_common_font_ot_populate_text_props(const Eina_Unicode *text,
+      Evas_Text_Props *props, int len)
 {
    RGBA_Font_Int *fi;
    hb_buffer_t *buffer;
index adbe54d..bc5ab02 100644 (file)
@@ -39,7 +39,7 @@ EAPI int
 evas_common_font_ot_cluster_size_get(const Evas_Text_Props *props, size_t char_index);
 
 EAPI Eina_Bool
-evas_common_font_ot_populate_text_props(void *fn, const Eina_Unicode *text,
+evas_common_font_ot_populate_text_props(const Eina_Unicode *text,
       Evas_Text_Props *props, int len);
 #endif
 
index d2a34ad..b3bb783 100644 (file)
@@ -3,6 +3,145 @@
 #include "evas_font_private.h" /* for Frame-Queuing support */
 #include "evas_font_ot.h"
 
+
+/* FIXME: Check coverage according to the font and not by actually loading */
+/**
+ * @internal
+ * Find the end of a run according to font coverage, and return the base script
+ * font and the current wanted font.
+ *
+ * @param[in] fn the font to use.
+ * @param script_fi The base font instance to be used with the script. If NULL, then it's calculated and returned in this variable, if not NULL, it's used and not modified.
+ * @param[out] cur_fi The font instance found for the current run.
+ * @param[in] script the base script
+ * @param[in] text the text to work on.
+ * @param[in] run_let the current run len, i.e "search limit".
+ * @return length of the run found.
+ */
+EAPI int
+evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi, RGBA_Font_Int **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len)
+{
+   RGBA_Font_Int *fi;
+   const Eina_Unicode *run_end = text + run_len;
+   const Eina_Unicode *itr;
+
+   /* If there's no current script_fi, find it first */
+   if (!*script_fi)
+     {
+        const Eina_Unicode *base_char = NULL;
+        /* Skip common chars */
+        for (base_char = text ;
+             (base_char < run_end) &&
+             (evas_common_language_char_script_get(*base_char) != script) ;
+             base_char++)
+           ;
+        if (base_char == run_end) base_char = text;
+
+        /* Find the first renderable char */
+        while (base_char < run_end)
+          {
+             /* 0x1F is the last ASCII contral char, just a hack in
+              * the meanwhile. */
+             if ((*base_char > 0x1F) &&
+                   evas_common_font_glyph_search(fn, &fi, *base_char))
+                break;
+             base_char++;
+          }
+
+
+        /* If everything else fails, at least try to find a font for the
+         * replacement char */
+        if (base_char == run_end)
+           evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
+
+        *script_fi = fi;
+     }
+   else
+     {
+        fi = *script_fi;
+     }
+
+   /* Find the longest run of the same font starting from the start position
+    * and update cur_fi accordingly. */
+   itr = text;
+   while (itr < run_end)
+     {
+        RGBA_Font_Int *tmp_fi;
+        /* Itr will end up being the first of the next run  */
+        for ( ; itr < run_end ; itr++)
+          {
+             /* Break if either it's not in the font, or if it is in the
+              * script's font. */
+             if (fi == *script_fi)
+               {
+                  if (!evas_common_get_char_index(fi, *itr))
+                     break;
+               }
+             else
+               {
+                  if (evas_common_get_char_index(*script_fi, *itr))
+                     break;
+               }
+          }
+
+        /* If the script font doesn't fit even one char, find a new font. */
+        if (itr == text)
+          {
+             /* If we can find a font, use it. Otherwise, find the first
+              * char the run of chars that can't be rendered until the first
+              * one that can. */
+             if (evas_common_font_glyph_search(fn, &tmp_fi, *itr))
+               {
+                  fi = tmp_fi;
+               }
+             else
+               {
+                  itr++;
+                  /* Go through all the chars that can't be rendered with any
+                   * font */
+                  for ( ; itr < run_end ; itr++)
+                    {
+                       if (evas_common_get_char_index(fi, *itr) ||
+                             evas_common_font_glyph_search(fn, &fi, *itr))
+                          break;
+                    }
+
+                  /* If we found a renderable character and the found font
+                   * can render the replacement char, continue, otherwise
+                   * find a font most suitable for the replacement char and
+                   * break */
+                  if ((itr == run_end) ||
+                        !evas_common_get_char_index(fi, REPLACEMENT_CHAR))
+                    {
+                       evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
+                       break;
+                    }
+               }
+             itr++;
+          }
+        else
+          {
+             /* If this char is not renderable by any font, but the replacement
+              * char can be rendered using the currentfont, continue this
+              * run. */
+             if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) &&
+                   evas_common_get_char_index(fi, REPLACEMENT_CHAR))
+               {
+                  itr++;
+               }
+             else
+               {
+                  /* Done, we did as much as possible */
+                  break;
+               }
+          }
+     }
+
+   *cur_fi = fi;
+
+   return itr - text;
+}
+
 /**
  * @internal
  * Calculate the kerning between "left" and "right.
index 6d48f4b..ab0a53e 100644 (file)
@@ -22,10 +22,9 @@ evas_common_text_props_bidi_set(Evas_Text_Props *props,
 }
 
 void
-evas_common_text_props_script_set(Evas_Text_Props *props,
-      const Eina_Unicode *str, size_t len)
+evas_common_text_props_script_set(Evas_Text_Props *props, Evas_Script_Type scr)
 {
-   props->script = evas_common_language_script_type_get(str, len);
+   props->script = scr;
 }
 
 void
@@ -195,12 +194,11 @@ evas_common_text_props_merge(Evas_Text_Props *item1,
 }
 
 EAPI Eina_Bool
-evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
+evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text,
       Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props,
       size_t par_pos, int len)
 {
-   RGBA_Font *fn = (RGBA_Font *) _fn;
-   RGBA_Font_Int *fi;
+   RGBA_Font_Int *fi = (RGBA_Font_Int *) _fi;
 
    if (text_props->info)
      {
@@ -213,35 +211,6 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
      }
    text_props->info = calloc(1, sizeof(Evas_Text_Props_Info));
 
-   fi = fn->fonts->data;
-   /* Load the glyph according to the first letter of the script, pretty
-    * bad, but will have to do */
-     {
-        const Eina_Unicode *base_char;
-        /* Skip common chars */
-        for (base_char = text ;
-             *base_char &&
-             (evas_common_language_char_script_get(*base_char) !=
-             text_props->script) ;
-             base_char++)
-           ;
-        if (!*base_char) base_char = text;
-
-        /* Find the first renderable char, and if there is none, find
-         * one that can show the replacement char. */
-        while (*base_char)
-          {
-             /* 0x1F is the last ASCII contral char. */
-             if ((*base_char > 0x1F) &&
-                   evas_common_font_glyph_search(fn, &fi, *base_char))
-                break;
-             base_char++;
-          }
-
-        if (!*base_char)
-           evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
-     }
-
    text_props->font_instance = fi;
 
    evas_common_font_int_reload(fi);
@@ -260,7 +229,7 @@ evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
    (void) par_props;
    (void) par_pos;
 
-   evas_common_font_ot_populate_text_props(fn, text, text_props, len);
+   evas_common_font_ot_populate_text_props(text, text_props, len);
 
    gl_itr = text_props->info->glyph;
    for (char_index = 0 ; char_index < text_props->len ; char_index++)
index 689ab29..5a0a439 100644 (file)
@@ -54,11 +54,10 @@ evas_common_text_props_bidi_set(Evas_Text_Props *props,
       Evas_BiDi_Paragraph_Props *bidi_par_props, size_t start);
 
 void
-evas_common_text_props_script_set(Evas_Text_Props *props,
-      const Eina_Unicode *str, size_t len);
+evas_common_text_props_script_set(Evas_Text_Props *props, Evas_Script_Type scr);
 
 EAPI Eina_Bool
-evas_common_text_props_content_create(void *_fn, const Eina_Unicode *text,
+evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text,
       Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props,
       size_t par_pos, int len);
 
index 51a7a24..94c891c 100644 (file)
@@ -733,6 +733,7 @@ struct _Evas_Func
    int  (*gl_native_surface_get)         (void *data, void *surface, void *native_surface);
    void *(*gl_api_get)                   (void *data);
    int  (*image_load_error_get)          (void *data, void *image);
+   int  (*font_run_end_get)     (void *data __UNUSED__, void *fn, void **script_fi, void **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len);
 };
 
 struct _Evas_Image_Load_Func
index 3e2c89d..95d46b9 100644 (file)
@@ -799,6 +799,14 @@ eng_font_last_up_to_pos(void *data __UNUSED__, void *font, const Evas_Text_Props
    return evas_common_font_query_last_up_to_pos(font, text_props, x, y);
 }
 
+static int
+eng_font_run_font_end_get(void *data __UNUSED__, void *fn, void **script_fi, void **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len)
+{
+   return evas_common_font_query_run_font_end_get(fn,
+         (RGBA_Font_Int **) script_fi, (RGBA_Font_Int **) cur_fi,
+         script, text, run_len);
+}
+
 static void
 eng_font_draw(void *data __UNUSED__, void *context, void *surface, void *font, int x, int y, int w __UNUSED__, int h __UNUSED__, int ow __UNUSED__, int oh __UNUSED__, const Evas_Text_Props *text_props)
 {
@@ -1081,7 +1089,8 @@ static Evas_Func func =
      NULL, // FIXME: need software mesa for gl rendering <- gl_proc_address_get
      NULL, // FIXME: need software mesa for gl rendering <- gl_native_surface_get
      NULL, // FIXME: need software mesa for gl rendering <- gl_api_get
-     eng_image_load_error_get
+     eng_image_load_error_get,
+     eng_font_run_font_end_get
    /* FUTURE software generic calls go here */
 };