forked from enlightenment/efl
evas_object_textblock: add support for variation sequences
Summary: update font processing to handle variation sequences unicodes to select proper glypg in respect to variation seqences Test Plan: ``` #define EFL_EO_API_SUPPORT 1 #define EFL_BETA_API_SUPPORT 1 #include <Eina.h> #include <Efl.h> #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win, *textblock; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("Main", ""); elm_win_autodel_set(win, EINA_TRUE); textblock = evas_object_textblock_add(win); efl_canvas_text_style_set(textblock,NULL,"DEFAULT='font=DejaVuSans font_fallbacks=SamsungColorEmoji color=#000 font_size=20'"); evas_object_textblock_text_markup_set(textblock, "8️⃣☪️AAA☪︎1234567️⃣"); evas_object_size_hint_weight_set(textblock, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(textblock, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(textblock); evas_object_move(textblock, 0, 0); evas_object_resize(textblock, 320, 320); evas_object_resize(win, 320, 320); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: woohyun, bowonryu, segfaultxavi, cedric, bu5hm4n Reviewed By: woohyun, cedric Subscribers: raster, bu5hm4n, subodh6129, herdsman, segfaultxavi, zmike, cedric, #committers, #reviewers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9053
This commit is contained in:
parent
c62a7dae63
commit
2d76224918
|
@ -244,6 +244,7 @@ void test_textblock_fit(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_label_ellipsis(void *data, Evas_Object *obj, void *event_info);
|
void test_label_ellipsis(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_label_colors(void *data, Evas_Object *obj, void *event_info);
|
void test_label_colors(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_label_emoji(void *data, Evas_Object *obj, void *event_info);
|
void test_label_emoji(void *data, Evas_Object *obj, void *event_info);
|
||||||
|
void test_label_variation_sequence(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_conformant(void *data, Evas_Object *obj, void *event_info);
|
void test_conformant(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_conformant2(void *data, Evas_Object *obj, void *event_info);
|
void test_conformant2(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_conformant_indicator(void *data, Evas_Object *obj, void *event_info);
|
void test_conformant_indicator(void *data, Evas_Object *obj, void *event_info);
|
||||||
|
@ -1211,6 +1212,7 @@ add_tests:
|
||||||
ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis);
|
ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis);
|
||||||
ADD_TEST(NULL, "Text", "Label Colors", test_label_colors);
|
ADD_TEST(NULL, "Text", "Label Colors", test_label_colors);
|
||||||
ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji);
|
ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji);
|
||||||
|
ADD_TEST(NULL, "Text", "Label Variation Sequnece", test_label_variation_sequence);
|
||||||
ADD_TEST_EO(NULL, "Text", "Efl.Ui.Textpath", test_ui_textpath);
|
ADD_TEST_EO(NULL, "Text", "Efl.Ui.Textpath", test_ui_textpath);
|
||||||
ADD_TEST_EO(NULL, "Text", "Efl.Canvas.Textblock style", test_canvas_textblock);
|
ADD_TEST_EO(NULL, "Text", "Efl.Canvas.Textblock style", test_canvas_textblock);
|
||||||
|
|
||||||
|
|
|
@ -635,6 +635,30 @@ test_label_colors(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *ev
|
||||||
evas_object_show(win);
|
evas_object_show(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** Label variation sequence **************************************************************/
|
||||||
|
void
|
||||||
|
test_label_variation_sequence(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Evas_Object *win, *lb;
|
||||||
|
|
||||||
|
win = elm_win_util_standard_add("label-variation sequence", "Label variation sequnece");
|
||||||
|
elm_win_autodel_set(win, EINA_TRUE);
|
||||||
|
|
||||||
|
lb = elm_label_add(win);
|
||||||
|
elm_object_text_set(lb,
|
||||||
|
"You need to have at least on font contains variation sequence<br>"
|
||||||
|
"Three different 8 glyphs : <br>"
|
||||||
|
"8<tab>8️<tab>8️⃣<br>"
|
||||||
|
"line with 3 variation glyphs : <br>"
|
||||||
|
"8️⃣☪️AAA☪︎1234567️⃣"
|
||||||
|
);
|
||||||
|
evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||||
|
elm_win_resize_object_add(win, lb);
|
||||||
|
evas_object_show(lb);
|
||||||
|
|
||||||
|
evas_object_show(win);
|
||||||
|
}
|
||||||
|
|
||||||
/*** Label Emoji *************************************************************/
|
/*** Label Emoji *************************************************************/
|
||||||
static char *
|
static char *
|
||||||
_fontlist_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
|
_fontlist_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
|
||||||
|
|
|
@ -56,7 +56,32 @@ typedef unsigned long long DATA64;
|
||||||
#define LKU(x) eina_lock_release(&(x))
|
#define LKU(x) eina_lock_release(&(x))
|
||||||
#define LKDBG(x) eina_lock_debug(&(x))
|
#define LKDBG(x) eina_lock_debug(&(x))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See explanation of variation_sequences at:
|
||||||
|
* https://unicode.org/Public/UCD/latest/ucd/StandardizedVariants.txt
|
||||||
|
* https://unicode.org/reports/tr37/
|
||||||
|
* https://unicode.org/ivd/
|
||||||
|
* https://www.freetype.org/freetype2/docs/reference/ft2-glyph_variants.html
|
||||||
|
*/
|
||||||
|
#define VAR_SEQ(x) GENERIC_VARIATION_SEQUENCES(x) | IDEOGRAPHICS_VARIATION_SEQUENCES(x) | MANGOLIAN_VARIATION_SEQUENCES(x)
|
||||||
|
#define GENERIC_VARIATION_SEQUENCES(x) (x>=0xFE00 && x<=0xFE0F) ? x : 0
|
||||||
|
#define IDEOGRAPHICS_VARIATION_SEQUENCES(x) (x>=0xE0100 && x<=0xE01EF) ? x : 0
|
||||||
|
#define MANGOLIAN_VARIATION_SEQUENCES(x) (x>=0x180B && x<=0x180D) ? x : 0
|
||||||
|
/**
|
||||||
|
* http://unicode.org/emoji/charts/emoji-variants.html
|
||||||
|
*/
|
||||||
|
#define VARIATION_EMOJI_PRESENTATION 0xFE0F
|
||||||
|
#define VARIATION_TEXT_PRESENTATION 0xFE0E
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These Options (Flags) are used with evas_common_font_glyph_search function
|
||||||
|
*/
|
||||||
|
#define EVAS_FONT_SEARCH_OPTION_NONE 0x0000
|
||||||
|
#define EVAS_FONT_SEARCH_OPTION_SKIP_COLOR 0x0001
|
||||||
|
|
||||||
|
|
||||||
|
#define FASH_INT_MAGIC 0x01012345
|
||||||
|
#define FASH_GLYPH_MAGIC 0x02012345
|
||||||
|
|
||||||
enum _Evas_Font_Style
|
enum _Evas_Font_Style
|
||||||
{
|
{
|
||||||
|
@ -128,6 +153,10 @@ typedef struct _RGBA_Font_Source RGBA_Font_Source;
|
||||||
typedef struct _RGBA_Font_Glyph RGBA_Font_Glyph;
|
typedef struct _RGBA_Font_Glyph RGBA_Font_Glyph;
|
||||||
typedef struct _RGBA_Font_Glyph_Out RGBA_Font_Glyph_Out;
|
typedef struct _RGBA_Font_Glyph_Out RGBA_Font_Glyph_Out;
|
||||||
|
|
||||||
|
typedef struct _Fash_Item_variation_Index_Item Fash_Item_variation_Index_Item;
|
||||||
|
typedef struct _Fash_Item_variation_List Fash_Item_variation_List;
|
||||||
|
typedef struct _Fash_Item_Index_Map_Variations Fash_Item_Index_Map_Variations;
|
||||||
|
|
||||||
typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map;
|
typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map;
|
||||||
typedef struct _Fash_Int_Map Fash_Int_Map;
|
typedef struct _Fash_Int_Map Fash_Int_Map;
|
||||||
typedef struct _Fash_Int_Map2 Fash_Int_Map2;
|
typedef struct _Fash_Int_Map2 Fash_Int_Map2;
|
||||||
|
@ -139,9 +168,25 @@ struct _Fash_Item_Index_Map
|
||||||
RGBA_Font_Int *fint;
|
RGBA_Font_Int *fint;
|
||||||
int index;
|
int index;
|
||||||
};
|
};
|
||||||
|
struct _Fash_Item_variation_Index_Item
|
||||||
|
{
|
||||||
|
Fash_Item_Index_Map item;
|
||||||
|
Eina_Unicode variation_sequence;
|
||||||
|
};
|
||||||
|
struct _Fash_Item_variation_List
|
||||||
|
{
|
||||||
|
Fash_Item_variation_Index_Item *list;
|
||||||
|
size_t length;
|
||||||
|
size_t capacity;
|
||||||
|
};
|
||||||
|
struct _Fash_Item_Index_Map_Variations
|
||||||
|
{
|
||||||
|
Fash_Item_Index_Map item;
|
||||||
|
Fash_Item_variation_List *variations;
|
||||||
|
};
|
||||||
struct _Fash_Int_Map
|
struct _Fash_Int_Map
|
||||||
{
|
{
|
||||||
Fash_Item_Index_Map item[256];
|
Fash_Item_Index_Map_Variations items[256];
|
||||||
};
|
};
|
||||||
struct _Fash_Int_Map2
|
struct _Fash_Int_Map2
|
||||||
{
|
{
|
||||||
|
@ -149,6 +194,7 @@ struct _Fash_Int_Map2
|
||||||
};
|
};
|
||||||
struct _Fash_Int
|
struct _Fash_Int
|
||||||
{
|
{
|
||||||
|
unsigned int MAGIC;
|
||||||
Fash_Int_Map2 *bucket[256];
|
Fash_Int_Map2 *bucket[256];
|
||||||
void (*freeme) (Fash_Int *fash);
|
void (*freeme) (Fash_Int *fash);
|
||||||
};
|
};
|
||||||
|
@ -166,6 +212,7 @@ struct _Fash_Glyph_Map2
|
||||||
};
|
};
|
||||||
struct _Fash_Glyph
|
struct _Fash_Glyph
|
||||||
{
|
{
|
||||||
|
unsigned int MAGIC;
|
||||||
Fash_Glyph_Map2 *bucket[256];
|
Fash_Glyph_Map2 *bucket[256];
|
||||||
void (*freeme) (Fash_Glyph *fash);
|
void (*freeme) (Fash_Glyph *fash);
|
||||||
};
|
};
|
||||||
|
@ -347,7 +394,7 @@ void *evas_common_font_freetype_face_get(RGBA_Font *font); /* XXX: Not EAPI on p
|
||||||
|
|
||||||
EAPI RGBA_Font_Glyph *evas_common_font_int_cache_glyph_get (RGBA_Font_Int *fi, FT_UInt index);
|
EAPI RGBA_Font_Glyph *evas_common_font_int_cache_glyph_get (RGBA_Font_Int *fi, FT_UInt index);
|
||||||
EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg);
|
EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg);
|
||||||
EAPI FT_UInt evas_common_get_char_index (RGBA_Font_Int* fi, Eina_Unicode gl);
|
EAPI FT_UInt evas_common_get_char_index (RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode variation_sequence);
|
||||||
|
|
||||||
/* load */
|
/* load */
|
||||||
EAPI void evas_common_font_dpi_set (int dpi_h, int dpi_v);
|
EAPI void evas_common_font_dpi_set (int dpi_h, int dpi_v);
|
||||||
|
@ -397,7 +444,7 @@ EAPI void evas_common_font_ascent_descent_get(RGBA_Font *fn, const
|
||||||
|
|
||||||
EAPI void *evas_common_font_glyph_compress(void *data, int num_grays, int pixel_mode, int pitch_data, int w, int h, int *size_ret);
|
EAPI void *evas_common_font_glyph_compress(void *data, int num_grays, int pixel_mode, int pitch_data, int w, int h, int *size_ret);
|
||||||
EAPI DATA8 *evas_common_font_glyph_uncompress(RGBA_Font_Glyph *fg, int *wret, int *hret);
|
EAPI DATA8 *evas_common_font_glyph_uncompress(RGBA_Font_Glyph *fg, int *wret, int *hret);
|
||||||
EAPI int evas_common_font_glyph_search (RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl);
|
EAPI int evas_common_font_glyph_search (RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl, Eina_Unicode variation_sequence, uint32_t evas_font_search_options);
|
||||||
|
|
||||||
void evas_common_font_load_init(void);
|
void evas_common_font_load_init(void);
|
||||||
void evas_common_font_load_shutdown(void);
|
void evas_common_font_load_shutdown(void);
|
||||||
|
|
|
@ -687,7 +687,11 @@ evas_common_font_free(RGBA_Font *fn)
|
||||||
evas_common_font_int_unref(fi);
|
evas_common_font_int_unref(fi);
|
||||||
evas_common_font_flush();
|
evas_common_font_flush();
|
||||||
eina_list_free(fn->fonts);
|
eina_list_free(fn->fonts);
|
||||||
if (fn->fash) fn->fash->freeme(fn->fash);
|
if (fn->fash)
|
||||||
|
{
|
||||||
|
fn->fash->freeme(fn->fash);
|
||||||
|
fn->fash = NULL;
|
||||||
|
}
|
||||||
LKD(fn->lock);
|
LKD(fn->lock);
|
||||||
free(fn);
|
free(fn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,33 +355,182 @@ end:
|
||||||
/* Set of common functions that are used in a couple of places. */
|
/* Set of common functions that are used in a couple of places. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_fash_int2_free(Fash_Int_Map2 *fash)
|
_fash_int_map_and_variations_free(Fash_Int_Map *map)
|
||||||
{
|
{
|
||||||
|
if(!map)
|
||||||
|
return;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]);
|
for (i = 0; i < 256; i++)
|
||||||
free(fash);
|
{
|
||||||
|
if (map->items[i].variations)
|
||||||
|
{
|
||||||
|
if (map->items[i].variations->list)
|
||||||
|
{
|
||||||
|
free(map->items[i].variations->list);
|
||||||
|
map->items[i].variations->list = NULL;
|
||||||
|
map->items[i].variations->capacity = 0;
|
||||||
|
map->items[i].variations->length = 0;
|
||||||
|
}
|
||||||
|
free(map->items[i].variations);
|
||||||
|
map->items[i].variations = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_fash_int2_free(Fash_Int_Map2 *fash)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (fash)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
if (fash->bucket[i])
|
||||||
|
{
|
||||||
|
_fash_int_map_and_variations_free(fash->bucket[i]);
|
||||||
|
fash->bucket[i] = NULL;
|
||||||
|
}
|
||||||
|
free(fash);
|
||||||
|
fash = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_fash_int_free(Fash_Int *fash)
|
_fash_int_free(Fash_Int *fash)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
if (fash)
|
||||||
|
{
|
||||||
|
if (fash->MAGIC != FASH_INT_MAGIC)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_int2_free(fash->bucket[i]);
|
for (i = 0; i < 256; i++)
|
||||||
free(fash);
|
{
|
||||||
|
if (fash->bucket[i])
|
||||||
|
{
|
||||||
|
_fash_int2_free(fash->bucket[i]);
|
||||||
|
fash->bucket[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(fash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Fash_Int *
|
static Fash_Int *
|
||||||
_fash_int_new(void)
|
_fash_int_new(void)
|
||||||
{
|
{
|
||||||
Fash_Int *fash = calloc(1, sizeof(Fash_Int));
|
Fash_Int *fash = calloc(1, sizeof(Fash_Int));
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
|
||||||
|
fash->MAGIC = FASH_INT_MAGIC;
|
||||||
fash->freeme = _fash_int_free;
|
fash->freeme = _fash_int_free;
|
||||||
return fash;
|
return fash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Fash_Item_variation_List *
|
||||||
|
_variations_list_new(void)
|
||||||
|
{
|
||||||
|
Fash_Item_variation_List *variations = calloc(1, sizeof(Fash_Item_variation_List));
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(variations, NULL);
|
||||||
|
variations->capacity = 0;
|
||||||
|
variations->length = 0;
|
||||||
|
variations->list = 0;
|
||||||
|
return variations;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_variations_list_add(Fash_Item_variation_List *variations,RGBA_Font_Int *fint, int index, Eina_Unicode variation_sequence)
|
||||||
|
{
|
||||||
|
Fash_Item_variation_Index_Item *list = variations->list;
|
||||||
|
if (variations->capacity == variations->length)
|
||||||
|
{
|
||||||
|
list = (Fash_Item_variation_Index_Item *) realloc(list, (variations->capacity + 4) * sizeof(Fash_Item_variation_Index_Item));
|
||||||
|
if (list)
|
||||||
|
{
|
||||||
|
variations->list = list;
|
||||||
|
variations->capacity += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(list);
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
int end = variations->length;
|
||||||
|
if (end == 0)
|
||||||
|
{
|
||||||
|
// if only on element just add it in 0 index
|
||||||
|
variations->list[0].item.fint = fint;
|
||||||
|
variations->list[0].item.index = index;
|
||||||
|
variations->list[0].variation_sequence = variation_sequence;
|
||||||
|
variations->length++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// find lower bound
|
||||||
|
while (end > start)
|
||||||
|
{
|
||||||
|
int middle = start + (end - start) / 2;
|
||||||
|
if (variations->list[middle].variation_sequence >= variation_sequence)
|
||||||
|
end = middle;
|
||||||
|
else
|
||||||
|
start = middle + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if passed value founded in list, just replace it
|
||||||
|
if (start < (int)variations->length && variations->list[start].variation_sequence == variation_sequence)
|
||||||
|
{
|
||||||
|
variations->list[start].item.fint = fint;
|
||||||
|
variations->list[start].item.index = index;
|
||||||
|
variations->list[start].variation_sequence = variation_sequence;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift array to insert item
|
||||||
|
for (int i = (variations->length - 1) ; i >= start; i--)
|
||||||
|
{
|
||||||
|
variations->list[i + 1] = variations->list[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert new item and keep array sorted
|
||||||
|
variations->list[start].item.fint = fint;
|
||||||
|
variations->list[start].item.index = index;
|
||||||
|
variations->list[start].variation_sequence = variation_sequence;
|
||||||
|
variations->length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Fash_Item_Index_Map *
|
static Fash_Item_Index_Map *
|
||||||
_fash_int_find(Fash_Int *fash, int item)
|
_variations_list_find(Fash_Item_variation_List * variations, Eina_Unicode variation_sequence)
|
||||||
|
{
|
||||||
|
if (!variations)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!variations->list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
int end = variations->length;
|
||||||
|
|
||||||
|
while(end > start)
|
||||||
|
{
|
||||||
|
int middle = start + (end - start) / 2;
|
||||||
|
if (variations->list[middle].variation_sequence == variation_sequence)
|
||||||
|
return &(variations->list[middle].item);
|
||||||
|
else if (variations->list[middle].variation_sequence < variation_sequence)
|
||||||
|
start = middle + 1;
|
||||||
|
else
|
||||||
|
end = middle - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Fash_Item_Index_Map *
|
||||||
|
_fash_int_find(Fash_Int *fash, int item, Eina_Unicode variation_sequence)
|
||||||
{
|
{
|
||||||
int grp, maj, min;
|
int grp, maj, min;
|
||||||
|
|
||||||
|
@ -391,14 +540,22 @@ _fash_int_find(Fash_Int *fash, int item)
|
||||||
min = item & 0xff;
|
min = item & 0xff;
|
||||||
if (!fash->bucket[grp]) return NULL;
|
if (!fash->bucket[grp]) return NULL;
|
||||||
if (!fash->bucket[grp]->bucket[maj]) return NULL;
|
if (!fash->bucket[grp]->bucket[maj]) return NULL;
|
||||||
return &(fash->bucket[grp]->bucket[maj]->item[min]);
|
if (!variation_sequence)
|
||||||
|
return &(fash->bucket[grp]->bucket[maj]->items[min].item);
|
||||||
|
else
|
||||||
|
return _variations_list_find(fash->bucket[grp]->bucket[maj]->items[min].variations, variation_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx)
|
_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx, Eina_Unicode variation_sequence)
|
||||||
{
|
{
|
||||||
int grp, maj, min;
|
int grp, maj, min;
|
||||||
|
|
||||||
|
// If we already have cached passed item, skip adding it again
|
||||||
|
const Fash_Item_Index_Map *fm = _fash_int_find(fash, item, variation_sequence);
|
||||||
|
if (fm && fm->fint)
|
||||||
|
return;
|
||||||
|
|
||||||
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
|
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
|
||||||
grp = (item >> 16) & 0xff;
|
grp = (item >> 16) & 0xff;
|
||||||
maj = (item >> 8) & 0xff;
|
maj = (item >> 8) & 0xff;
|
||||||
|
@ -409,8 +566,20 @@ _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx)
|
||||||
if (!fash->bucket[grp]->bucket[maj])
|
if (!fash->bucket[grp]->bucket[maj])
|
||||||
fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
|
fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
|
||||||
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
|
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
|
||||||
fash->bucket[grp]->bucket[maj]->item[min].fint = fint;
|
if (variation_sequence)
|
||||||
fash->bucket[grp]->bucket[maj]->item[min].index = idx;
|
{
|
||||||
|
if (!fash->bucket[grp]->bucket[maj]->items[min].variations)
|
||||||
|
{
|
||||||
|
fash->bucket[grp]->bucket[maj]->items[min].variations =_variations_list_new();
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]->items[min].variations);
|
||||||
|
}
|
||||||
|
_variations_list_add(fash->bucket[grp]->bucket[maj]->items[min].variations, fint, idx, variation_sequence);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fash->bucket[grp]->bucket[maj]->items[min].item.fint = fint;
|
||||||
|
fash->bucket[grp]->bucket[maj]->items[min].item.index = idx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -462,24 +631,45 @@ _fash_gl2_free(Fash_Glyph_Map2 *fash)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
|
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
|
||||||
for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_glyph_free(fash->bucket[i]);
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
if (fash->bucket[i])
|
||||||
|
{
|
||||||
|
_fash_glyph_free(fash->bucket[i]);
|
||||||
|
fash->bucket[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
free(fash);
|
free(fash);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_fash_gl_free(Fash_Glyph *fash)
|
_fash_gl_free(Fash_Glyph *fash)
|
||||||
{
|
{
|
||||||
int i;
|
if (fash)
|
||||||
|
{
|
||||||
|
if (fash->MAGIC != FASH_GLYPH_MAGIC)
|
||||||
|
return;
|
||||||
|
|
||||||
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
|
int i;
|
||||||
for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_gl2_free(fash->bucket[i]);
|
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
|
||||||
free(fash);
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
if (fash->bucket[i])
|
||||||
|
{
|
||||||
|
_fash_gl2_free(fash->bucket[i]);
|
||||||
|
fash->bucket[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(fash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Fash_Glyph *
|
static Fash_Glyph *
|
||||||
_fash_gl_new(void)
|
_fash_gl_new(void)
|
||||||
{
|
{
|
||||||
Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
|
Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
|
||||||
|
fash->MAGIC = FASH_GLYPH_MAGIC;
|
||||||
fash->freeme = _fash_gl_free;
|
fash->freeme = _fash_gl_free;
|
||||||
return fash;
|
return fash;
|
||||||
}
|
}
|
||||||
|
@ -680,7 +870,7 @@ struct _Font_Char_Index
|
||||||
};
|
};
|
||||||
|
|
||||||
EAPI FT_UInt
|
EAPI FT_UInt
|
||||||
evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
|
evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode variation_sequence)
|
||||||
{
|
{
|
||||||
static const unsigned short mapfix[] =
|
static const unsigned short mapfix[] =
|
||||||
{
|
{
|
||||||
|
@ -742,7 +932,10 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
|
||||||
* that something else try to use it.
|
* that something else try to use it.
|
||||||
*/
|
*/
|
||||||
/* FTLOCK(); */
|
/* FTLOCK(); */
|
||||||
result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
|
if (variation_sequence)
|
||||||
|
result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
|
||||||
|
else
|
||||||
|
result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
|
||||||
/* FTUNLOCK(); */
|
/* FTUNLOCK(); */
|
||||||
result.gl = gl;
|
result.gl = gl;
|
||||||
|
|
||||||
|
@ -774,7 +967,10 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
|
||||||
{
|
{
|
||||||
gl = mapfix[(i << 1) + 1];
|
gl = mapfix[(i << 1) + 1];
|
||||||
FTLOCK();
|
FTLOCK();
|
||||||
result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
|
if (variation_sequence)
|
||||||
|
result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
|
||||||
|
else
|
||||||
|
result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
|
||||||
FTUNLOCK();
|
FTUNLOCK();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -799,20 +995,49 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
|
||||||
return result.index;
|
return result.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @internal
|
||||||
|
* Search for unicode glyph inside all font files, and return font and glyph index
|
||||||
|
*
|
||||||
|
* @param[in] fn the font to use.
|
||||||
|
* @param[out] fi_ret founded font.
|
||||||
|
* @param[in] gl unicode glyph to search for
|
||||||
|
* @param[in] variation_sequence for the gl glyph
|
||||||
|
* @param[in] evas_font_search_options search options when searching font files
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
EAPI int
|
EAPI int
|
||||||
evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl)
|
evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl, Eina_Unicode variation_sequence, uint32_t evas_font_search_options)
|
||||||
{
|
{
|
||||||
Eina_List *l;
|
Eina_List *l;
|
||||||
|
|
||||||
if (fn->fash)
|
if (fn->fash)
|
||||||
{
|
{
|
||||||
Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl);
|
const Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl, variation_sequence);
|
||||||
if (fm)
|
if (fm)
|
||||||
{
|
{
|
||||||
if (fm->fint)
|
if (fm->fint)
|
||||||
{
|
{
|
||||||
*fi_ret = fm->fint;
|
if (evas_font_search_options == EVAS_FONT_SEARCH_OPTION_NONE)
|
||||||
return fm->index;
|
{
|
||||||
|
*fi_ret = fm->fint;
|
||||||
|
return fm->index;
|
||||||
|
}
|
||||||
|
else if( (evas_font_search_options & EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR)
|
||||||
|
{
|
||||||
|
if (!fm->fint->src->ft.face)
|
||||||
|
{
|
||||||
|
evas_common_font_int_reload(fm->fint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fm->fint->src->ft.face && !FT_HAS_COLOR(fm->fint->src->ft.face))
|
||||||
|
{
|
||||||
|
*fi_ret = fm->fint;
|
||||||
|
return fm->index;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (fm->index == -1) return 0;
|
else if (fm->index == -1) return 0;
|
||||||
}
|
}
|
||||||
|
@ -851,20 +1076,35 @@ evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicod
|
||||||
}
|
}
|
||||||
if (fi->src->ft.face)
|
if (fi->src->ft.face)
|
||||||
{
|
{
|
||||||
idx = evas_common_get_char_index(fi, gl);
|
Eina_Bool is_color_only = (evas_font_search_options & EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR &&
|
||||||
|
FT_HAS_COLOR(fi->src->ft.face);
|
||||||
|
|
||||||
|
if (is_color_only)
|
||||||
|
{
|
||||||
|
/* This is color font ignore it */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = (int) evas_common_get_char_index(fi, gl, variation_sequence);
|
||||||
if (idx != 0)
|
if (idx != 0)
|
||||||
{
|
{
|
||||||
if (!fi->ft.size)
|
if (!fi->ft.size)
|
||||||
evas_common_font_int_load_complete(fi);
|
evas_common_font_int_load_complete(fi);
|
||||||
if (!fn->fash) fn->fash = _fash_int_new();
|
if (!is_color_only)
|
||||||
if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx);
|
{
|
||||||
|
if (!fn->fash) fn->fash = _fash_int_new();
|
||||||
|
if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx, variation_sequence);
|
||||||
|
}
|
||||||
*fi_ret = fi;
|
*fi_ret = fi;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!fn->fash) fn->fash = _fash_int_new();
|
if (!is_color_only)
|
||||||
if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1);
|
{
|
||||||
|
if (!fn->fash) fn->fash = _fash_int_new();
|
||||||
|
if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1, variation_sequence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "evas_font_private.h" /* for Frame-Queuing support */
|
#include "evas_font_private.h" /* for Frame-Queuing support */
|
||||||
|
|
||||||
|
#define VAR_SEQ_SAFE(x) (((x)<run_end) ? VAR_SEQ(*(x)) : 0)
|
||||||
|
|
||||||
/* FIXME: Check coverage according to the font and not by actually loading */
|
/* FIXME: Check coverage according to the font and not by actually loading */
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +33,9 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
(evas_common_language_char_script_get(*base_char) != script) ;
|
(evas_common_language_char_script_get(*base_char) != script) ;
|
||||||
base_char++)
|
base_char++)
|
||||||
;
|
;
|
||||||
|
/* If counter reach variation sequence it is safe to pick default font */
|
||||||
|
if(VAR_SEQ_SAFE(base_char) || (base_char != run_end && VAR_SEQ_SAFE((base_char+1)))) goto get_top_font;
|
||||||
|
|
||||||
if (base_char == run_end) base_char = text;
|
if (base_char == run_end) base_char = text;
|
||||||
|
|
||||||
/* Find the first renderable char */
|
/* Find the first renderable char */
|
||||||
|
@ -40,7 +44,7 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
/* 0x1F is the last ASCII contral char, just a hack in
|
/* 0x1F is the last ASCII contral char, just a hack in
|
||||||
* the meanwhile. */
|
* the meanwhile. */
|
||||||
if ((*base_char > 0x1F) &&
|
if ((*base_char > 0x1F) &&
|
||||||
evas_common_font_glyph_search(fn, &fi, *base_char))
|
evas_common_font_glyph_search(fn, &fi, *base_char, 0, EVAS_FONT_SEARCH_OPTION_NONE))
|
||||||
break;
|
break;
|
||||||
base_char++;
|
base_char++;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +53,8 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
/* If everything else fails, at least try to find a font for the
|
/* If everything else fails, at least try to find a font for the
|
||||||
* replacement char */
|
* replacement char */
|
||||||
if (base_char == run_end)
|
if (base_char == run_end)
|
||||||
evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
|
evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR, 0, EVAS_FONT_SEARCH_OPTION_NONE);
|
||||||
|
get_top_font:
|
||||||
|
|
||||||
if (!fi)
|
if (!fi)
|
||||||
fi = fn->fonts->data;
|
fi = fn->fonts->data;
|
||||||
|
@ -80,15 +85,17 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
if (evas_common_language_char_script_get(*itr) == EVAS_SCRIPT_INHERITED)
|
if (evas_common_language_char_script_get(*itr) == EVAS_SCRIPT_INHERITED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Eina_Unicode variation_sequence = VAR_SEQ_SAFE(itr+1);
|
||||||
|
|
||||||
/* Break if either it's not in the font, or if it is in the
|
/* Break if either it's not in the font, or if it is in the
|
||||||
* script's font. */
|
* script's font. */
|
||||||
if (!evas_common_get_char_index(fi, *itr))
|
if (!evas_common_get_char_index(fi, *itr, variation_sequence))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (fi != *script_fi)
|
if (fi != *script_fi)
|
||||||
{
|
{
|
||||||
if (evas_common_get_char_index(*script_fi, *itr))
|
if (evas_common_get_char_index(*script_fi, *itr, variation_sequence))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +109,25 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
/* If we can find a font, use it. Otherwise, find the first
|
/* 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
|
* char the run of chars that can't be rendered until the first
|
||||||
* one that can. */
|
* one that can. */
|
||||||
if (evas_common_font_glyph_search(fn, &tmp_fi, *itr))
|
Eina_Unicode variation_sequence = VAR_SEQ_SAFE(itr+1);
|
||||||
|
if (evas_common_font_glyph_search(fn, &tmp_fi, *itr, variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE))
|
||||||
{
|
{
|
||||||
fi = tmp_fi;
|
fi = tmp_fi;
|
||||||
}
|
}
|
||||||
|
else if ( (variation_sequence == VARIATION_TEXT_PRESENTATION) && evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_SKIP_COLOR))
|
||||||
|
{
|
||||||
|
/* If we can not find unicode with variation sequence, then we will
|
||||||
|
Search and find for non color glyph because variation sequence is Text
|
||||||
|
*/
|
||||||
|
fi = tmp_fi;
|
||||||
|
}
|
||||||
|
else if ( variation_sequence && evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_NONE))
|
||||||
|
{
|
||||||
|
/* If we can not find unicode with variation sequence, then we will
|
||||||
|
Search and find glyph without the variation sequence
|
||||||
|
*/
|
||||||
|
fi = tmp_fi;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itr++;
|
itr++;
|
||||||
|
@ -113,9 +135,13 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
* font */
|
* font */
|
||||||
for ( ; itr < run_end ; itr++)
|
for ( ; itr < run_end ; itr++)
|
||||||
{
|
{
|
||||||
|
if(VAR_SEQ_SAFE(itr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Eina_Unicode variation_sequence = VAR_SEQ_SAFE(itr+1);
|
||||||
tmp_fi = fi;
|
tmp_fi = fi;
|
||||||
if (evas_common_get_char_index(fi, *itr) ||
|
if (evas_common_get_char_index(fi, *itr, variation_sequence) ||
|
||||||
evas_common_font_glyph_search(fn, &tmp_fi, *itr))
|
evas_common_font_glyph_search(fn, &tmp_fi, *itr, variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE))
|
||||||
{
|
{
|
||||||
fi = tmp_fi;
|
fi = tmp_fi;
|
||||||
break;
|
break;
|
||||||
|
@ -127,9 +153,9 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
* find a font most suitable for the replacement char and
|
* find a font most suitable for the replacement char and
|
||||||
* break */
|
* break */
|
||||||
if ((itr == run_end) ||
|
if ((itr == run_end) ||
|
||||||
!evas_common_get_char_index(fi, REPLACEMENT_CHAR))
|
!evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0))
|
||||||
{
|
{
|
||||||
evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
|
evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR, 0, EVAS_FONT_SEARCH_OPTION_NONE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,8 +166,11 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
|
||||||
/* If this char is not renderable by any font, but the replacement
|
/* If this char is not renderable by any font, but the replacement
|
||||||
* char can be rendered using the currentfont, continue this
|
* char can be rendered using the currentfont, continue this
|
||||||
* run. */
|
* run. */
|
||||||
if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) &&
|
Eina_Unicode variation_sequence = VAR_SEQ_SAFE(itr+1);
|
||||||
evas_common_get_char_index(fi, REPLACEMENT_CHAR))
|
|
||||||
|
if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr, variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE) &&
|
||||||
|
(variation_sequence ? !evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_NONE) : 1) &&
|
||||||
|
evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0))
|
||||||
{
|
{
|
||||||
itr++;
|
itr++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1066,7 +1066,7 @@ _content_create_ot(RGBA_Font_Int *fi, const Eina_Unicode *text,
|
||||||
/* If we got a malformed index, show the replacement char instead */
|
/* If we got a malformed index, show the replacement char instead */
|
||||||
if (gl_itr->index == 0)
|
if (gl_itr->index == 0)
|
||||||
{
|
{
|
||||||
gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR);
|
gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0);
|
||||||
is_replacement = EINA_TRUE;
|
is_replacement = EINA_TRUE;
|
||||||
}
|
}
|
||||||
idx = gl_itr->index;
|
idx = gl_itr->index;
|
||||||
|
@ -1172,10 +1172,10 @@ _content_create_regular(RGBA_Font_Int *fi, const Eina_Unicode *text,
|
||||||
_gl = *text;
|
_gl = *text;
|
||||||
if (_gl == 0) break;
|
if (_gl == 0) break;
|
||||||
|
|
||||||
idx = evas_common_get_char_index(fi, _gl);
|
idx = evas_common_get_char_index(fi, _gl, 0);
|
||||||
if (idx == 0)
|
if (idx == 0)
|
||||||
{
|
{
|
||||||
idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR);
|
idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fg = evas_common_font_int_cache_glyph_get(fi, idx);
|
fg = evas_common_font_int_cache_glyph_get(fi, idx);
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
|
||||||
|
#include <Evas.h>
|
||||||
|
#include <Evas_Engine_Buffer.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Convenience routine to allocate and initialize the canvas.
|
||||||
|
* In a real application we'd be using ecore_evas_buffer_new() instead.
|
||||||
|
*/
|
||||||
|
Evas *canvas_create(int width, int height)
|
||||||
|
{
|
||||||
|
Evas *canvas;
|
||||||
|
Evas_Engine_Info_Buffer *einfo;
|
||||||
|
int method;
|
||||||
|
void *pixels;
|
||||||
|
|
||||||
|
/* Request a handle for the 'buffer' type of rendering engine. */
|
||||||
|
method = evas_render_method_lookup("buffer");
|
||||||
|
if (method <= 0)
|
||||||
|
{
|
||||||
|
fputs("ERROR: evas was not compiled with 'buffer' engine!\n", stderr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a general canvas object.
|
||||||
|
* Note that we are responsible for freeing the canvas when we're done. */
|
||||||
|
canvas = evas_new();
|
||||||
|
if (!canvas)
|
||||||
|
{
|
||||||
|
fputs("ERROR: could not instantiate new evas canvas.\n", stderr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specify that the canvas will be rendering using the buffer engine method.
|
||||||
|
* We also size the canvas and viewport to the same width and height, with
|
||||||
|
* the viewport set to the origin of the canvas.
|
||||||
|
*/
|
||||||
|
evas_output_method_set(canvas, method);
|
||||||
|
evas_output_size_set(canvas, width, height);
|
||||||
|
evas_output_viewport_set(canvas, 0, 0, width, height);
|
||||||
|
|
||||||
|
/* Before we can use the engine, we *must* set its configuration
|
||||||
|
* parameters. The available parameters are kept in a struct
|
||||||
|
* named Evas_Engine_Info which is internal to Evas. Thus to set
|
||||||
|
* parameters we must first request the current info object from
|
||||||
|
* our canvas:
|
||||||
|
*/
|
||||||
|
einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
|
||||||
|
if (!einfo)
|
||||||
|
{
|
||||||
|
fputs("ERROR: could not get evas engine info!\n", stderr);
|
||||||
|
evas_free(canvas);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the underlying data buffer that our canvas will use. This
|
||||||
|
* is a simple array of ARGB32 pixels. Each color component
|
||||||
|
* (including alpha) is one byte, resulting in 4 bytes per pixel (or
|
||||||
|
* 32 bits). We can thus store each pixel in an integer data type,
|
||||||
|
* thus calculating our data buffer as W x H x sizeof(int) bytes in
|
||||||
|
* length.
|
||||||
|
*/
|
||||||
|
pixels = malloc(width * height * sizeof(int));
|
||||||
|
if (!pixels)
|
||||||
|
{
|
||||||
|
fputs("ERROR: could not allocate canvas pixels!\n", stderr);
|
||||||
|
evas_free(canvas);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next set the various configuration parameters. We
|
||||||
|
* register the pixel buffer that the canvas will use,
|
||||||
|
* indicate the pixel format as ARGB32, and the size of
|
||||||
|
* each row of data. */
|
||||||
|
einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
|
||||||
|
einfo->info.dest_buffer = pixels;
|
||||||
|
einfo->info.dest_buffer_row_bytes = width * sizeof(int);
|
||||||
|
einfo->info.use_color_key = 0;
|
||||||
|
einfo->info.alpha_threshold = 0;
|
||||||
|
einfo->info.func.new_update_region = NULL;
|
||||||
|
einfo->info.func.free_update_region = NULL;
|
||||||
|
|
||||||
|
/* Finally, we configure the canvas with our chosen parameters. */
|
||||||
|
evas_engine_info_set(canvas, (Evas_Engine_Info *)einfo);
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convenience routine to shut down the canvas.
|
||||||
|
* In a real application we'd be using ecore_evas_free() instead
|
||||||
|
*/
|
||||||
|
void canvas_destroy(Evas *canvas)
|
||||||
|
{
|
||||||
|
Evas_Engine_Info_Buffer *einfo;
|
||||||
|
|
||||||
|
einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
|
||||||
|
if (!einfo)
|
||||||
|
{
|
||||||
|
fputs("ERROR: could not get evas engine info!\n", stderr);
|
||||||
|
evas_free(canvas);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the data buffer we allocated in create_buffer() */
|
||||||
|
free(einfo->info.dest_buffer);
|
||||||
|
|
||||||
|
/* Finally, free the canvas itself. */
|
||||||
|
evas_free(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return internal buffer address
|
||||||
|
*/
|
||||||
|
void* canvas_buffer(Evas *canvas)
|
||||||
|
{
|
||||||
|
Evas_Engine_Info_Buffer *einfo;
|
||||||
|
einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
|
||||||
|
if (!einfo)
|
||||||
|
{
|
||||||
|
fputs("ERROR: could not get evas engine info!\n", stderr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return einfo->info.dest_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convenience routine to update the scene.
|
||||||
|
* In a real application Ecore Evas would be doing this for us.
|
||||||
|
*/
|
||||||
|
void canvas_draw(Evas *canvas)
|
||||||
|
{
|
||||||
|
Eina_List *updates, *n;
|
||||||
|
Eina_Rectangle *update;
|
||||||
|
|
||||||
|
/* Render the canvas, and get a list of the updated rectangles. */
|
||||||
|
updates = evas_render_updates(canvas);
|
||||||
|
|
||||||
|
/* Just for informative purposes, print out the areas being updated: */
|
||||||
|
EINA_LIST_FOREACH(updates, n, update)
|
||||||
|
printf("UPDATED REGION: pos: %3d, %3d size: %3dx%3d\n",
|
||||||
|
update->x, update->y, update->w, update->h);
|
||||||
|
|
||||||
|
/* Free the list of update rectangles */
|
||||||
|
evas_render_updates_free(updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the canvas buffer to a Portable Pixel Map (PPM) file */
|
||||||
|
void canvas_save(Evas *canvas, const char *dest)
|
||||||
|
{
|
||||||
|
Evas_Engine_Info_Buffer *einfo;
|
||||||
|
const unsigned int *pixels, *pixels_end;
|
||||||
|
int width, height;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
/* Retrieve the current data buffer. */
|
||||||
|
einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
|
||||||
|
if (!einfo)
|
||||||
|
{
|
||||||
|
fputs("ERROR: could not get evas engine info!\n", stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve the canvas dimensions */
|
||||||
|
evas_output_size_get(canvas, &width, &height);
|
||||||
|
|
||||||
|
/* Open our output PPM file for writing */
|
||||||
|
f = fopen(dest, "wb+");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: could not open for writing '%s': %s\n",
|
||||||
|
dest, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write out the pixel data to the PPM file */
|
||||||
|
pixels = einfo->info.dest_buffer;
|
||||||
|
pixels_end = pixels + (width * height);
|
||||||
|
|
||||||
|
/* PPM P6 format is dead simple to write. First we output a magic
|
||||||
|
* number 'P6' to designate the file as PPM, then the width and
|
||||||
|
* height on their own line in ASCII decimal, followed by the maximum
|
||||||
|
* color value (255) on its own line in ASCII decimal, and finally a
|
||||||
|
* the pixel data in RGB order with each color component written as
|
||||||
|
* a char (byte). No alpha information is stored.
|
||||||
|
*/
|
||||||
|
fprintf(f, "P6\n%d %d\n255\n", width, height);
|
||||||
|
for (; pixels < pixels_end; pixels++)
|
||||||
|
{
|
||||||
|
int r, g, b;
|
||||||
|
|
||||||
|
r = ((*pixels) & 0xff0000) >> 16;
|
||||||
|
g = ((*pixels) & 0x00ff00) >> 8;
|
||||||
|
b = (*pixels) & 0x0000ff;
|
||||||
|
|
||||||
|
fprintf(f, "%c%c%c", r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
printf("saved scene as '%s'\n", dest);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef _EVAS_BUFFER_HELPER_H_
|
||||||
|
#define _EVAS_BUFFER_HELPER_H_
|
||||||
|
|
||||||
|
#include <Evas.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create canvas with buffer and create its internal buffer
|
||||||
|
*/
|
||||||
|
Evas* canvas_create(int width, int height);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return internal buffer
|
||||||
|
*/
|
||||||
|
void* canvas_buffer(Evas *evas);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Destroy canvas and internal buffer
|
||||||
|
*/
|
||||||
|
void canvas_destroy(Evas *canvas);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save canvas into image with PPM P6 format (*.ppm)
|
||||||
|
*/
|
||||||
|
void canvas_save(Evas *canvas, const char *dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw canvas (this should be called after making changes into evas)
|
||||||
|
*/
|
||||||
|
void canvas_draw(Evas *canvas);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // !_EVAS_BUFFER_HELPER_H_
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* TODO:
|
||||||
* * Test different font lodaing mechanisms.
|
* * Test different font loading mechanisms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* TODO:
|
||||||
* * Test different font lodaing mechanisms.
|
* * Test different font loading mechanisms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "evas_suite.h"
|
#include "evas_suite.h"
|
||||||
#include "evas_tests_helpers.h"
|
#include "evas_tests_helpers.h"
|
||||||
|
#include "evas_buffer_helper.h"
|
||||||
|
|
||||||
#define TESTS_DIC_DIR TESTS_SRC_DIR"/dicts"
|
#define TESTS_DIC_DIR TESTS_SRC_DIR"/dicts"
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ evas_suite_src = [
|
||||||
'evas_test_object.c',
|
'evas_test_object.c',
|
||||||
'evas_test_object_smart.c',
|
'evas_test_object_smart.c',
|
||||||
'evas_test_textblock.c',
|
'evas_test_textblock.c',
|
||||||
|
'evas_buffer_helper.c',
|
||||||
'evas_test_text.c',
|
'evas_test_text.c',
|
||||||
'evas_test_callbacks.c',
|
'evas_test_callbacks.c',
|
||||||
'evas_test_render_engines.c',
|
'evas_test_render_engines.c',
|
||||||
|
|
Loading…
Reference in New Issue