efl/src/lib/evas/common/evas_font_main.c

1154 lines
32 KiB
C
Raw Normal View History

#include "evas_font_private.h"
#include "evas_font_draw.h"
#include FT_OUTLINE_H
#include FT_SYNTHESIS_H
#include FT_BITMAP_H
#include FT_TRUETYPE_DRIVER_H
FT_Library evas_ft_lib = 0;
static int initialised = 0;
2002-11-08 00:02:15 -08:00
LK(lock_font_draw); // for freetype2 API calls
LK(lock_bidi); // for evas bidi internal usage.
LK(lock_ot); // for evas bidi internal usage.
int _evas_font_log_dom_global = -1;
EAPI void
evas_common_font_init(void)
2002-11-08 00:02:15 -08:00
{
int error;
const char *s;
FT_UInt interpreter_version =
#ifndef TT_INTERPRETER_VERSION_35
TT_INTERPRETER_VERSION_35;
#else
35;
#endif
_evas_font_log_dom_global = eina_log_domain_register
("evas_font_main", EVAS_FONT_DEFAULT_LOG_COLOR);
if (_evas_font_log_dom_global < 0)
{
EINA_LOG_ERR("Can not create a module log domain.");
}
2002-11-08 00:02:15 -08:00
initialised++;
if (initialised != 1) return;
error = FT_Init_FreeType(&evas_ft_lib);
if (error) return;
FT_Property_Set(evas_ft_lib, "truetype", "interpreter-version",
&interpreter_version);
evas_common_font_load_init();
evas_common_font_draw_init();
s = getenv("EVAS_FONT_DPI");
if (s)
{
int dpi_h = 75, dpi_v = 0;
2011-11-09 00:01:00 -08:00
if (sscanf(s, "%dx%d", &dpi_h, &dpi_v) < 2)
dpi_h = dpi_v = atoi(s);
if (dpi_h > 0) evas_common_font_dpi_set(dpi_h, dpi_v);
}
LKI(lock_font_draw);
LKI(lock_bidi);
LKI(lock_ot);
2002-11-08 00:02:15 -08:00
}
EAPI void
evas_common_font_shutdown(void)
{
if (initialised < 1) return;
initialised--;
if (initialised != 0) return;
evas_common_font_load_shutdown();
evas_common_font_cache_set(0);
evas_common_font_flush();
FT_Done_FreeType(evas_ft_lib);
evas_ft_lib = 0;
LKD(lock_font_draw);
LKD(lock_bidi);
LKD(lock_ot);
eina_log_domain_unregister(_evas_font_log_dom_global);
}
EAPI void
evas_common_font_font_all_unload(void)
{
evas_common_font_all_clear();
}
/* FIXME: This function should not be used. It's a short-cut fix that is meant
* to improve font fallback for in-theme fonts. It will break if we stop using
* freetype (unlikely) or do anything else fancy. */
void *
evas_common_font_freetype_face_get(RGBA_Font *font)
{
RGBA_Font_Int *fi = font->fonts->data;
if (!fi)
return NULL;
evas_common_font_int_reload(fi);
return fi->src->ft.face;
}
EAPI int
evas_common_font_instance_ascent_get(RGBA_Font_Int *fi)
2002-11-08 00:02:15 -08:00
{
int val;
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
if (!FT_IS_SCALABLE(fi->src->ft.face))
{
WRN("NOT SCALABLE!");
}
val = (int)fi->src->ft.face->size->metrics.ascender;
if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
{
if (FT_HAS_COLOR(fi->src->ft.face) &&
fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
val *= fi->scale_factor;
}
return FONT_METRIC_ROUNDUP(val);
// printf("%i | %i\n", val, val >> 6);
// if (fi->src->ft.face->units_per_EM == 0)
// return val;
// dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
// ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
// return ret;
2002-11-08 00:02:15 -08:00
}
EAPI int
evas_common_font_instance_descent_get(RGBA_Font_Int *fi)
2002-11-08 00:02:15 -08:00
{
int val;
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
val = -(int)fi->src->ft.face->size->metrics.descender;
if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
{
if (FT_HAS_COLOR(fi->src->ft.face) &&
fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
val *= fi->scale_factor;
}
return FONT_METRIC_ROUNDUP(val);
// if (fi->src->ft.face->units_per_EM == 0)
// return val;
// dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
// ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
// return ret;
2002-11-08 00:02:15 -08:00
}
EAPI int
evas_common_font_instance_max_ascent_get(RGBA_Font_Int *fi)
2002-11-08 00:02:15 -08:00
{
int val, dv;
2002-11-08 00:02:15 -08:00
int ret;
2005-05-21 19:49:48 -07:00
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
if ((fi->src->ft.face->bbox.yMax == 0) &&
(fi->src->ft.face->bbox.yMin == 0) &&
(fi->src->ft.face->units_per_EM == 0))
val = FONT_METRIC_ROUNDUP((int)fi->src->ft.face->size->metrics.ascender);
else
val = (int)fi->src->ft.face->bbox.yMax;
if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
{
if (FT_HAS_COLOR(fi->src->ft.face) &&
fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
val *= fi->scale_factor;
}
if (fi->src->ft.face->units_per_EM == 0)
2009-04-23 21:35:52 -07:00
return val;
2005-05-21 19:49:48 -07:00
dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
2012-10-10 00:00:07 -07:00
ret = FONT_METRIC_CONV(val, dv, fi->src->ft.face->size->metrics.y_scale);
2002-11-08 00:02:15 -08:00
return ret;
}
EAPI int
evas_common_font_instance_max_descent_get(RGBA_Font_Int *fi)
2002-11-08 00:02:15 -08:00
{
int val, dv;
2002-11-08 00:02:15 -08:00
int ret;
2005-05-21 19:49:48 -07:00
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
if ((fi->src->ft.face->bbox.yMax == 0) &&
(fi->src->ft.face->bbox.yMin == 0) &&
(fi->src->ft.face->units_per_EM == 0))
val = FONT_METRIC_ROUNDUP(-(int)fi->src->ft.face->size->metrics.descender);
else
val = -(int)fi->src->ft.face->bbox.yMin;
if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
{
if (FT_HAS_COLOR(fi->src->ft.face) &&
fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
val *= fi->scale_factor;
}
if (fi->src->ft.face->units_per_EM == 0)
2009-04-23 21:35:52 -07:00
return val;
2005-05-21 19:49:48 -07:00
dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
2012-10-10 00:00:07 -07:00
ret = FONT_METRIC_CONV(val, dv, fi->src->ft.face->size->metrics.y_scale);
2002-11-08 00:02:15 -08:00
return ret;
}
EAPI int
evas_common_font_ascent_get(RGBA_Font *fn)
{
// evas_common_font_size_use(fn);
return evas_common_font_instance_ascent_get(fn->fonts->data);
}
EAPI int
evas_common_font_descent_get(RGBA_Font *fn)
{
// evas_common_font_size_use(fn);
return evas_common_font_instance_descent_get(fn->fonts->data);
}
EAPI int
evas_common_font_max_ascent_get(RGBA_Font *fn)
{
// evas_common_font_size_use(fn);
return evas_common_font_instance_max_ascent_get(fn->fonts->data);
}
EAPI int
evas_common_font_max_descent_get(RGBA_Font *fn)
{
// evas_common_font_size_use(fn);
return evas_common_font_instance_max_descent_get(fn->fonts->data);
}
EAPI int
evas_common_font_get_line_advance(RGBA_Font *fn)
2002-11-08 00:02:15 -08:00
{
int val;
RGBA_Font_Int *fi;
2005-05-21 19:49:48 -07:00
// evas_common_font_size_use(fn);
fi = fn->fonts->data;
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
val = (int)fi->src->ft.face->size->metrics.height;
if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
{
if ((fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR) &&
FT_HAS_COLOR(fi->src->ft.face))
val *= fi->scale_factor;
}
if ((fi->src->ft.face->bbox.yMax == 0) &&
(fi->src->ft.face->bbox.yMin == 0) &&
(fi->src->ft.face->units_per_EM == 0))
return FONT_METRIC_ROUNDUP(val);
else if (fi->src->ft.face->units_per_EM == 0)
2009-04-23 21:35:52 -07:00
return val;
return FONT_METRIC_ROUNDUP(val);
// dv = (fi->src->ft.orig_upem * 2048) / fi->src->ft.face->units_per_EM;
// ret = (val * fi->src->ft.face->size->metrics.y_scale) / (dv * dv);
// return ret;
2002-11-08 00:02:15 -08:00
}
EAPI int
evas_common_font_instance_underline_position_get(RGBA_Font_Int *fi)
{
int position = 0;
if (!fi) goto end;
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
position = FT_MulFix(fi->src->ft.face->underline_position,
fi->src->ft.face->size->metrics.x_scale);
position = FONT_METRIC_ROUNDUP(abs(position));
end:
/* This almost surely means a broken font, offset at least by one pixel. */
if (position == 0)
position = 1;
return position;
}
EAPI int
evas_common_font_instance_underline_thickness_get(RGBA_Font_Int *fi)
{
int thickness = 0;
if (!fi) goto end;
evas_common_font_int_reload(fi);
if (fi->src->current_size != fi->size)
{
FTLOCK();
FT_Activate_Size(fi->ft.size);
FTUNLOCK();
fi->src->current_size = fi->size;
}
thickness = FT_MulFix(fi->src->ft.face->underline_thickness,
fi->src->ft.face->size->metrics.x_scale);
thickness = FONT_METRIC_ROUNDUP(thickness);
end:
/* This almost surely means a broken font, make it at least one pixel. */
if (thickness == 0)
thickness = 1;
return thickness;
}
/* Set of common functions that are used in a couple of places. */
static void
2019-12-11 23:22:12 -08:00
_fash_int_map_and_variations_free(Fash_Int_Map *map)
{
if(!map)
return;
int i;
2019-12-11 23:22:12 -08:00
for (i = 0; i < 256; i++)
{
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
_fash_int_free(Fash_Int *fash)
{
int i;
2019-12-11 23:22:12 -08:00
if (fash)
{
if (fash->MAGIC != FASH_INT_MAGIC)
{
return;
}
2019-12-11 23:22:12 -08:00
for (i = 0; i < 256; i++)
{
if (fash->bucket[i])
{
_fash_int2_free(fash->bucket[i]);
fash->bucket[i] = NULL;
}
}
free(fash);
}
}
static Fash_Int *
_fash_int_new(void)
{
Fash_Int *fash = calloc(1, sizeof(Fash_Int));
2019-12-11 23:22:12 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
fash->MAGIC = FASH_INT_MAGIC;
fash->freeme = _fash_int_free;
return fash;
}
2019-12-11 23:22:12 -08:00
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 *
2019-12-11 23:22:12 -08:00
_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;
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
grp = (item >> 16) & 0xff;
maj = (item >> 8) & 0xff;
min = item & 0xff;
if (!fash->bucket[grp]) return NULL;
if (!fash->bucket[grp]->bucket[maj]) return NULL;
2019-12-11 23:22:12 -08:00
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
2019-12-11 23:22:12 -08:00
_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx, Eina_Unicode variation_sequence)
{
int grp, maj, min;
2019-12-11 23:22:12 -08:00
// 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)
grp = (item >> 16) & 0xff;
maj = (item >> 8) & 0xff;
min = item & 0xff;
if (!fash->bucket[grp])
fash->bucket[grp] = calloc(1, sizeof(Fash_Int_Map2));
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
if (!fash->bucket[grp]->bucket[maj])
fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
2019-12-11 23:22:12 -08:00
if (variation_sequence)
{
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
_glyph_free(RGBA_Font_Glyph *fg)
{
if ((!fg) || (fg == (void *)(-1))) return;
if (fg->glyph_out)
{
if ((!fg->glyph_out->rle) && (!fg->glyph_out->bitmap.rle_alloc))
{
FT_BitmapGlyph fbg = (FT_BitmapGlyph)fg->glyph;
FT_Bitmap_Done(evas_ft_lib, &(fbg->bitmap));
}
if ((fg->glyph_out->rle) && (fg->glyph_out->bitmap.rle_alloc))
free(fg->glyph_out->rle);
else if ((fg->glyph_out->bitmap.buffer) && (fg->glyph_out->bitmap.rle_alloc))
{
free(fg->glyph_out->bitmap.buffer);
fg->glyph_out->bitmap.buffer = NULL;
}
fg->glyph_out->rle = NULL;
if (!fg->glyph_out->bitmap.no_free_glout) free(fg->glyph_out);
fg->glyph_out = NULL;
}
FT_Done_Glyph(fg->glyph);
/* extension calls */
if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
if (fg->col_dat) evas_cache_image_drop(fg->col_dat);
free(fg);
}
static void
_fash_glyph_free(Fash_Glyph_Map *fmap)
{
int i;
for (i = 0; i <= 0xff; i++)
{
RGBA_Font_Glyph *fg = fmap->item[i];
if ((fg) && (fg != (void *)(-1)))
{
_glyph_free(fg);
fmap->item[i] = NULL;
}
}
free(fmap);
}
static void
_fash_gl2_free(Fash_Glyph_Map2 *fash)
{
int i;
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
2019-12-11 23:22:12 -08:00
for (i = 0; i < 256; i++)
{
if (fash->bucket[i])
{
_fash_glyph_free(fash->bucket[i]);
fash->bucket[i] = NULL;
}
}
free(fash);
}
static void
_fash_gl_free(Fash_Glyph *fash)
{
2019-12-11 23:22:12 -08:00
if (fash)
{
if (fash->MAGIC != FASH_GLYPH_MAGIC)
return;
2019-12-11 23:22:12 -08:00
int i;
// 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_gl2_free(fash->bucket[i]);
fash->bucket[i] = NULL;
}
}
free(fash);
}
}
static Fash_Glyph *
_fash_gl_new(void)
{
Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
2019-12-11 23:22:12 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
fash->MAGIC = FASH_GLYPH_MAGIC;
fash->freeme = _fash_gl_free;
return fash;
}
static RGBA_Font_Glyph *
_fash_gl_find(Fash_Glyph *fash, int item)
{
int grp, maj, min;
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
grp = (item >> 16) & 0xff;
maj = (item >> 8) & 0xff;
min = item & 0xff;
if (!fash->bucket[grp]) return NULL;
if (!fash->bucket[grp]->bucket[maj]) return NULL;
return fash->bucket[grp]->bucket[maj]->item[min];
}
static void
_fash_gl_add(Fash_Glyph *fash, int item, RGBA_Font_Glyph *glyph)
{
int grp, maj, min;
// 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
grp = (item >> 16) & 0xff;
maj = (item >> 8) & 0xff;
min = item & 0xff;
if (!fash->bucket[grp])
fash->bucket[grp] = calloc(1, sizeof(Fash_Glyph_Map2));
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]);
if (!fash->bucket[grp]->bucket[maj])
fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Glyph_Map));
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
fash->bucket[grp]->bucket[maj]->item[min] = glyph;
}
EAPI RGBA_Font_Glyph *
evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt idx)
{
RGBA_Font_Glyph *fg;
FT_Error error;
const FT_Int32 hintflags[3] =
{ FT_LOAD_NO_HINTING, FT_LOAD_FORCE_AUTOHINT, FT_LOAD_NO_AUTOHINT };
static FT_Matrix transform = {0x10000, _EVAS_FONT_SLANT_TAN * 0x10000,
0x00000, 0x10000};
evas_common_font_int_promote(fi);
if (fi->fash)
{
fg = _fash_gl_find(fi->fash, idx);
if (fg == (void *)(-1)) return NULL;
else if (fg)
return fg;
}
// fg = eina_hash_find(fi->glyphs, &hindex);
// if (fg) return fg;
evas_common_font_int_reload(fi);
FTLOCK();
error = FT_Load_Glyph(fi->src->ft.face, idx,
(FT_HAS_COLOR(fi->src->ft.face) ?
(FT_LOAD_COLOR | hintflags[fi->hinting]) :
(FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP | hintflags[fi->hinting])));
FTUNLOCK();
if (error)
{
if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
return NULL;
}
/* Transform the outline of Glyph according to runtime_rend. */
if (fi->runtime_rend & FONT_REND_SLANT)
FT_Outline_Transform(&fi->src->ft.face->glyph->outline, &transform);
/* Embolden the outline of Glyph according to rundtime_rend. */
if (fi->runtime_rend & FONT_REND_WEIGHT)
FT_GlyphSlot_Embolden(fi->src->ft.face->glyph);
fg = calloc(1, sizeof(RGBA_Font_Glyph));
if (!fg) return NULL;
FTLOCK();
error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph));
FTUNLOCK();
if (error)
{
free(fg);
if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, idx, (void *)(-1));
return NULL;
}
{
FT_BBox outbox;
FT_Glyph_Get_CBox(fg->glyph,
((fi->hinting == 0) ? FT_GLYPH_BBOX_UNSCALED :
FT_GLYPH_BBOX_GRIDFIT),
&outbox);
fg->width = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMax - outbox.xMin);
fg->x_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.xMin);
fg->y_bear = EVAS_FONT_ROUND_26_6_TO_INT(outbox.yMax);
if (FT_HAS_FIXED_SIZES(fi->src->ft.face))
{
if (FT_HAS_COLOR(fi->src->ft.face) &&
fi->bitmap_scalable & EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR)
{
fg->glyph->advance.x *= fi->scale_factor;
fg->glyph->advance.y *= fi->scale_factor;
fg->width *= fi->scale_factor;
fg->x_bear *= fi->scale_factor;
fg->y_bear *= fi->scale_factor;
}
}
}
fg->index = idx;
fg->fi = fi;
if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, idx, fg);
// eina_hash_direct_add(fi->glyphs, &fg->index, fg);
return fg;
}
EAPI Eina_Bool
evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg)
{
int size;
FT_Error error;
RGBA_Font_Int *fi = fg->fi;
FT_BitmapGlyph fbg;
/* no cserve2 case */
if (fg->glyph_out)
return EINA_TRUE;
FTLOCK();
error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
if (error)
{
FT_Done_Glyph(fg->glyph);
FTUNLOCK();
if (!fi->fash) fi->fash = _fash_gl_new();
if (fi->fash) _fash_gl_add(fi->fash, fg->index, (void *)(-1));
2013-04-15 02:42:47 -07:00
free(fg);
return EINA_FALSE;
}
FTUNLOCK();
fbg = (FT_BitmapGlyph)fg->glyph;
fg->glyph_out = calloc(1, sizeof(RGBA_Font_Glyph_Out));
fg->glyph_out->bitmap.rows = fbg->bitmap.rows;
fg->glyph_out->bitmap.width = fbg->bitmap.width;
fg->glyph_out->bitmap.pitch = fbg->bitmap.pitch;
fg->glyph_out->bitmap.buffer = fbg->bitmap.buffer;
fg->glyph_out->bitmap.rle_alloc = EINA_TRUE;
/* This '+ 100' is just an estimation of how much memory freetype will use
* on it's size. This value is not really used anywhere in code - it's
* only for statistics. */
size = sizeof(RGBA_Font_Glyph) + sizeof(Eina_List) +
(fg->glyph_out->bitmap.width * fg->glyph_out->bitmap.rows / 2) + 100;
fi->usage += size;
if (fi->inuse) evas_common_font_int_use_increase(size);
if (!FT_HAS_COLOR(fi->src->ft.face))
{
fg->glyph_out->rle = evas_common_font_glyph_compress
(fbg->bitmap.buffer, fbg->bitmap.num_grays, fbg->bitmap.pixel_mode,
fbg->bitmap.pitch, fbg->bitmap.width, fbg->bitmap.rows,
&(fg->glyph_out->rle_size));
fg->glyph_out->bitmap.rle_alloc = EINA_TRUE;
fg->glyph_out->bitmap.buffer = NULL;
// this may be technically incorrect as we go and free a bitmap buffer
// behind the ftglyph's back...
FT_Bitmap_Done(evas_ft_lib, &(fbg->bitmap));
}
else
{
fg->glyph_out->rle = NULL;
fg->glyph_out->bitmap.rle_alloc = EINA_FALSE;
evas_text: reduce Video Memory & RAM needed for text textures (Color Glyphs) Summary: Texture created for bitmap font glyph, with a fixed size in the font, this size could be much bigger than the needed size in application. Then a scale factor is applied to these textures when drawn. Now, instead, we will create smaller bitmaps and create texture from them with reduced texture size (that is not needed). ** This will affect both Video Memory and Ram needed to store glyphs** Open this file {F3883874} in terminology before and after applying the patch and notice the difference. Test Plan: **Notes** - You need to scroll down to make all glyphs visible, then notice Video/Ram memory | | Video | Ram |----------------------|-------|----- | Before (Font_size=50) | 360 | 300 | After (Font_size=50) | 40 | 100 | Ration After/before | 11% | 33% **I notice speed up in text rendering for small font size** ``` #include <Elementary.h> typedef struct _APP { Evas_Object *tb1; Evas_Object *btnLoad; } APP; char *text = "<align=center><color=#4DE0FFFF underline=on underline_color=#4DE0FFFF><a href='tel:1234567890'>1234567890</a></color>😀😁😂🤣😃😄😅😆😉😊😋😎😍😘😗😙😚☺🙂🤗🤔😐😑😶🙄😏😣😥😮🤐😯😪😫😴😌🤓😛😜😝🤤😒😓😔😕🙃🤑😲☹🙁😖😞😟😤😢😭😦😧😨😩😬😰😱😳😵😡😠😇🤠🤡🤥😷🤒🤕🤢🤧☻😈👿👹👺💀☠👻👽👾🤖💩😺😸😹😻😼😽🙀😿😾🙈🙉🙊👦👧👨👩👵👶👼👨‍⚕️👩‍⚕️👨‍🎓👩‍🎓👨‍🏫👩‍🏫👨‍⚖👩‍⚖👨‍🌾👩‍🌾👨‍🍳👩‍🍳👨‍🔧👩‍🔧👨‍🏭👩‍🏭👨‍💼👩‍💼👨‍🔬👩‍🔬👨‍💻👩‍💻👨‍🎤👩‍🎤👨‍🎨👩‍🎨👨‍✈️👩‍✈️👨‍🚀👩‍🚀👨‍🚒👩‍🚒👮‍♂️👮‍♀️🕵️‍♂️🕵️‍♀️💂‍♂️💂‍♀️👷‍♂️👷‍♀️👳‍♂️👳‍♀️👱‍♂️👱‍♀️🎅🤶👸🤴👰🤵🤰👲🙍‍♂️🙍‍♀️🙎‍♂️🙎‍♀️🙅‍♂️🙅‍♀️🙆‍♂️🙆‍♀️💁‍♂️💁‍♀️🙋‍♂️🙋‍♀️🙇‍♂️🙇‍♀️🤦‍♂️🤦‍♀️🤷‍♂️🤷‍♀️💆‍♂️💆‍♀️💇‍♂️💇‍♀️🚶‍♂️🚶‍♀️🏃‍♂️🏃‍♀️💃🕺👯‍♂️👯‍♀️🕴🗣👤👥👫👬👭💏💑👪👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👦👨‍👦‍👦👨‍👧👨‍👧‍👦👨‍👧‍👧👩‍👦👩‍👦‍👦👩‍👧👩‍👧‍👦👩‍👧‍👧💪🤳👈👉☝️👆🖕👇✌🤞🖖🤘👊🖐✋👌👍👎✊👊🤛🤜🤚👋👏✍👐🙌🙏🤝💅👂👃👣👀👁👅👄💋💘❤💓💔💕💖💗💙💚💛💜🖤💝💞💟❣💌💤💢💣💥💦💨💫💬🗨🗯💭🕳👓🕶👔👕👖👗👘👙👚👛👜👝🛍🎒👞👟👠👡👢👑👒🎩🎓⛑📿💄💍💎🐵🐒🦍🐶🐕🐩🐺🦊🐱🐈🦁🐯🐅🐆🐴🐎🦌🦄🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🐘🦏🐭🐁🐀🐹🐰🐇🐿🦇🐻🐨🐼🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊🦅🦆🦉🐸🐊🐢🦎🐍🐲🐉🐳🐋🐬🐟🐠🐡🦈🐙🐚🦀🦐🦑🦋🐌🐛🐜🐝🐞🕷🕸🦂💐🌸💮🏵🌹🥀🌺🌻🌼🌷⚘🌱🌲🌳🌴🌵🌾🌿☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍅🥝🥑🍆🥔🥕🌽🌶🥒🍄🥜🌰🍞🥐🥖🥞🧀🍖🍗🥓🍔🍟🍕🌭🌮🌯🥙🥚🍳🥘🍲🥗🍿🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🍡🍦🍧🍨🍩🍪🎂🍰🍫🍬🍭🍮🍯🍼🥛☕🍵🍶🍾🍷🍸🍹🍺🍻🥂🍽🍴🥄🔪🏺🎃🎄🎆🎇✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🎀🎁🎗🎟🎫🎖🏆🏅🥇🥈🥉⚽️⚾️🏀🏐🏈🏉🎾🎱🎳🏏🏑🏒🏓🏸🥊🥋🥅🎯⛳🏌️‍♂️🏌️‍♀️⛸🎣🎽🎿⛷🏂🏄‍♂️🏄‍♀️🏇🏊‍♂️🏊‍♀️⛹️‍♂️⛹️‍♀️🏋️‍♂️🏋️‍♀️🚴‍♂️🚴‍♀️🚵‍♂️🚵‍♀️🏎🏍🤸‍♂️🤸‍♀️🤼‍♂️🤼‍♀️🤽‍♂️🤽‍♀️🤾‍♂️🤾‍♀️🤺🤹‍♂️🤹‍♀️🎮🕹🎲♠️♥️♦️♣️🃏🀄🎴🌍🌎🌏🌐🗺🏔⛰🌋🗻🏕🏖🏜🏝🏞🏟🏛🏗🏘🏙🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🕍⛩🕋⛲⛺🌁🌃🌄🌅🌆🌇🌉⛼♨️🌌🎠🎡🎢💈🎪🎭🖼🎨🎰🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛⛟🚜🚲🛴🛵🚏🛣🛤⛽🚨🚥🚦🚧🛑⚓⛵🚣‍♂️🚣‍♀️🛶🚤🛳⛴🛥🚢✈🛩🛫🛬💺🚁🚟🚠🚡🚀🛰🛎🚪🛌🛏🛋🚽🚿🛀🛁⌛⏳⌚⏰⏱⏲🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡☀️🌝🌞⭐🌟🌠☁️⛅⛈🌤🌥🌦🌧🌨🌩🌪🌫🌬🌀🌈🌂☂️☔⛱⚡❄☃️⛄☄🔥💧🌊🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙🎚🎛🎤🎧📻🎷🎸🎹🎺🎻🥁📱📲☎️📞📟📠🔋🔌💻🖥🖨⌨🖱🖲💽💾💿📀🎥🎞📽🎬📺📷📸📹📼🔍🔎🔬🔭📡🕯💡🔦🏮📔📕📖📗📘📙📚📓📒📃📜📄📰🗞📑🔖🏷💰💴💵💶💷💸💳💱💲✉📧📨📩📤📥📦📫📪📬📭📮🗳✏✒🖋🖊🖌🖍📝💼📁📂🗂📅📆🗒🗓📇📈📉📊📋📌📍📎🖇📏📐✂️🗃🗄🗑🔒🔓🔏🔐🔑🗝🔨⛏⚒🛠🗡⚔🔫🏹🛡🔧🔩⚙🗜⚗⚖🔗⛓💉💊🚬⚰⚱🗿🛢🔮🔮🏧🚮🚰♿🚹🚺🚻🚼🚾🛂🛃🛄🛅⚠️🚸⛔🚫🚳🚭🚯🚱🚷📵🔞☢☣⬆️↗️➡️↘️⬇️↙️⬅️↖️↕️↔️↩↪⤴️⤵️🔃🔄🔙🔚🔛🔜🔝🛐⚛🕉✡☸☯️☦☮🕎🔯♈♉♊♋♌♍♎♏♐♑♒♓⛎🔀🔁🔂▶️⏩⏭⏯◀️⏪⏮🔼⏫🔽⏬⏸⏹⏺⏏🎦🔅🔆📶📳📴♻️📛⚜🔰🔱⭕✅☑✔✖❌❎➕♀️♂️⚕➖➗➰➿〽✳✴❇⁉️❓❔❕❗〰🔟💯🔠🔡🔢🔣🔤🅰️🆎️🅱️🆑️🆒️🆓️ℹ🆔️Ⓜ️🆕️🆖️🅾️🆗️🅿️🆘️🆙️🆚️🈁🈂🈷🈶🈯🉐🈹🈚🈲🉑🈸🈴🈳㊗㊙🈺🈵▫️◻◼◽◾⬛⬜🔶️🔷️🔸️🔹️🔺️🔻💠🔘🔲🔳⚪⚫🔴🔵🏁🚩🏴🏳🏳️‍🌈⚀⚁⚂⚃⚄⚅⛾♾🇦🇨🇦🇩🇦🇪🇦🇫🇦🇬🇦🇮🇦🇱🇦🇲🇦🇴🇦🇶🇦🇷🇦🇸🇦🇹🇦🇺🇦🇼🇦🇽🇦🇿🇧🇦🇧🇧🇧🇩🇧🇪🇧🇫🇧🇬🇧🇭🇧🇮🇧🇯🇧🇱🇧🇲🇧🇳🇧🇴🇧🇶🇧🇷🇧🇸🇧🇹🇧🇼🇧🇾🇧🇿🇨🇦🇨🇨🇨🇩🇨🇫🇨🇬🇨🇭🇨🇮🇨🇰🇨🇱🇨🇲🇨🇳🇨🇴🇨🇷🇨🇺🇨🇻🇨🇼🇨🇽🇨🇾🇨🇿🇩🇪🇩🇯🇩🇰🇩🇲🇩🇴🇩🇿🇪🇨🇪🇪🇪🇬🇪🇭🇪🇷🇪🇸🇪🇹🇪🇺🇫🇮🇫🇯🇫🇰🇫🇲🇫🇴🇫🇷🇬🇦🇬🇧🇬🇩🇬🇪🇬🇫🇬🇬🇬🇭🇬🇮🇬🇱🇬🇲🇬🇳🇬🇵🇬🇶🇬🇷🇬🇸🇬🇹🇬🇺🇬🇼🇬🇾🇭🇰🇭🇲🇭🇳🇭🇷🇭🇹🇭🇺🇮🇨🇮🇩🇮🇪🇮🇱🇮🇲🇮🇳🇮🇴🇮🇶🇮🇷🇮🇸🇮🇹🇯🇪🇯🇲🇯🇴🇯🇵🇰🇪🇰🇬🇰🇭🇰🇮🇰🇲🇰🇳🇰🇵🇰🇷🇰🇼🇰🇾🇰🇿🇱🇦🇱🇧🇱🇨🇱🇮🇱🇰🇱🇷🇱🇸🇱🇹🇱🇺🇱🇻🇱🇾🇲🇦🇲🇨🇲🇩🇲🇪🇲🇬🇲🇭🇲🇰🇲🇱🇲🇲🇲🇳🇲🇴🇲🇵🇲🇶🇲🇷🇲🇸🇲🇹🇲🇺🇲🇻🇲🇼🇲🇽🇲🇾🇲🇿🇳🇦🇳🇨🇳🇪🇳🇫🇳🇬🇳🇮🇳🇱🇳🇴🇳🇵🇳🇷🇳🇺🇳🇿🇴🇲🇵🇦🇵🇪🇵🇫🇵🇬🇵🇭🇵🇰🇵🇱🇵🇲🇵🇳🇵🇷🇵🇸🇵🇹🇵🇼🇵🇾🇶🇦🇷🇪🇷🇴🇷🇸🇷🇺🇷🇼🇸🇦🇸🇧🇸🇨🇸🇩🇸🇪🇸🇬🇸🇭🇸🇮🇸🇰🇸🇱🇸🇲🇸🇳🇸🇴🇸🇷🇸🇸🇸🇹🇸🇻🇸🇽🇸🇾🇸🇿🇹🇦🇹🇨🇹🇩🇹🇫🇹🇬🇹🇭🇹🇯🇹🇰🇹🇱🇹🇲🇹🇳🇹🇴🇹🇷🇹🇹🇹🇻🇹🇼🇹🇿🇺🇦🇺🇬🇺🇳🇺🇸🇺🇾🇺🇿🇻🇦🇻🇨🇻🇪🇻🇬🇻🇮🇻🇳🇻🇺🇼🇫🇼🇸🇽🇰🇾🇪🇾🇹🇿🇦🇿🇲🇿🇼8<br/><br/><br/><br/>Sent from my Samsung Galaxy smartphone.</align>"; int font_size = 100; void _button_clicked(void *data, Evas_Object *obj, void *event_info) { APP *app = data; font_size = font_size - font_size/5; char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); Evas_Textblock_Style *style = evas_textblock_style_new(); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); sprintf(buffer, "font_size = %i",font_size); elm_object_text_set(app->btnLoad, buffer); style = NULL; } EAPI_MAIN int elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) { APP *app = calloc(1, sizeof(APP)); Evas_Object *win, *scroller1, *scroller2, *box; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); scroller1 = elm_scroller_add(win); evas_object_size_hint_weight_set(scroller1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(scroller1, EVAS_HINT_FILL, EVAS_HINT_FILL); //evas_text_cache_policy_set(EVAS_TEXT_CACHE_POLICY_TEXTURE ,EVAS_TEXT_CACHE_NONE); app->tb1 = evas_object_textblock_add(win); Evas_Textblock_Style *style = evas_textblock_style_new(); char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); style = NULL; int w,h; evas_object_textblock_text_markup_set(app->tb1, ""); evas_object_size_hint_min_set(app->tb1, 360, 720); elm_object_content_set(scroller1, app->tb1); elm_box_pack_end(box, scroller1); elm_object_content_set(win, box); app->btnLoad = elm_button_add(win); sprintf(buffer, "font_size = %i",font_size); elm_object_text_set(app->btnLoad, buffer); evas_object_smart_callback_add(app->btnLoad, "clicked", _button_clicked, app); evas_object_show(app->btnLoad); evas_object_move(app->btnLoad, 0, 20); evas_object_resize(app->btnLoad, 150, 20); evas_object_textblock_text_markup_set(app->tb1, text); evas_object_textblock_size_formatted_get(app->tb1, &w, &h); evas_object_size_hint_min_set(app->tb1, 800, w/800 + h + 150); evas_object_resize(win, 800, 800); evas_object_show(box); evas_object_show(scroller1); evas_object_show(scroller2); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: raster, woohyun, bu5hm4n, zmike, Hermet, segfaultxavi Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8712 Differential Revision: https://phab.enlightenment.org/D11814
2020-05-29 02:10:28 -07:00
if (fi->is_resized)
{
int w = fbg->bitmap.width;
int h = fbg->bitmap.rows;
RGBA_Image src = {0};
src.image.data = (DATA32 *) fbg->bitmap.buffer;
src.cache_entry.w = w;
src.cache_entry.h = h;
src.cache_entry.flags.alpha = 1;
RGBA_Image dst = {0};
dst.cache_entry.w = w * fi->scale_factor;
dst.cache_entry.h = h * fi->scale_factor;
dst.image.data = malloc(dst.cache_entry.w * dst.cache_entry.h * 4);
dst.cache_entry.flags.alpha = 1;
evas_common_scale_rgba_smooth_draw(&src, &dst,
0, 0, src.cache_entry.w , src.cache_entry.h,
0xffffffff, EVAS_RENDER_COPY,
0, 0, src.cache_entry.w , src.cache_entry.h,
0, 0, dst.cache_entry.w, dst.cache_entry.h,
NULL, 0, 0);
fg->glyph_out->bitmap.rows = dst.cache_entry.h;
fg->glyph_out->bitmap.width = dst.cache_entry.w;
fg->glyph_out->bitmap.buffer = (unsigned char *) dst.image.data;
fg->glyph_out->bitmap.pitch = dst.cache_entry.w * 4;
evas_text: reduce Video Memory & RAM needed for text textures (Color Glyphs) Summary: Texture created for bitmap font glyph, with a fixed size in the font, this size could be much bigger than the needed size in application. Then a scale factor is applied to these textures when drawn. Now, instead, we will create smaller bitmaps and create texture from them with reduced texture size (that is not needed). ** This will affect both Video Memory and Ram needed to store glyphs** Open this file {F3883874} in terminology before and after applying the patch and notice the difference. Test Plan: **Notes** - You need to scroll down to make all glyphs visible, then notice Video/Ram memory | | Video | Ram |----------------------|-------|----- | Before (Font_size=50) | 360 | 300 | After (Font_size=50) | 40 | 100 | Ration After/before | 11% | 33% **I notice speed up in text rendering for small font size** ``` #include <Elementary.h> typedef struct _APP { Evas_Object *tb1; Evas_Object *btnLoad; } APP; char *text = "<align=center><color=#4DE0FFFF underline=on underline_color=#4DE0FFFF><a href='tel:1234567890'>1234567890</a></color>😀😁😂🤣😃😄😅😆😉😊😋😎😍😘😗😙😚☺🙂🤗🤔😐😑😶🙄😏😣😥😮🤐😯😪😫😴😌🤓😛😜😝🤤😒😓😔😕🙃🤑😲☹🙁😖😞😟😤😢😭😦😧😨😩😬😰😱😳😵😡😠😇🤠🤡🤥😷🤒🤕🤢🤧☻😈👿👹👺💀☠👻👽👾🤖💩😺😸😹😻😼😽🙀😿😾🙈🙉🙊👦👧👨👩👵👶👼👨‍⚕️👩‍⚕️👨‍🎓👩‍🎓👨‍🏫👩‍🏫👨‍⚖👩‍⚖👨‍🌾👩‍🌾👨‍🍳👩‍🍳👨‍🔧👩‍🔧👨‍🏭👩‍🏭👨‍💼👩‍💼👨‍🔬👩‍🔬👨‍💻👩‍💻👨‍🎤👩‍🎤👨‍🎨👩‍🎨👨‍✈️👩‍✈️👨‍🚀👩‍🚀👨‍🚒👩‍🚒👮‍♂️👮‍♀️🕵️‍♂️🕵️‍♀️💂‍♂️💂‍♀️👷‍♂️👷‍♀️👳‍♂️👳‍♀️👱‍♂️👱‍♀️🎅🤶👸🤴👰🤵🤰👲🙍‍♂️🙍‍♀️🙎‍♂️🙎‍♀️🙅‍♂️🙅‍♀️🙆‍♂️🙆‍♀️💁‍♂️💁‍♀️🙋‍♂️🙋‍♀️🙇‍♂️🙇‍♀️🤦‍♂️🤦‍♀️🤷‍♂️🤷‍♀️💆‍♂️💆‍♀️💇‍♂️💇‍♀️🚶‍♂️🚶‍♀️🏃‍♂️🏃‍♀️💃🕺👯‍♂️👯‍♀️🕴🗣👤👥👫👬👭💏💑👪👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👦👨‍👦‍👦👨‍👧👨‍👧‍👦👨‍👧‍👧👩‍👦👩‍👦‍👦👩‍👧👩‍👧‍👦👩‍👧‍👧💪🤳👈👉☝️👆🖕👇✌🤞🖖🤘👊🖐✋👌👍👎✊👊🤛🤜🤚👋👏✍👐🙌🙏🤝💅👂👃👣👀👁👅👄💋💘❤💓💔💕💖💗💙💚💛💜🖤💝💞💟❣💌💤💢💣💥💦💨💫💬🗨🗯💭🕳👓🕶👔👕👖👗👘👙👚👛👜👝🛍🎒👞👟👠👡👢👑👒🎩🎓⛑📿💄💍💎🐵🐒🦍🐶🐕🐩🐺🦊🐱🐈🦁🐯🐅🐆🐴🐎🦌🦄🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🐘🦏🐭🐁🐀🐹🐰🐇🐿🦇🐻🐨🐼🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊🦅🦆🦉🐸🐊🐢🦎🐍🐲🐉🐳🐋🐬🐟🐠🐡🦈🐙🐚🦀🦐🦑🦋🐌🐛🐜🐝🐞🕷🕸🦂💐🌸💮🏵🌹🥀🌺🌻🌼🌷⚘🌱🌲🌳🌴🌵🌾🌿☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍅🥝🥑🍆🥔🥕🌽🌶🥒🍄🥜🌰🍞🥐🥖🥞🧀🍖🍗🥓🍔🍟🍕🌭🌮🌯🥙🥚🍳🥘🍲🥗🍿🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🍡🍦🍧🍨🍩🍪🎂🍰🍫🍬🍭🍮🍯🍼🥛☕🍵🍶🍾🍷🍸🍹🍺🍻🥂🍽🍴🥄🔪🏺🎃🎄🎆🎇✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🎀🎁🎗🎟🎫🎖🏆🏅🥇🥈🥉⚽️⚾️🏀🏐🏈🏉🎾🎱🎳🏏🏑🏒🏓🏸🥊🥋🥅🎯⛳🏌️‍♂️🏌️‍♀️⛸🎣🎽🎿⛷🏂🏄‍♂️🏄‍♀️🏇🏊‍♂️🏊‍♀️⛹️‍♂️⛹️‍♀️🏋️‍♂️🏋️‍♀️🚴‍♂️🚴‍♀️🚵‍♂️🚵‍♀️🏎🏍🤸‍♂️🤸‍♀️🤼‍♂️🤼‍♀️🤽‍♂️🤽‍♀️🤾‍♂️🤾‍♀️🤺🤹‍♂️🤹‍♀️🎮🕹🎲♠️♥️♦️♣️🃏🀄🎴🌍🌎🌏🌐🗺🏔⛰🌋🗻🏕🏖🏜🏝🏞🏟🏛🏗🏘🏙🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🕍⛩🕋⛲⛺🌁🌃🌄🌅🌆🌇🌉⛼♨️🌌🎠🎡🎢💈🎪🎭🖼🎨🎰🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛⛟🚜🚲🛴🛵🚏🛣🛤⛽🚨🚥🚦🚧🛑⚓⛵🚣‍♂️🚣‍♀️🛶🚤🛳⛴🛥🚢✈🛩🛫🛬💺🚁🚟🚠🚡🚀🛰🛎🚪🛌🛏🛋🚽🚿🛀🛁⌛⏳⌚⏰⏱⏲🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡☀️🌝🌞⭐🌟🌠☁️⛅⛈🌤🌥🌦🌧🌨🌩🌪🌫🌬🌀🌈🌂☂️☔⛱⚡❄☃️⛄☄🔥💧🌊🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙🎚🎛🎤🎧📻🎷🎸🎹🎺🎻🥁📱📲☎️📞📟📠🔋🔌💻🖥🖨⌨🖱🖲💽💾💿📀🎥🎞📽🎬📺📷📸📹📼🔍🔎🔬🔭📡🕯💡🔦🏮📔📕📖📗📘📙📚📓📒📃📜📄📰🗞📑🔖🏷💰💴💵💶💷💸💳💱💲✉📧📨📩📤📥📦📫📪📬📭📮🗳✏✒🖋🖊🖌🖍📝💼📁📂🗂📅📆🗒🗓📇📈📉📊📋📌📍📎🖇📏📐✂️🗃🗄🗑🔒🔓🔏🔐🔑🗝🔨⛏⚒🛠🗡⚔🔫🏹🛡🔧🔩⚙🗜⚗⚖🔗⛓💉💊🚬⚰⚱🗿🛢🔮🔮🏧🚮🚰♿🚹🚺🚻🚼🚾🛂🛃🛄🛅⚠️🚸⛔🚫🚳🚭🚯🚱🚷📵🔞☢☣⬆️↗️➡️↘️⬇️↙️⬅️↖️↕️↔️↩↪⤴️⤵️🔃🔄🔙🔚🔛🔜🔝🛐⚛🕉✡☸☯️☦☮🕎🔯♈♉♊♋♌♍♎♏♐♑♒♓⛎🔀🔁🔂▶️⏩⏭⏯◀️⏪⏮🔼⏫🔽⏬⏸⏹⏺⏏🎦🔅🔆📶📳📴♻️📛⚜🔰🔱⭕✅☑✔✖❌❎➕♀️♂️⚕➖➗➰➿〽✳✴❇⁉️❓❔❕❗〰🔟💯🔠🔡🔢🔣🔤🅰️🆎️🅱️🆑️🆒️🆓️ℹ🆔️Ⓜ️🆕️🆖️🅾️🆗️🅿️🆘️🆙️🆚️🈁🈂🈷🈶🈯🉐🈹🈚🈲🉑🈸🈴🈳㊗㊙🈺🈵▫️◻◼◽◾⬛⬜🔶️🔷️🔸️🔹️🔺️🔻💠🔘🔲🔳⚪⚫🔴🔵🏁🚩🏴🏳🏳️‍🌈⚀⚁⚂⚃⚄⚅⛾♾🇦🇨🇦🇩🇦🇪🇦🇫🇦🇬🇦🇮🇦🇱🇦🇲🇦🇴🇦🇶🇦🇷🇦🇸🇦🇹🇦🇺🇦🇼🇦🇽🇦🇿🇧🇦🇧🇧🇧🇩🇧🇪🇧🇫🇧🇬🇧🇭🇧🇮🇧🇯🇧🇱🇧🇲🇧🇳🇧🇴🇧🇶🇧🇷🇧🇸🇧🇹🇧🇼🇧🇾🇧🇿🇨🇦🇨🇨🇨🇩🇨🇫🇨🇬🇨🇭🇨🇮🇨🇰🇨🇱🇨🇲🇨🇳🇨🇴🇨🇷🇨🇺🇨🇻🇨🇼🇨🇽🇨🇾🇨🇿🇩🇪🇩🇯🇩🇰🇩🇲🇩🇴🇩🇿🇪🇨🇪🇪🇪🇬🇪🇭🇪🇷🇪🇸🇪🇹🇪🇺🇫🇮🇫🇯🇫🇰🇫🇲🇫🇴🇫🇷🇬🇦🇬🇧🇬🇩🇬🇪🇬🇫🇬🇬🇬🇭🇬🇮🇬🇱🇬🇲🇬🇳🇬🇵🇬🇶🇬🇷🇬🇸🇬🇹🇬🇺🇬🇼🇬🇾🇭🇰🇭🇲🇭🇳🇭🇷🇭🇹🇭🇺🇮🇨🇮🇩🇮🇪🇮🇱🇮🇲🇮🇳🇮🇴🇮🇶🇮🇷🇮🇸🇮🇹🇯🇪🇯🇲🇯🇴🇯🇵🇰🇪🇰🇬🇰🇭🇰🇮🇰🇲🇰🇳🇰🇵🇰🇷🇰🇼🇰🇾🇰🇿🇱🇦🇱🇧🇱🇨🇱🇮🇱🇰🇱🇷🇱🇸🇱🇹🇱🇺🇱🇻🇱🇾🇲🇦🇲🇨🇲🇩🇲🇪🇲🇬🇲🇭🇲🇰🇲🇱🇲🇲🇲🇳🇲🇴🇲🇵🇲🇶🇲🇷🇲🇸🇲🇹🇲🇺🇲🇻🇲🇼🇲🇽🇲🇾🇲🇿🇳🇦🇳🇨🇳🇪🇳🇫🇳🇬🇳🇮🇳🇱🇳🇴🇳🇵🇳🇷🇳🇺🇳🇿🇴🇲🇵🇦🇵🇪🇵🇫🇵🇬🇵🇭🇵🇰🇵🇱🇵🇲🇵🇳🇵🇷🇵🇸🇵🇹🇵🇼🇵🇾🇶🇦🇷🇪🇷🇴🇷🇸🇷🇺🇷🇼🇸🇦🇸🇧🇸🇨🇸🇩🇸🇪🇸🇬🇸🇭🇸🇮🇸🇰🇸🇱🇸🇲🇸🇳🇸🇴🇸🇷🇸🇸🇸🇹🇸🇻🇸🇽🇸🇾🇸🇿🇹🇦🇹🇨🇹🇩🇹🇫🇹🇬🇹🇭🇹🇯🇹🇰🇹🇱🇹🇲🇹🇳🇹🇴🇹🇷🇹🇹🇹🇻🇹🇼🇹🇿🇺🇦🇺🇬🇺🇳🇺🇸🇺🇾🇺🇿🇻🇦🇻🇨🇻🇪🇻🇬🇻🇮🇻🇳🇻🇺🇼🇫🇼🇸🇽🇰🇾🇪🇾🇹🇿🇦🇿🇲🇿🇼8<br/><br/><br/><br/>Sent from my Samsung Galaxy smartphone.</align>"; int font_size = 100; void _button_clicked(void *data, Evas_Object *obj, void *event_info) { APP *app = data; font_size = font_size - font_size/5; char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); Evas_Textblock_Style *style = evas_textblock_style_new(); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); sprintf(buffer, "font_size = %i",font_size); elm_object_text_set(app->btnLoad, buffer); style = NULL; } EAPI_MAIN int elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED) { APP *app = calloc(1, sizeof(APP)); Evas_Object *win, *scroller1, *scroller2, *box; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); scroller1 = elm_scroller_add(win); evas_object_size_hint_weight_set(scroller1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(scroller1, EVAS_HINT_FILL, EVAS_HINT_FILL); //evas_text_cache_policy_set(EVAS_TEXT_CACHE_POLICY_TEXTURE ,EVAS_TEXT_CACHE_NONE); app->tb1 = evas_object_textblock_add(win); Evas_Textblock_Style *style = evas_textblock_style_new(); char buffer[100] = {0}; sprintf(buffer, "DEFAULT='font=NotoColorEmoji font_size=%i color=red ellipsis=-1.0 wrap=mixed'", font_size); evas_textblock_style_set(style, buffer); evas_object_textblock_style_set(app->tb1, style); evas_textblock_style_free(style); style = NULL; int w,h; evas_object_textblock_text_markup_set(app->tb1, ""); evas_object_size_hint_min_set(app->tb1, 360, 720); elm_object_content_set(scroller1, app->tb1); elm_box_pack_end(box, scroller1); elm_object_content_set(win, box); app->btnLoad = elm_button_add(win); sprintf(buffer, "font_size = %i",font_size); elm_object_text_set(app->btnLoad, buffer); evas_object_smart_callback_add(app->btnLoad, "clicked", _button_clicked, app); evas_object_show(app->btnLoad); evas_object_move(app->btnLoad, 0, 20); evas_object_resize(app->btnLoad, 150, 20); evas_object_textblock_text_markup_set(app->tb1, text); evas_object_textblock_size_formatted_get(app->tb1, &w, &h); evas_object_size_hint_min_set(app->tb1, 800, w/800 + h + 150); evas_object_resize(win, 800, 800); evas_object_show(box); evas_object_show(scroller1); evas_object_show(scroller2); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: raster, woohyun, bu5hm4n, zmike, Hermet, segfaultxavi Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T8712 Differential Revision: https://phab.enlightenment.org/D11814
2020-05-29 02:10:28 -07:00
fg->glyph_out->rle = NULL;
fg->glyph_out->bitmap.rle_alloc = EINA_TRUE;
// this may be technically incorrect as we go and free a bitmap buffer
// behind the ftglyph's back...
FT_Bitmap_Done(evas_ft_lib, &(fbg->bitmap));
}
}
return EINA_TRUE;
}
typedef struct _Font_Char_Index Font_Char_Index;
struct _Font_Char_Index
{
FT_UInt index;
Eina_Unicode gl;
};
EAPI FT_UInt
2019-12-11 23:22:12 -08:00
evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode variation_sequence)
{
static const unsigned short mapfix[] =
{
0x00b0, 0x7,
0x00b1, 0x8,
0x00b7, 0x1f,
0x03c0, 0x1c,
0x20a4, 0xa3,
0x2260, 0x1d,
0x2264, 0x1a,
0x2265, 0x1b,
0x23ba, 0x10,
0x23bb, 0x11,
0x23bc, 0x13,
0x23bd, 0x14,
0x2409, 0x3,
0x240a, 0x6,
0x240b, 0xa,
0x240c, 0x4,
0x240d, 0x5,
0x2424, 0x9,
0x2500, 0x12,
0x2502, 0x19,
0x250c, 0xd,
0x2510, 0xc,
0x2514, 0xe,
0x2518, 0xb,
0x251c, 0x15,
0x2524, 0x16,
0x252c, 0x18,
0x2534, 0x17,
0x253c, 0xf,
0x2592, 0x2,
0x25c6, 0x1,
};
Font_Char_Index result;
//FT_UInt ret;
#ifdef HAVE_PTHREAD
/// pthread_mutex_lock(&fi->ft_mutex);
#endif
// result = eina_hash_find(fi->indexes, &gl);
// if (result) goto on_correct;
//
// result = malloc(sizeof (Font_Char_Index));
// if (!result)
// {
//#ifdef HAVE_PTHREAD
// pthread_mutex_unlock(&fi->ft_mutex);
//#endif
// return FT_Get_Char_Index(fi->src->ft.face, gl);
// }
evas_common_font_int_reload(fi);
/*
* There is no point in locking FreeType at this point as all caller
* are running in the main loop at a time where there is zero chance
* that something else try to use it.
*/
/* FTLOCK(); */
2019-12-11 23:22:12 -08:00
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(); */
result.gl = gl;
// eina_hash_direct_add(fi->indexes, &result->gl, result);
//
// on_correct:
#ifdef HAVE_PTHREAD
// pthread_mutex_unlock(&fi->ft_mutex);
#endif
// this is a workaround freetype bugs where for a bitmap old style font
// even if it has unicode information and mappings, they are not used
// to find terminal line/drawing chars, so do this by hand with a table
if ((result.index <= 0) && (fi->src->ft.face->num_fixed_sizes == 1) &&
(fi->src->ft.face->num_glyphs < 512))
{
int i, min = 0, max;
// binary search through sorted table of codepoints to new
// codepoints with a guess that bitmap font is playing the old
// game of putting line drawing chars in specific ranges
max = sizeof(mapfix) / (sizeof(mapfix[0]) * 2);
i = (min + max) / 2;
for (;;)
{
unsigned short v;
v = mapfix[i << 1];
if (gl == v)
{
gl = mapfix[(i << 1) + 1];
FTLOCK();
2019-12-11 23:22:12 -08:00
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();
break;
}
// failure to find at all
if ((max - min) <= 2) break;
// if glyph above out position...
if (gl > v)
{
min = i;
if ((max - min) == 1) i = max;
else i = (min + max) / 2;
}
// if glyph below out position
else if (gl < v)
{
max = i;
if ((max - min) == 1) i = min;
else i = (min + max) / 2;
}
}
}
return result.index;
}
2019-12-11 23:22:12 -08:00
/*
* @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
2019-12-11 23:22:12 -08:00
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;
if (fn->fash)
{
2019-12-11 23:22:12 -08:00
const Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl, variation_sequence);
if (fm)
{
if (fm->fint)
{
2019-12-11 23:22:12 -08:00
if (evas_font_search_options == EVAS_FONT_SEARCH_OPTION_NONE)
{
*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;
}
}
for (l = fn->fonts; l; l = l->next)
{
RGBA_Font_Int *fi;
int idx;
fi = l->data;
#if 0 /* FIXME: charmap user is disabled and use a deprecated data type. */
/*
if (fi->src->charmap) // Charmap loaded, FI/FS blank
{
idx = evas_array_hash_search(fi->src->charmap, gl);
if (idx != 0)
{
evas_common_font_source_load_complete(fi->src);
evas_common_font_int_load_complete(fi);
evas_array_hash_free(fi->src->charmap);
fi->src->charmap = NULL;
*fi_ret = fi;
return idx;
}
}
else
*/
#endif
if (!fi->src->ft.face) /* Charmap not loaded, FI/FS blank */
{
evas_common_font_int_reload(fi);
}
if (fi->src->ft.face)
{
2019-12-11 23:22:12 -08:00
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 (!fi->ft.size)
evas_common_font_int_load_complete(fi);
2019-12-11 23:22:12 -08:00
if (!is_color_only)
{
if (!fn->fash) fn->fash = _fash_int_new();
if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx, variation_sequence);
}
*fi_ret = fi;
return idx;
}
else
{
2019-12-11 23:22:12 -08:00
if (!is_color_only)
{
if (!fn->fash) fn->fash = _fash_int_new();
if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1, variation_sequence);
}
}
}
}
*fi_ret = NULL;
return 0;
}