forked from enlightenment/efl
203 lines
4.5 KiB
C
203 lines
4.5 KiB
C
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "evas_common.h"
|
|
#include "evas_bidi_utils.h"
|
|
#include "evas_encoding.h"
|
|
|
|
#include "evas_font_private.h"
|
|
|
|
#ifdef BIDI_SUPPORT
|
|
#include <fribidi/fribidi.h>
|
|
|
|
#define _SAFE_FREE(x) \
|
|
do { \
|
|
if (x) \
|
|
{ \
|
|
free(x); \
|
|
x = NULL; \
|
|
} \
|
|
} while(0)
|
|
|
|
Eina_Bool
|
|
evas_bidi_is_rtl_str(const Eina_Unicode *str)
|
|
{
|
|
int i = 0;
|
|
int ch;
|
|
EvasBiDiCharType type;
|
|
|
|
if (!str)
|
|
return EINA_FALSE;
|
|
|
|
for ( ; *str ; str++)
|
|
{
|
|
type = fribidi_get_bidi_type(*str);
|
|
if (FRIBIDI_IS_LETTER(type) && FRIBIDI_IS_RTL(type))
|
|
{
|
|
return EINA_TRUE;
|
|
}
|
|
}
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
int
|
|
evas_bidi_update_props(Eina_Unicode *ustr, Evas_BiDi_Props *intl_props)
|
|
{
|
|
EvasBiDiCharType *char_types = NULL;
|
|
EvasBiDiLevel *embedding_levels = NULL;
|
|
EvasBiDiJoiningType *join_types = NULL;
|
|
size_t len;
|
|
|
|
if (!ustr)
|
|
return -2;
|
|
|
|
if (!evas_bidi_is_rtl_str(ustr)) /* No need to handle bidi */
|
|
{
|
|
len = -1;
|
|
goto cleanup;
|
|
}
|
|
|
|
len = eina_unicode_strlen(ustr);
|
|
|
|
/* Prep work for reordering */
|
|
char_types = (EvasBiDiCharType *) malloc(sizeof(EvasBiDiCharType) * len);
|
|
if (!char_types)
|
|
{
|
|
len = -2;
|
|
goto cleanup;
|
|
}
|
|
fribidi_get_bidi_types(ustr, len, char_types);
|
|
|
|
embedding_levels = (EvasBiDiLevel *)malloc(sizeof(EvasBiDiLevel) * len);
|
|
if (!embedding_levels)
|
|
{
|
|
len = -2;
|
|
goto cleanup;
|
|
}
|
|
if (!fribidi_get_par_embedding_levels(char_types, len, &intl_props->direction, embedding_levels))
|
|
{
|
|
len = -2;
|
|
goto cleanup;
|
|
}
|
|
|
|
join_types = (EvasBiDiJoiningType *) malloc(sizeof(EvasBiDiJoiningType) * len);
|
|
if (!join_types)
|
|
{
|
|
len = -2;
|
|
goto cleanup;
|
|
}
|
|
fribidi_get_joining_types(ustr, len, join_types);
|
|
|
|
fribidi_join_arabic(char_types, len, embedding_levels, join_types);
|
|
|
|
|
|
/* Actually modify the string */
|
|
fribidi_shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, embedding_levels, len, join_types,
|
|
ustr);
|
|
|
|
/* clean up */
|
|
if (intl_props->embedding_levels)
|
|
{
|
|
free(intl_props->embedding_levels);
|
|
}
|
|
intl_props->embedding_levels = embedding_levels;
|
|
|
|
/* clean up */
|
|
|
|
if (intl_props->char_types)
|
|
{
|
|
free(intl_props->char_types);
|
|
}
|
|
intl_props->char_types = char_types;
|
|
|
|
|
|
if (join_types) free(join_types);
|
|
|
|
return len;
|
|
|
|
/* Cleanup */
|
|
cleanup:
|
|
if (join_types) free(join_types);
|
|
if (char_types) free(char_types);
|
|
if (embedding_levels) free(embedding_levels);
|
|
evas_bidi_props_clean(intl_props); /*Mark that we don't need bidi handling */
|
|
return len;
|
|
}
|
|
|
|
int
|
|
evas_bidi_props_reorder_line(Eina_Unicode *ustr, const Evas_BiDi_Props *intl_props, EvasBiDiStrIndex **_v_to_l)
|
|
{
|
|
EvasBiDiStrIndex *v_to_l = NULL;
|
|
size_t len;
|
|
|
|
if (!EVAS_BIDI_IS_BIDI_PROP(intl_props))
|
|
return 0;
|
|
|
|
len = eina_unicode_strlen(ustr);
|
|
|
|
if (_v_to_l) {
|
|
int i;
|
|
v_to_l = *_v_to_l = calloc(len, sizeof(EvasBiDiStrIndex));
|
|
if (!v_to_l)
|
|
{
|
|
goto error;
|
|
}
|
|
/* init the array for fribidi */
|
|
for (i = 0 ; i < len ; i++)
|
|
{
|
|
v_to_l[i] = i;
|
|
}
|
|
}
|
|
|
|
/* Shaping must be done *BEFORE* breaking to lines so there's no choice but
|
|
doing it in textblock. */
|
|
if (!fribidi_reorder_line (FRIBIDI_FLAGS_DEFAULT, intl_props->char_types,
|
|
len, 0, intl_props->direction,
|
|
intl_props->embedding_levels, ustr, v_to_l))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
|
|
return 0;
|
|
/* ERROR HANDLING */
|
|
error:
|
|
_SAFE_FREE(v_to_l);
|
|
return 1;
|
|
}
|
|
|
|
|
|
EvasBiDiStrIndex
|
|
evas_bidi_position_logical_to_visual(EvasBiDiStrIndex *v_to_l, int len, EvasBiDiStrIndex position)
|
|
{
|
|
int i;
|
|
EvasBiDiStrIndex *ind;
|
|
if (position >= len || !v_to_l)
|
|
return position;
|
|
|
|
for (i = 0, ind = v_to_l ; i < len ; i++, ind++)
|
|
{
|
|
if (*ind == position)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return position;
|
|
}
|
|
|
|
Eina_Bool
|
|
evas_bidi_is_rtl_char(EvasBiDiLevel *embedded_level_list, EvasBiDiStrIndex index)
|
|
{
|
|
if(!embedded_level_list || index < 0)
|
|
return EINA_FALSE;
|
|
return (FRIBIDI_IS_RTL(embedded_level_list[index])) ? EINA_TRUE : EINA_FALSE;
|
|
}
|
|
|
|
void
|
|
evas_bidi_props_clean(Evas_BiDi_Props *intl_props)
|
|
{
|
|
_SAFE_FREE(intl_props->embedding_levels);
|
|
_SAFE_FREE(intl_props->char_types);
|
|
}
|
|
#endif
|