Evas font+textblock: Stopped using FcNameParse, parse ourselves.
authortasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 1 Aug 2011 08:20:52 +0000 (08:20 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 1 Aug 2011 08:20:52 +0000 (08:20 +0000)
FcNameParse is pretty bad, not only that it's pretty bad, it doesn't
work well in some cases. Also this makes our lives a lot easier since
we want to allow overriding style/weight/width and etc from markup.
We now parse the "font" markup ourselves, populating a font description
structure that we created, and then override values in it as needed.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/evas@61936 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/canvas/evas_font_dir.c
src/lib/canvas/evas_object_text.c
src/lib/canvas/evas_object_textblock.c
src/lib/include/evas_private.h

index 0a248cc..e07dc9d 100644 (file)
@@ -26,9 +26,9 @@ typedef struct _Fndat Fndat;
 
 struct _Fndat
 {
-   const char      *name;
+   Evas_Font_Description *fdesc;
    const char      *source;
-   int              size;
+   Evas_Font_Size   size;
    Evas_Font_Set   *font;
    int              ref;
    Font_Rend_Flags  wanted_rend;
@@ -136,7 +136,7 @@ evas_fonts_zero_free(Evas *evas)
 
    EINA_LIST_FREE(fonts_zero, fd)
      {
-       if (fd->name) eina_stringshare_del(fd->name);
+        if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
        if (fd->source) eina_stringshare_del(fd->source);
        evas->engine.func->font_free(evas->engine.data.output, fd->font);
 #ifdef HAVE_FONTCONFIG
@@ -160,7 +160,7 @@ evas_fonts_zero_presure(Evas *evas)
        if (fd->ref != 0) break;
        fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
 
-       if (fd->name) eina_stringshare_del(fd->name);
+        if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
        if (fd->source) eina_stringshare_del(fd->source);
        evas->engine.func->font_free(evas->engine.data.output, fd->font);
 #ifdef HAVE_FONTCONFIG
@@ -200,7 +200,7 @@ evas_font_free(Evas *evas, void *font)
        if (fd->ref != 0) break;
        fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero);
 
-       if (fd->name) eina_stringshare_del(fd->name);
+        if (fd->fdesc) evas_font_desc_unref(fd->fdesc);
        if (fd->source) eina_stringshare_del(fd->source);
        evas->engine.func->font_free(evas->engine.data.output, fd->font);
 #ifdef HAVE_FONTCONFIG
@@ -254,54 +254,242 @@ evas_load_fontconfig(Evas *evas, FcFontSet *set, int size,
 }
 #endif
 
-static Eina_Bool
-_font_style_name_match(const char *font_name, const char *style_name)
+struct _FcPattern {   
+   int             num;
+   int             size;
+   intptr_t        elts_offset;
+   int             ref;
+};
+
+#ifdef HAVE_FONTCONFIG
+/* In sync with Evas_Font_Style, Evas_Font_Weight and Evas_Font_Width */
+static int _fc_slant_map[] =
+{
+   FC_SLANT_ROMAN,
+   FC_SLANT_OBLIQUE,
+   FC_SLANT_ITALIC
+};
+
+static int _fc_weight_map[] =
+{
+   FC_WEIGHT_NORMAL,
+   FC_WEIGHT_THIN,
+   FC_WEIGHT_ULTRALIGHT,
+   FC_WEIGHT_LIGHT,
+   FC_WEIGHT_BOOK,
+   FC_WEIGHT_MEDIUM,
+   FC_WEIGHT_SEMIBOLD,
+   FC_WEIGHT_BOLD,
+   FC_WEIGHT_ULTRABOLD,
+   FC_WEIGHT_BLACK,
+   FC_WEIGHT_EXTRABLACK
+};
+
+# ifdef FC_WIDTH
+static int _fc_width_map[] =
+{
+   FC_WIDTH_NORMAL,
+   FC_WIDTH_ULTRACONDENSED,
+   FC_WIDTH_EXTRACONDENSED,
+   FC_WIDTH_CONDENSED,
+   FC_WIDTH_SEMICONDENSED,
+   FC_WIDTH_SEMIEXPANDED,
+   FC_WIDTH_EXPANDED,
+   FC_WIDTH_EXTRAEXPANDED,
+   FC_WIDTH_ULTRAEXPANDED
+};
+# endif
+
+#endif
+
+struct _Style_Map
+{
+   const char *name;
+   int type;
+};
+typedef struct _Style_Map Style_Map;
+
+static Style_Map _style_width_map[] =
+{
+     {"normal", EVAS_FONT_WIDTH_NORMAL},
+     {"ultracondensed", EVAS_FONT_WIDTH_ULTRACONDENSED},
+     {"extracondensed", EVAS_FONT_WIDTH_EXTRACONDENSED},
+     {"condensed", EVAS_FONT_WIDTH_CONDENSED},
+     {"semicondensed", EVAS_FONT_WIDTH_SEMICONDENSED},
+     {"semiexpanded", EVAS_FONT_WIDTH_SEMIEXPANDED},
+     {"expanded", EVAS_FONT_WIDTH_EXPANDED},
+     {"extraexpanded", EVAS_FONT_WIDTH_EXTRAEXPANDED},
+     {"ultraexpanded", EVAS_FONT_WIDTH_ULTRAEXPANDED},
+};
+
+static Style_Map _style_weight_map[] =
 {
-   char *style_key = NULL;
+     {"normal", EVAS_FONT_WEIGHT_NORMAL},
+     {"thin", EVAS_FONT_WEIGHT_THIN},
+     {"ultralight", EVAS_FONT_WEIGHT_ULTRALIGHT},
+     {"light", EVAS_FONT_WEIGHT_LIGHT},
+     {"book", EVAS_FONT_WEIGHT_BOOK},
+     {"medium", EVAS_FONT_WEIGHT_MEDIUM},
+     {"semibold", EVAS_FONT_WEIGHT_SEMIBOLD},
+     {"bold", EVAS_FONT_WEIGHT_BOLD},
+     {"ultrabold", EVAS_FONT_WEIGHT_ULTRABOLD},
+     {"black", EVAS_FONT_WEIGHT_BLACK},
+     {"extrablack", EVAS_FONT_WEIGHT_EXTRABLACK}
+};
 
-   style_key = strchr(font_name, ':');
-   if (!style_key) return EINA_FALSE;
-   if (strlen(style_key) > 2) style_key++;
-   if (strstr(style_key, "style="))
+static Style_Map _style_slant_map[] =
+{
+     {"normal", EVAS_FONT_SLANT_NORMAL},
+     {"oblique", EVAS_FONT_SLANT_OBLIQUE},
+     {"italic", EVAS_FONT_SLANT_ITALIC}
+};
+
+#define _STYLE_MAP_LEN(x) (sizeof(x) / sizeof(*(x)))
+/**
+ * @internal
+ * Find a certain attribute from the map in the style.
+ * @return the index of the found one.
+ */
+static int
+_evas_font_style_find_internal(const char *style, const char *style_end,
+      Style_Map _map[], size_t map_len)
+{
+   size_t i;
+   while (style < style_end)
      {
-        if (!strcmp(style_name, "Italic"))
+        for (i = 0 ; i < map_len ; i++)
           {
-             if (strstr(style_key, "Italic")
-                 || strstr(style_key, "italic")
-                 || strstr(style_key, "Cursiva")
-                 || strstr(style_key, "cursiva")
-                 || strstr(style_key, "Oblique")
-                 || strstr(style_key, "oblique"))
-                return EINA_TRUE;
-             else
-                return EINA_FALSE;
+             size_t len;
+             const char *cur = _map[i].name;
+             len = strlen(cur);
+             if (!strncasecmp(style, cur, len) &&
+                   (!cur[len] || (cur[len] == ' ')))
+               {
+                  return _map[i].type;
+               }
           }
-        else if (!strcmp(style_name, "Bold"))
+        style = strchr(style, ' ');
+        if (!style)
+           break;
+
+        while (*style && (*style == ' '))
+           style++;
+     }
+   return 0;
+}
+
+int
+evas_font_style_find(const char *start, const char *end,
+      Evas_Font_Style style)
+{
+#define _RET_STYLE(x) \
+   return _evas_font_style_find_internal(start, end, \
+                   _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
+   switch (style)
+     {
+        case EVAS_FONT_STYLE_SLANT:
+           _RET_STYLE(slant);
+        case EVAS_FONT_STYLE_WEIGHT:
+           _RET_STYLE(weight);
+        case EVAS_FONT_STYLE_WIDTH:
+           _RET_STYLE(width);
+        default:
+           return 0;
+     }
+#undef _RET_STYLE
+}
+
+void
+evas_font_desc_unref(Evas_Font_Description *fdesc)
+{
+   if (--(fdesc->ref) == 0)
+     {
+        eina_stringshare_del(fdesc->name);
+        free(fdesc);
+     }
+}
+
+Evas_Font_Description *
+evas_font_desc_ref(Evas_Font_Description *fdesc)
+{
+   fdesc->ref++;
+   return fdesc;
+}
+
+Evas_Font_Description *
+evas_font_desc_new(void)
+{
+   Evas_Font_Description *fdesc;
+   fdesc = calloc(1, sizeof(*fdesc));
+   fdesc->ref = 1;
+   fdesc->new = EINA_TRUE;
+
+   return fdesc;
+}
+
+Evas_Font_Description *
+evas_font_desc_dup(const Evas_Font_Description *fdesc)
+{
+   Evas_Font_Description *new;
+   new = evas_font_desc_new();
+   memcpy(new, fdesc, sizeof(*new));
+   new->ref = 1;
+   new->new = EINA_TRUE;
+   new->name = eina_stringshare_ref(new->name);
+
+   return new;
+}
+
+int
+evas_font_desc_cmp(const Evas_Font_Description *a,
+      const Evas_Font_Description *b)
+{
+   /* FIXME: Do actual comparison, i.e less than and bigger than. */
+   return !((a->name == b->name) && (a->weight == b->weight) &&
+         (a->slant == b->slant) && (a->width == b->width) &&
+         (a->lang == b->lang));
+}
+
+void
+evas_font_name_parse(Evas_Font_Description *fdesc, const char *name)
+{
+   const char *end;
+
+   end = strchr(name, ':');
+   if (!end)
+      fdesc->name = eina_stringshare_add(name);
+   else
+      fdesc->name = eina_stringshare_add_length(name, end - name);
+
+   while (end)
+     {
+        const char *tend;
+        name = end;
+        end = strchr(end + 1, ':');
+        if (!end)
+           tend = name + strlen(name);
+        else
+           tend = end;
+
+        if (!strncmp(name, ":style=", 7))
           {
-             if (strstr(style_key, "Bold")
-                 || strstr(style_key, "bold")
-                 || strstr(style_key, "Negreta")
-                 || strstr(style_key, "negreta"))
-                return EINA_TRUE;
-             else
-                return EINA_FALSE;
+#define _SET_STYLE(x) \
+             fdesc->x = _evas_font_style_find_internal(name + 7, tend, \
+                   _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map));
+             _SET_STYLE(slant);
+             _SET_STYLE(weight);
+             _SET_STYLE(width);
+#undef _SET_STYLE
+          }
+        else if (!strncmp(name, ":lang=", 6))
+          {
+             /* FIXME: handle lang. */
           }
-        else
-           return EINA_FALSE;
      }
-   else
-      return EINA_FALSE;
 }
 
-struct _FcPattern {   
-   int             num;
-   int             size;
-   intptr_t        elts_offset;
-   int             ref;
-};
-
 void *
-evas_font_load(Evas *evas, const char *name, const char *source, int size)
+evas_font_load(Evas *evas, Evas_Font_Description *fdesc, const char *source, Evas_Font_Size size)
 {
 #ifdef HAVE_FONTCONFIG
    FcPattern *p_nm = NULL;
@@ -314,24 +502,25 @@ evas_font_load(Evas *evas, const char *name, const char *source, int size)
    char *nm;
    Font_Rend_Flags wanted_rend = 0;
 
-   if (!name) return NULL;
-   if (name[0] == 0) return NULL;
+   if (!fdesc) return NULL;
+   fdesc->new = EINA_FALSE;
 
-   if (_font_style_name_match(name, "Italic"))
+   if (fdesc->slant != EVAS_FONT_SLANT_NORMAL)
       wanted_rend |= FONT_REND_ITALIC;
-   if (_font_style_name_match(name, "Bold"))
+   if (fdesc->weight == EVAS_FONT_WEIGHT_BOLD)
       wanted_rend |= FONT_REND_BOLD;
 
    evas_font_init();
 
    EINA_LIST_FOREACH(fonts_cache, l, fd)
      {
-       if (!strcmp(name, fd->name))
+        if (!evas_font_desc_cmp(fdesc, fd->fdesc))
          {
             if (((!source) && (!fd->source)) ||
                 ((source) && (fd->source) && (!strcmp(source, fd->source))))
               {
-                 if ((size == fd->size) && (wanted_rend == fd->wanted_rend))
+                 if ((size == fd->size) &&
+                        (wanted_rend == fd->wanted_rend))
                    {
                       fonts_cache = eina_list_promote_list(fonts_cache, l);
                       fd->ref++;
@@ -351,12 +540,13 @@ evas_font_load(Evas *evas, const char *name, const char *source, int size)
 
    EINA_LIST_FOREACH(fonts_zero, l, fd)
      {
-       if (!strcmp(name, fd->name))
+        if (!evas_font_desc_cmp(fdesc, fd->fdesc))
          {
             if (((!source) && (!fd->source)) ||
                 ((source) && (fd->source) && (!strcmp(source, fd->source))))
               {
-                 if ((size == fd->size) && (wanted_rend == fd->wanted_rend))
+                 if ((size == fd->size) &&
+                        (wanted_rend == fd->wanted_rend))
                    {
                       fonts_zero = eina_list_remove_list(fonts_zero, l);
                       fonts_cache = eina_list_prepend(fonts_cache, fd);
@@ -375,7 +565,7 @@ evas_font_load(Evas *evas, const char *name, const char *source, int size)
          }
      }
 
-   fonts = evas_font_set_get(name);
+   fonts = evas_font_set_get(fdesc->name);
    EINA_LIST_FOREACH(fonts, l, nm) /* Load each font in append */
      {
        if (l == fonts || !font) /* First iteration OR no font */
@@ -510,7 +700,16 @@ evas_font_load(Evas *evas, const char *name, const char *source, int size)
      {
        FcResult res;
 
-       p_nm = FcNameParse((FcChar8 *)name);
+        p_nm = FcPatternBuild (NULL,
+              FC_WEIGHT, FcTypeInteger, _fc_weight_map[fdesc->weight],
+              FC_SLANT,  FcTypeInteger, _fc_slant_map[fdesc->slant],
+#ifdef FC_WIDTH
+              FC_WIDTH,  FcTypeInteger, _fc_width_map[fdesc->width],
+#endif
+              NULL);
+        /* FIXME: Handle font fallbacks!!! */
+        FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) fdesc->name);
+
        FcConfigSubstitute(NULL, p_nm, FcMatchPattern);
        FcDefaultSubstitute(p_nm);
 
@@ -518,17 +717,12 @@ evas_font_load(Evas *evas, const char *name, const char *source, int size)
        set = FcFontSort(NULL, p_nm, FcTrue, NULL, &res);
        if (!set)
          {
-            ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", name);
+            ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", fdesc->name);
             FcPatternDestroy(p_nm);
             p_nm = NULL;
          }
        else
           {
-             // FIXME: this i think is a bugfix for a rare bug... but i'm
-             // not sure 100%. it seems that way from fc. if trim is set
-             // to FcTrue...
-             //  ok - not a bugfix... but there is something going on somewhere that's weird?
-//             FcPatternReference(p_nm); /* we have to reference count the pat */
              font = evas_load_fontconfig(evas, set, size, wanted_rend);
           }
      }
@@ -538,9 +732,8 @@ evas_font_load(Evas *evas, const char *name, const char *source, int size)
    fd = calloc(1, sizeof(Fndat));
    if (fd)
      {
-       fd->name = eina_stringshare_add(name);
+       fd->fdesc = evas_font_desc_ref(fdesc);
        if (source) fd->source = eina_stringshare_add(source);
-       fd->size = size;
        fd->font = font;
         fd->wanted_rend = wanted_rend;
        fd->ref = 1;
index 48b0193..cd0511d 100644 (file)
@@ -19,6 +19,7 @@ struct _Evas_Object_Text
    struct {
       const char          *utf8_text; /* The text exposed to the API */
       const char          *font;
+      Evas_Font_Description *fdesc;
       const char          *source;
       Evas_Font_Size       size;
       struct {
@@ -345,7 +346,7 @@ evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size siz
 {
    Evas_Object_Text *o;
    int is, was = 0, pass = 0;
-   int same_font = 0;
+   Evas_Font_Description *fdesc;
 
    if ((!font) || (size <= 0)) return;
    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
@@ -356,11 +357,22 @@ evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size siz
    return;
    MAGIC_CHECK_END();
 
-   if ((o->cur.font) && (font) && (!strcmp(o->cur.font, font)))
+   fdesc = evas_font_desc_new();
+   evas_font_name_parse(fdesc, font);
+   if (o->cur.fdesc && !evas_font_desc_cmp(fdesc, o->cur.fdesc) &&
+         (size == o->cur.size))
      {
-       same_font = 1;
-       if (size == o->cur.size) return;
+        evas_font_desc_unref(fdesc);
+        return;
      }
+
+   if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
+   o->cur.fdesc = fdesc;
+
+   o->cur.size = size;
+   eina_stringshare_replace(&o->cur.font, font);
+   o->prev.font = NULL;
+
    if (obj->layer->evas->events_frozen <= 0)
      {
        pass = evas_event_passes_through(obj);
@@ -381,19 +393,9 @@ evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size siz
        evas_font_free(obj->layer->evas, o->font);
        o->font = NULL;
      }
-   if (!same_font)
-     {
-       /*
-       if (o->cur.font) eina_stringshare_del(o->cur.font);
-       if (font) o->cur.font = eina_stringshare_add(font);
-       else o->cur.font = NULL;
-        */
-       eina_stringshare_replace(&o->cur.font, font);
-       o->prev.font = NULL;
-     }
-   o->cur.size = size;
-   o->font = evas_font_load(obj->layer->evas, o->cur.font, o->cur.source,
-                                  (int)(((double)o->cur.size) * obj->cur.scale));
+
+   o->font = evas_font_load(obj->layer->evas, o->cur.fdesc, o->cur.source,
+         (int)(((double) o->cur.size) * obj->cur.scale));
    if (o->font)
      {
         o->ascent = ENFN->font_ascent_get(ENDT, o->font);
@@ -1441,6 +1443,7 @@ evas_object_text_free(Evas_Object *obj)
    if (o->items) _evas_object_text_items_clear(o);
    if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text);
    if (o->cur.font) eina_stringshare_del(o->cur.font);
+   if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc);
    if (o->cur.source) eina_stringshare_del(o->cur.source);
    if (o->font) evas_font_free(obj->layer->evas, o->font);
 #ifdef BIDI_SUPPORT
index f2c97f9..a686321 100644 (file)
@@ -348,11 +348,11 @@ struct _Evas_Object_Textblock_Format
    double               halign;
    double               valign;
    struct {
-      const char       *name;
+      Evas_Font_Description *fdesc;
       const char       *source;
       const char       *fallbacks;
       Evas_Font_Set    *font;
-      int               size;
+      Evas_Font_Size    size;
    } font;
    struct {
       struct {
@@ -620,7 +620,7 @@ _format_unref_free(const Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
 {
    fmt->ref--;
    if (fmt->ref > 0) return;
-   if (fmt->font.name) eina_stringshare_del(fmt->font.name);
+   if (fmt->font.fdesc) evas_font_desc_unref(fmt->font.fdesc);
    if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks);
    if (fmt->font.source) eina_stringshare_del(fmt->font.source);
    evas_font_free(obj->layer->evas, fmt->font.font);
@@ -1131,95 +1131,6 @@ _format_clean_param(char *dst, const char *src)
    *ds = 0;
 }
 
-static const char *_style_weight_map[] = { "ultralight", "light", "bold",
-     "ultrabold", "black", "normal" };
-#define _STYLE_WEIGHT_MAP_LEN (sizeof(_style_weight_map) / sizeof(_style_weight_map[0]))
-
-static const char *_style_style_map[] = { "normal", "oblique", "italic" };
-#define _STYLE_STYLE_MAP_LEN (sizeof(_style_style_map) / sizeof(_style_style_map[0]))
-/**
- * @internal
- * Find a certain attribute from the map in the style.
- * @return true if found, false otherwise.
- */
-static Eina_Bool
-_format_font_style_find(const char *style, const char *style_end,
-      const char **start, const char **end, const char *_map[], size_t map_len)
-{
-   size_t i;
-   while (style < style_end)
-     {
-        for (i = 0 ; i < map_len ; i++)
-          {
-             size_t len;
-             const char *cur = _map[i];
-             len = strlen(cur);
-             if (!strncasecmp(style, cur, len) &&
-                   (!cur[len] || (cur[len] == ' ')))
-               {
-                  *start = style;
-                  *end = *start + len;
-                  return EINA_TRUE;
-               }
-          }
-        style = strchr(style, ' ');
-        if (!style)
-           break;
-
-        while (*style && _is_white(*style))
-           style++;
-     }
-   return EINA_FALSE;
-}
-
-static void
-_format_command_parse_font_weight_style(Evas_Object_Textblock_Format *fmt,
-      const char *param, const char *_map[], size_t map_len)
-{
-   size_t flen = eina_stringshare_strlen(fmt->font.name);
-   const char *style = strstr(fmt->font.name, ":style=");
-   if (style)
-     {
-        Eina_Strbuf *buf;
-        const char *found_start, *found_end;
-        const char *style_end = strchr(style + 7, ':');
-        /* Point to the end, either it be the next attribute,
-         * or the terminating 0 */
-        if (!style_end)
-           style_end = fmt->font.name + flen;
-
-        buf = eina_strbuf_new();
-        eina_strbuf_append_length(buf, fmt->font.name, flen);
-
-        if (_format_font_style_find(style + 7, style_end,
-                 &found_start, &found_end, _map, map_len))
-          {
-             eina_strbuf_remove(buf, found_start - fmt->font.name,
-                   found_end - fmt->font.name);
-          }
-        else
-          {
-             found_start = style + 7; /* + 7 for :style= */
-             eina_strbuf_insert_char(buf, ' ', found_start - fmt->font.name);
-          }
-        eina_strbuf_insert(buf, param, found_start - fmt->font.name);
-        if (fmt->font.name) eina_stringshare_del(fmt->font.name);
-        fmt->font.name = eina_stringshare_add(eina_strbuf_string_get(buf));
-        eina_strbuf_free(buf);
-     }
-   else
-     {
-        /* Make a buffer big enough to hold whatever we do.
-         * 7 == len(:style=). */
-        char *tmpres = alloca(flen + strlen(param) + 7 + 1);
-        /* Handle font.name == NULL */
-        memcpy(tmpres, fmt->font.name, flen);
-        sprintf(tmpres + flen, ":style=%s", param);
-        if (fmt->font.name) eina_stringshare_del(fmt->font.name);
-        fmt->font.name = eina_stringshare_add(tmpres);
-     }
-}
-
 /**
  * @internal
  * Parses the cmd and parameter and adds the parsed format to fmt.
@@ -1232,7 +1143,6 @@ _format_command_parse_font_weight_style(Evas_Object_Textblock_Format *fmt,
 static void
 _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *cmd, const char *param)
 {
-   int new_font = 0;
    int len;
    char *tmp_param;
 
@@ -1240,15 +1150,26 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char
    tmp_param = alloca(len + 1);
 
    _format_clean_param(tmp_param, param);
-   if (cmd == fontstr)
+
+   /* If we are changing the font, create the fdesc. */
+   if ((cmd == font_weightstr) || (cmd == font_stylestr) || (cmd == fontstr))
      {
-        if ((!fmt->font.name) ||
-              ((fmt->font.name) && (strcmp(fmt->font.name, tmp_param))))
+        if (!fmt->font.fdesc)
           {
-             if (fmt->font.name) eina_stringshare_del(fmt->font.name);
-             fmt->font.name = eina_stringshare_add(tmp_param);
-             new_font = 1;
+             fmt->font.fdesc = evas_font_desc_new();
           }
+        else if (!fmt->font.fdesc->new)
+          {
+             Evas_Font_Description *old = fmt->font.fdesc;
+             fmt->font.fdesc = evas_font_desc_dup(fmt->font.fdesc);
+             if (old) evas_font_desc_unref(old);
+          }
+     }
+
+
+   if (cmd == fontstr)
+     {
+        evas_font_name_parse(fmt->font.fdesc, tmp_param);
      }
    else if (cmd == font_fallbacksstr)
      {
@@ -1260,7 +1181,6 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char
               */
              if (fmt->font.fallbacks) eina_stringshare_del(fmt->font.fallbacks);
              fmt->font.fallbacks = eina_stringshare_add(tmp_param);
-             new_font = 1;
           }
      }
    else if (cmd == font_sizestr)
@@ -1271,7 +1191,6 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char
         if (v != fmt->font.size)
           {
              fmt->font.size = v;
-             new_font = 1;
           }
      }
    else if (cmd == font_sourcestr)
@@ -1281,20 +1200,17 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char
           {
              if (fmt->font.source) eina_stringshare_del(fmt->font.source);
              fmt->font.source = eina_stringshare_add(tmp_param);
-             new_font = 1;
           }
      }
    if (cmd == font_weightstr)
      {
-        _format_command_parse_font_weight_style(fmt, tmp_param,
-              _style_weight_map, _STYLE_WEIGHT_MAP_LEN);
-        new_font = 1;
+        fmt->font.fdesc->weight = evas_font_style_find(tmp_param,
+              tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_WEIGHT);
      }
    if (cmd == font_stylestr)
      {
-        _format_command_parse_font_weight_style(fmt, tmp_param,
-              _style_style_map, _STYLE_STYLE_MAP_LEN);
-        new_font = 1;
+        fmt->font.fdesc->slant = evas_font_style_find(tmp_param,
+              tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_SLANT);
      }
    else if (cmd == colorstr)
      _format_color_parse(tmp_param,
@@ -1616,29 +1532,6 @@ _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char
         else if (!strcmp(tmp_param, "on"))
           fmt->password = 1;
      }
-
-   if (new_font)
-     {
-        void *of;
-        char *buf = NULL;
-
-        of = fmt->font.font;
-        if ((fmt->font.name) && (fmt->font.fallbacks))
-          {
-             buf = malloc(strlen(fmt->font.name) + 1 + strlen(fmt->font.fallbacks) + 1);
-             strcpy(buf, fmt->font.name);
-             strcat(buf, ",");
-             strcat(buf, fmt->font.fallbacks);
-          }
-        else if (fmt->font.name)
-          buf = strdup(fmt->font.name);
-
-        fmt->font.font = evas_font_load(obj->layer->evas,
-              buf, fmt->font.source,
-              (int)(((double)fmt->font.size) * obj->cur.scale));
-        if (buf) free(buf);
-        if (of) evas_font_free(obj->layer->evas, of);
-     }
 }
 
 /**
@@ -1796,22 +1689,14 @@ _format_dup(Evas_Object *obj, const Evas_Object_Textblock_Format *fmt)
    fmt2 = calloc(1, sizeof(Evas_Object_Textblock_Format));
    memcpy(fmt2, fmt, sizeof(Evas_Object_Textblock_Format));
    fmt2->ref = 1;
-   if (fmt->font.name) fmt2->font.name = eina_stringshare_add(fmt->font.name);
+   fmt2->font.fdesc = evas_font_desc_ref(fmt->font.fdesc);
+
    if (fmt->font.fallbacks) fmt2->font.fallbacks = eina_stringshare_add(fmt->font.fallbacks);
    if (fmt->font.source) fmt2->font.source = eina_stringshare_add(fmt->font.source);
 
-   if ((fmt2->font.name) && (fmt2->font.fallbacks))
-     {
-        buf = malloc(strlen(fmt2->font.name) + 1 + strlen(fmt2->font.fallbacks) + 1);
-        strcpy(buf, fmt2->font.name);
-        strcat(buf, ",");
-        strcat(buf, fmt2->font.fallbacks);
-     }
-   else if (fmt2->font.name)
-     buf = strdup(fmt2->font.name);
-   fmt2->font.font = evas_font_load(obj->layer->evas,
-         buf, fmt2->font.source,
-         (int)(((double)fmt2->font.size) * obj->cur.scale));
+   /* FIXME: just ref the font here... */
+   fmt2->font.font = evas_font_load(obj->layer->evas, fmt2->font.fdesc,
+         fmt2->font.source, (int)(((double) fmt2->font.size) * obj->cur.scale));
    if (buf) free(buf);
    return fmt2;
 }
@@ -3067,6 +2952,23 @@ _layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node_Format *n, const cha
 
 /**
  * @internal
+ * Should be call after we finish filling a format.
+ * FIXME: doc.
+ */
+static void
+_format_finalize(Evas_Object *obj, Evas_Object_Textblock_Format *fmt)
+{
+   void *of;
+
+   of = fmt->font.font;
+
+   fmt->font.font = evas_font_load(obj->layer->evas, fmt->font.fdesc,
+         fmt->font.source, (int)(((double) fmt->font.size) * obj->cur.scale));
+   if (of) evas_font_free(obj->layer->evas, of);
+}
+
+/**
+ * @internal
  * Returns true if the item is a tab
  * @def _IS_TAB(item)
  */
@@ -3253,6 +3155,7 @@ _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c,
                     }
                }
           }
+        _format_finalize(c->obj, fmt);
      }
 
      {
@@ -4222,6 +4125,7 @@ _layout(const Evas_Object *obj, int w, int h, int *w_ret, int *h_ret)
      {
         c->fmt = _layout_format_push(c, NULL, NULL);
         _format_fill(c->obj, c->fmt, c->o->style->default_tag);
+        _format_finalize(c->obj, c->fmt);
      }
    if (!c->fmt)
      {
index 768d7d2..77b41fd 100644 (file)
@@ -31,6 +31,7 @@ typedef struct _Evas_Size_Hints             Evas_Size_Hints;
 typedef struct _Evas_Font_Dir               Evas_Font_Dir;
 typedef struct _Evas_Font                   Evas_Font;
 typedef struct _Evas_Font_Alias             Evas_Font_Alias;
+typedef struct _Evas_Font_Description       Evas_Font_Description;
 typedef struct _Evas_Data_Node              Evas_Data_Node;
 typedef struct _Evas_Func_Node              Evas_Func_Node;
 typedef RGBA_Image_Loadopts                 Evas_Image_Load_Opts;
@@ -46,6 +47,11 @@ typedef struct _Evas_Map_Point              Evas_Map_Point;
 typedef struct _Evas_Smart_Cb_Description_Array Evas_Smart_Cb_Description_Array;
 typedef struct _Evas_Post_Callback          Evas_Post_Callback;
 
+typedef enum _Evas_Font_Style               Evas_Font_Style;
+typedef enum _Evas_Font_Slant               Evas_Font_Slant;
+typedef enum _Evas_Font_Weight              Evas_Font_Weight;
+typedef enum _Evas_Font_Width               Evas_Font_Width;
+
 /* General types - used for script type chceking */
 #define OPAQUE_TYPE(type) struct __##type { int a; }; \
    typedef struct __##type type
@@ -584,6 +590,61 @@ struct _Evas_Font_Alias
    Evas_Font  *fn;
 };
 
+enum _Evas_Font_Style
+{
+   EVAS_FONT_STYLE_SLANT,
+   EVAS_FONT_STYLE_WEIGHT,
+   EVAS_FONT_STYLE_WIDTH
+};
+
+enum _Evas_Font_Slant
+{
+   EVAS_FONT_SLANT_NORMAL,
+   EVAS_FONT_SLANT_OBLIQUE,
+   EVAS_FONT_SLANT_ITALIC
+};
+
+enum _Evas_Font_Weight
+{
+   EVAS_FONT_WEIGHT_NORMAL,
+   EVAS_FONT_WEIGHT_THIN,
+   EVAS_FONT_WEIGHT_ULTRALIGHT,
+   EVAS_FONT_WEIGHT_LIGHT,
+   EVAS_FONT_WEIGHT_BOOK,
+   EVAS_FONT_WEIGHT_MEDIUM,
+   EVAS_FONT_WEIGHT_SEMIBOLD,
+   EVAS_FONT_WEIGHT_BOLD,
+   EVAS_FONT_WEIGHT_ULTRABOLD,
+   EVAS_FONT_WEIGHT_BLACK,
+   EVAS_FONT_WEIGHT_EXTRABLACK
+};
+
+enum _Evas_Font_Width
+{
+   EVAS_FONT_WIDTH_NORMAL,
+   EVAS_FONT_WIDTH_ULTRACONDENSED,
+   EVAS_FONT_WIDTH_EXTRACONDENSED,
+   EVAS_FONT_WIDTH_CONDENSED,
+   EVAS_FONT_WIDTH_SEMICONDENSED,
+   EVAS_FONT_WIDTH_SEMIEXPANDED,
+   EVAS_FONT_WIDTH_EXPANDED,
+   EVAS_FONT_WIDTH_EXTRAEXPANDED,
+   EVAS_FONT_WIDTH_ULTRAEXPANDED
+};
+
+struct _Evas_Font_Description
+{
+   int ref;
+   /* We assume everywhere this is stringshared */
+   const char *name;
+
+   Evas_Font_Slant slant;
+   Evas_Font_Weight weight;
+   Evas_Font_Width width;
+
+   Eina_Bool new : 1;
+};
+
 struct _Evas_Object_Func
 {
    void (*free) (Evas_Object *obj);
@@ -871,7 +932,14 @@ void evas_font_dir_available_list_free(Eina_List *available);
 void evas_font_free(Evas *evas, void *font);
 void evas_fonts_zero_free(Evas *evas);
 void evas_fonts_zero_presure(Evas *evas);
-void *evas_font_load(Evas *evas, const char *name, const char *source, int size);
+void evas_font_name_parse(Evas_Font_Description *fdesc, const char *name);
+int evas_font_style_find(const char *start, const char *end, Evas_Font_Style style);
+Evas_Font_Description *evas_font_desc_new(void);
+Evas_Font_Description *evas_font_desc_dup(const Evas_Font_Description *fdesc);
+void evas_font_desc_unref(Evas_Font_Description *fdesc);
+int evas_font_desc_cmp(const Evas_Font_Description *a, const Evas_Font_Description *b);
+Evas_Font_Description *evas_font_desc_ref(Evas_Font_Description *fdesc);
+void * evas_font_load(Evas *evas, Evas_Font_Description *fdesc, const char *source, Evas_Font_Size size);
 void evas_font_load_hinting_set(Evas *evas, void *font, int hinting);
 void evas_object_smart_member_cache_invalidate(Evas_Object *obj);
 void evas_text_style_pad_get(Evas_Text_Style_Type style, int *l, int *r, int *t, int *b);