From 62ae9cd271f12823d0bbcb882c1655d5f27112d9 Mon Sep 17 00:00:00 2001 From: tasn Date: Mon, 1 Aug 2011 08:20:52 +0000 Subject: [PATCH] Evas font+textblock: Stopped using FcNameParse, parse ourselves. 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 | 313 ++++++++++++++++++++++++++------- src/lib/canvas/evas_object_text.c | 37 ++-- src/lib/canvas/evas_object_textblock.c | 192 +++++--------------- src/lib/include/evas_private.h | 70 +++++++- 4 files changed, 390 insertions(+), 222 deletions(-) diff --git a/src/lib/canvas/evas_font_dir.c b/src/lib/canvas/evas_font_dir.c index 0a248cc..e07dc9d 100644 --- a/src/lib/canvas/evas_font_dir.c +++ b/src/lib/canvas/evas_font_dir.c @@ -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; diff --git a/src/lib/canvas/evas_object_text.c b/src/lib/canvas/evas_object_text.c index 48b0193..cd0511d 100644 --- a/src/lib/canvas/evas_object_text.c +++ b/src/lib/canvas/evas_object_text.c @@ -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 diff --git a/src/lib/canvas/evas_object_textblock.c b/src/lib/canvas/evas_object_textblock.c index f2c97f9..a686321 100644 --- a/src/lib/canvas/evas_object_textblock.c +++ b/src/lib/canvas/evas_object_textblock.c @@ -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) { diff --git a/src/lib/include/evas_private.h b/src/lib/include/evas_private.h index 768d7d2..77b41fd 100644 --- a/src/lib/include/evas_private.h +++ b/src/lib/include/evas_private.h @@ -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); -- 2.7.4