Skip to content

Commit

Permalink
add basic support for arabic.
Browse files Browse the repository at this point in the history
  • Loading branch information
aliaspider committed Feb 5, 2018
1 parent 5549b13 commit 45580cb
Show file tree
Hide file tree
Showing 25 changed files with 5,810 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ OBJ += intl/msg_hash_de.o \
intl/msg_hash_ru.o \
intl/msg_hash_vn.o \
intl/msg_hash_chs.o \
intl/msg_hash_cht.o
intl/msg_hash_cht.o \
intl/msg_hash_ar.o

endif

Expand Down
241 changes: 241 additions & 0 deletions gfx/font_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,14 +470,255 @@ static bool font_init_first(
return false;
}

#ifdef HAVE_LANGEXTRA

/* ACII: 0xxxxxxx (c & 0x80) == 0x00
* other start: 11xxxxxx (c & 0xC0) == 0xC0
* other cont: 10xxxxxx (c & 0xC0) == 0x80
* Neutral :
* 0020 - 002F : 001xxxxx (c & 0xE0) == 0x20
* Arabic:
* 0600 - 07FF : 11011xxx (c & 0xF8) == 0xD8 (2 bytes)
* 0800 - 08FF : 11100000 101000xx c == 0xE0 && (c1 & 0xAC) == 0xA0 (3 bytes) */

/* clang-format off */
#define IS_ASCII(p) ((*(p)&0x80) == 0x00)
#define IS_MBSTART(p) ((*(p)&0xC0) == 0xC0)
#define IS_MBCONT(p) ((*(p)&0xC0) == 0x80)
#define IS_DIR_NEUTRAL(p) ((*(p)&0xE0) == 0x20)
#define IS_ARABIC0(p) ((*(p)&0xF8) == 0xD8)
#define IS_ARABIC1(p) ((*(p) == 0xE0) && ((*((p) + 1) & 0xAC) == 0xA0))
#define IS_ARABIC(p) (IS_ARABIC0(p) || IS_ARABIC1(p))
#define IS_RTL(p) IS_ARABIC(p)

/* 0x0620 to 0x064F */
static const unsigned arabic_shape_map[0x50 - 0x20][0x4] = {
{ 0 }, /* 0x0620 */
{ 0xFE80 },
{ 0xFE81, 0xFE82 },
{ 0xFE83, 0xFE84 },
{ 0xFE85, 0xFE86 },
{ 0xFE87, 0xFE88 },
{ 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C },
{ 0xFE8D, 0xFE8E },

{ 0xFE8F, 0xFE90, 0xFE91, 0xFE92 },
{ 0xFE93, 0xFE94 },
{ 0xFE95, 0xFE96, 0xFE97, 0xFE98 },
{ 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C },
{ 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0 },
{ 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4 },
{ 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8 },
{ 0xFEA9, 0xFEAA },

{ 0xFEAB, 0xFEAC }, /* 0x0630 */
{ 0xFEAD, 0xFEAE },
{ 0xFEAF, 0xFEB0 },
{ 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4 },
{ 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8 },
{ 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC },
{ 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 },
{ 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 },
{ 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 },

{ 0xFEC9, 0xFECA, 0xFECB, 0xFECC },
{ 0xFECD, 0xFECE, 0xFECF, 0xFED0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },

{ 0xFED1, 0xFED2, 0xFED3, 0xFED4 }, /* 0x0640 */
{ 0xFED5, 0xFED6, 0xFED7, 0xFED8 },
{ 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC },
{ 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 },
{ 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 },
{ 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 },
{ 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC },
{ 0xFEED, 0xFEEE },

{ 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9 },
{ 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 },
};
/* clang-format on */

static INLINE unsigned font_get_replacement(const char* src, const char* start)
{
if ((*src & 0xFC) == 0xD8) /* 0x0600 to 0x06FF */
{
int lookup;
unsigned result;
bool prev_connected = false;
bool next_connected = false;
unsigned char id = (src[0] << 6) | (src[1] & 0x3F);
const char* prev1 = src - 2;
const char* prev2 = src - 4;

if (id < 0x21 || id > 0x4A)
return 0;

if(prev2 < start)
{
prev2 = NULL;
if(prev1 < start)
prev1 = NULL;
}

if (prev1 && (*prev1 & 0xFC) == 0xD8)
{
unsigned char prev1_id = 0;

if (prev1)
prev1_id = (prev1[0] << 6) | (prev1[1] & 0x3F);

if (prev1_id == 0x44)
{
unsigned char prev2_id = 0;

if (prev2)
prev2_id = (prev2[0] << 6) | (prev2[1] & 0x3F);

if (prev2_id > 0x20 || prev2_id < 0x50)
prev_connected = !!arabic_shape_map[prev2_id - 0x20][2];

switch (id)
{
case 0x22:
return 0xFEF5 + prev_connected;
case 0x23:
return 0xFEF7 + prev_connected;
case 0x25:
return 0xFEF9 + prev_connected;
case 0x27:
return 0xFEFB + prev_connected;
}
}
if (prev1_id > 0x20 || prev1_id < 0x50)
prev_connected = !!arabic_shape_map[prev1_id - 0x20][2];
}

if ((src[2] & 0xFC) == 0xD8)
{
unsigned char next_id = (src[2] << 6) | (src[3] & 0x3F);

if (next_id > 0x20 || next_id < 0x50)
next_connected = true;
}

result = arabic_shape_map[id - 0x20][prev_connected | (next_connected << 1)];

if (result)
return result;

return arabic_shape_map[id - 0x20][prev_connected];
}

return 0;
}

static char* font_driver_reshape_msg(const char* msg)
{
/* worst case transformations are 2 bytes to 4 bytes */
char* buffer = (char*)malloc((strlen(msg) * 2) + 1);
const char* src = msg;
char* dst = buffer;
bool reverse = false;

while (*src || reverse)
{
if (reverse)
{
src--;
while (IS_MBCONT(src))
src--;

if (IS_RTL(src) || IS_DIR_NEUTRAL(src))
{
unsigned replacement = font_get_replacement(src, msg);
if (replacement)
{
if (replacement < 0x80)
*dst++ = replacement;
else if (replacement < 0x8000)
{
*dst++ = 0xC0 | (replacement >> 6);
*dst++ = 0x80 | (replacement & 0x3F);
}
else if (replacement < 0x10000)
{
/* merged glyphs */
if ((replacement >= 0xFEF5) && (replacement <= 0xFEFC))
src -= 2;

*dst++ = 0xE0 | (replacement >> 12);
*dst++ = 0x80 | ((replacement >> 6) & 0x3F);
*dst++ = 0x80 | (replacement & 0x3F);
}
else
{
*dst++ = 0xF0 | (replacement >> 18);
*dst++ = 0x80 | ((replacement >> 12) & 0x3F);
*dst++ = 0x80 | ((replacement >> 6) & 0x3F);
*dst++ = 0x80 | (replacement & 0x3F);
}

continue;
}

*dst++ = *src++;
while (IS_MBCONT(src))
*dst++ = *src++;
src--;

while (IS_MBCONT(src))
src--;
}
else
{
reverse = false;
src++;
while (IS_MBCONT(src) || IS_RTL(src) || IS_DIR_NEUTRAL(src))
src++;
}
}
else
{
if (IS_RTL(src))
{
reverse = true;
while (IS_MBCONT(src) || IS_RTL(src) || IS_DIR_NEUTRAL(src))
src++;
}
else
*dst++ = *src++;
}
}

*dst = '\0';

return buffer;
}
#endif

void font_driver_render_msg(
video_frame_info_t *video_info,
void *font_data,
const char *msg, const void *params)
{
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);

if (font && font->renderer && font->renderer->render_msg)
{
#ifdef HAVE_LANGEXTRA
char* new_msg = font_driver_reshape_msg(msg);
font->renderer->render_msg(video_info, font->renderer_data, new_msg, params);
free(new_msg);
#else
font->renderer->render_msg(video_info, font->renderer_data, msg, params);
#endif
}
}

void font_driver_bind_block(void *font_data, void *block)
Expand Down
1 change: 1 addition & 0 deletions griffin/griffin.c
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ RETROARCH
#include "../intl/msg_hash_vn.c"
#include "../intl/msg_hash_chs.c"
#include "../intl/msg_hash_cht.c"
#include "../intl/msg_hash_ar.c"
#endif

#include "../intl/msg_hash_us.c"
Expand Down
Loading

0 comments on commit 45580cb

Please sign in to comment.