Patch #783877 by Gadi Cohen updated by Naftali Goldstein - Bidirectional text support for Hebrew and Arabic
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7292 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1874a33298
commit
41a53d2c1c
10 changed files with 246 additions and 1 deletions
|
@ -3238,3 +3238,9 @@ desc: in browse_id3
|
|||
eng: "<No gain>"
|
||||
voice ""
|
||||
new:
|
||||
|
||||
id: LANG_BIDI_SUPPORT
|
||||
desc: in settings_menu, option to enable reversal of hebrew/arabic text
|
||||
eng: "BiDi Hebrew/Arabic"
|
||||
voice ""
|
||||
new:
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "power.h"
|
||||
#include "backlight.h"
|
||||
#include "powermgmt.h"
|
||||
#include "bidi.h"
|
||||
#include "status.h"
|
||||
#include "atoi.h"
|
||||
#include "screens.h"
|
||||
|
@ -265,10 +266,14 @@ static const struct bit_entry rtc_bits[] =
|
|||
{1, S_O(remote_flip_display), false, "remote flip display", off_on },
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LCD_BITMAP /* move to LCD next time we bump version */
|
||||
{1, S_O(bidi_support), false, "bidi hebrew/arabic", off_on },
|
||||
#endif
|
||||
|
||||
/* new stuff to be added here */
|
||||
/* If values are just added to the end, no need to bump the version. */
|
||||
|
||||
/* Current sum of bits: 268 (worst case, but w/o remote lcd) */
|
||||
/* Current sum of bits: 277 (worst case, but w/o remote lcd) */
|
||||
/* Sum of all bit sizes must not grow beyond 288! */
|
||||
};
|
||||
|
||||
|
@ -820,6 +825,7 @@ void settings_apply(void)
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
set_bidi_support(global_settings.bidi_support);
|
||||
lcd_set_invert_display(global_settings.invert);
|
||||
lcd_set_flip(global_settings.flip_display);
|
||||
button_set_flip(global_settings.flip_display);
|
||||
|
|
|
@ -197,6 +197,7 @@ struct user_settings
|
|||
bool invert_cursor; /* invert the current file in dir browser and menu
|
||||
instead of using the default cursor */
|
||||
bool flip_display; /* turn display (and button layout) by 180 degrees */
|
||||
bool bidi_support; /* reverse hebrew/arabic chars: 0=off, 1=on */
|
||||
int poweroff; /* power off timer */
|
||||
int backlight_timeout; /* backlight off timeout: 0-18 0=never,
|
||||
1=always,
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "fat.h" /* For dotfile settings */
|
||||
#include "sleeptimer.h"
|
||||
#include "powermgmt.h"
|
||||
#include "bidi.h"
|
||||
#include "rtc.h"
|
||||
#include "ata.h"
|
||||
#include "tree.h"
|
||||
|
@ -278,6 +279,18 @@ static bool invert_cursor(void)
|
|||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu to reverse Hebrew and Arabic text according to BiDi algorythm
|
||||
*/
|
||||
static bool bidi_support(void)
|
||||
{
|
||||
return set_bool_options( str(LANG_BIDI_SUPPORT),
|
||||
&global_settings.bidi_support,
|
||||
STR(LANG_SET_BOOL_YES),
|
||||
STR(LANG_SET_BOOL_NO),
|
||||
set_bidi_support);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu to configure the battery display on status bar
|
||||
*/
|
||||
|
@ -1421,6 +1434,7 @@ static bool lcd_settings_menu(void)
|
|||
{ ID2P(LANG_INVERT), invert },
|
||||
{ ID2P(LANG_FLIP_DISPLAY), flip_display },
|
||||
{ ID2P(LANG_INVERT_CURSOR), invert_cursor },
|
||||
{ ID2P(LANG_BIDI_SUPPORT), bidi_support },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -129,3 +129,5 @@ Ryan Jackson
|
|||
Per Holmäng
|
||||
Frederic Devernay
|
||||
José M. Fandiño
|
||||
Gadi Cohen
|
||||
Naftali Goldstein
|
||||
|
|
|
@ -49,6 +49,7 @@ drivers/lcd-player-charset.c
|
|||
drivers/lcd-player.c
|
||||
#endif
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
bidi.c
|
||||
#if LCD_DEPTH == 2
|
||||
drivers/lcd-h100.c
|
||||
#elif LCD_DEPTH == 1
|
||||
|
|
184
firmware/bidi.c
Normal file
184
firmware/bidi.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2005 by Gadi Cohen
|
||||
*
|
||||
* Largely based on php_hebrev by Zeev Suraski <zeev@php.net>
|
||||
* Heavily modified by Gadi Cohen aka Kinslayer <dragon@wastelands.net>
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "file.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#define _HEB_BUFFER_LENGTH MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2
|
||||
#define _HEB_BLOCK_TYPE_ENG 1
|
||||
#define _HEB_BLOCK_TYPE_HEB 0
|
||||
#define _HEB_ORIENTATION_LTR 1
|
||||
#define _HEB_ORIENTATION_RTL 0
|
||||
|
||||
#define ischar(c) (((((unsigned char) c)>=193) && (((unsigned char) c)<=250)) ? 1 : 0)
|
||||
#define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0)
|
||||
#define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0)
|
||||
#define XOR(a,b) ((a||b) && !(a&&b))
|
||||
|
||||
bool bidi_support_enabled = false;
|
||||
|
||||
unsigned char *bidi_l2v(const unsigned char *str, int orientation)
|
||||
{
|
||||
static unsigned char buf_heb_str[_HEB_BUFFER_LENGTH];
|
||||
static unsigned char buf_broken_str[_HEB_BUFFER_LENGTH];
|
||||
const unsigned char *tmp;
|
||||
unsigned char *heb_str, *target, *opposite_target, *broken_str;
|
||||
int block_start, block_end, block_type, block_length, i;
|
||||
int block_ended;
|
||||
long max_chars=0;
|
||||
int begin, end, char_count, orig_begin;
|
||||
|
||||
if (!str || !*str)
|
||||
return "";
|
||||
|
||||
tmp = str;
|
||||
block_start=block_end=0;
|
||||
block_ended=0;
|
||||
|
||||
heb_str = buf_heb_str;
|
||||
if (orientation) {
|
||||
target = heb_str;
|
||||
opposite_target = heb_str + strlen(str);
|
||||
} else {
|
||||
target = heb_str + strlen(str);
|
||||
opposite_target = heb_str;
|
||||
*target = 0;
|
||||
target--;
|
||||
}
|
||||
|
||||
block_length=0;
|
||||
if (ischar(*tmp))
|
||||
block_type = _HEB_BLOCK_TYPE_HEB;
|
||||
else
|
||||
block_type = _HEB_BLOCK_TYPE_ENG;
|
||||
|
||||
do {
|
||||
while((XOR(ischar((int)*(tmp+1)),block_type)
|
||||
|| _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1))
|
||||
|| (int)*(tmp+1)=='\n')
|
||||
&& block_end<(int)strlen(str)-1) {
|
||||
tmp++;
|
||||
block_end++;
|
||||
block_length++;
|
||||
}
|
||||
|
||||
if (block_type != orientation) {
|
||||
while ((_isblank((int)*tmp) || ispunct((int)*tmp))
|
||||
&& *tmp!='/' && *tmp!='-' && block_end>block_start) {
|
||||
tmp--;
|
||||
block_end--;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=block_start; i<=block_end; i++) {
|
||||
*target = (block_type == orientation) ? *(str+i) : *(str+block_end-i+block_start);
|
||||
if (block_type!=orientation) {
|
||||
switch (*target) {
|
||||
case '(':
|
||||
*target = ')';
|
||||
break;
|
||||
case ')':
|
||||
*target = '(';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
target += orientation ? 1 : -1;
|
||||
}
|
||||
block_type = !block_type;
|
||||
block_start=block_end+1;
|
||||
} while(block_end<(int)strlen(str)-1);
|
||||
|
||||
broken_str = buf_broken_str;
|
||||
begin=end=strlen(str)-1;
|
||||
target = broken_str;
|
||||
|
||||
while (1) {
|
||||
char_count=0;
|
||||
while ((!max_chars || char_count<max_chars) && begin>0) {
|
||||
char_count++;
|
||||
begin--;
|
||||
if (begin<=0 || _isnewline(heb_str[begin])) {
|
||||
while(begin>0 && _isnewline(heb_str[begin-1])) {
|
||||
begin--;
|
||||
char_count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (char_count==max_chars) { /* try to avoid breaking words */
|
||||
int new_char_count = char_count;
|
||||
int new_begin = begin;
|
||||
|
||||
while (new_char_count>0) {
|
||||
if (_isblank(heb_str[new_begin]) ||
|
||||
_isnewline(heb_str[new_begin])) {
|
||||
break;
|
||||
}
|
||||
new_begin++;
|
||||
new_char_count--;
|
||||
}
|
||||
if (new_char_count>0) {
|
||||
char_count=new_char_count;
|
||||
begin=new_begin;
|
||||
}
|
||||
}
|
||||
orig_begin=begin;
|
||||
|
||||
if (_isblank(heb_str[begin])) {
|
||||
heb_str[begin]='\n';
|
||||
}
|
||||
|
||||
/* skip leading newlines */
|
||||
while (begin<=end && _isnewline(heb_str[begin])) {
|
||||
begin++;
|
||||
}
|
||||
|
||||
/* copy content */
|
||||
for (i=begin; i<=end; i++) {
|
||||
*target = heb_str[i];
|
||||
target++;
|
||||
}
|
||||
|
||||
for (i=orig_begin; i<=end && _isnewline(heb_str[i]); i++) {
|
||||
*target = heb_str[i];
|
||||
target++;
|
||||
}
|
||||
begin=orig_begin;
|
||||
|
||||
if (begin<=0) {
|
||||
*target = 0;
|
||||
break;
|
||||
}
|
||||
begin--;
|
||||
end=begin;
|
||||
}
|
||||
return broken_str;
|
||||
}
|
||||
|
||||
void set_bidi_support(bool setting)
|
||||
{
|
||||
bidi_support_enabled = setting;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#include "debug.h"
|
||||
#include "system.h"
|
||||
#include "font.h"
|
||||
#include "bidi.h"
|
||||
|
||||
/*** definitions ***/
|
||||
|
||||
|
@ -992,6 +993,9 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
|
|||
int ch;
|
||||
struct font* pf = font_get(curfont);
|
||||
|
||||
if (bidi_support_enabled)
|
||||
str = bidi_l2v(str, 1);
|
||||
|
||||
while ((ch = *str++) != '\0' && x < LCD_WIDTH)
|
||||
{
|
||||
int width;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "system.h"
|
||||
#include "font.h"
|
||||
#include "hwcompat.h"
|
||||
#include "bidi.h"
|
||||
|
||||
/*** definitions ***/
|
||||
|
||||
|
@ -846,6 +847,9 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
|
|||
int ch;
|
||||
struct font* pf = font_get(curfont);
|
||||
|
||||
if (bidi_support_enabled)
|
||||
str = bidi_l2v(str, 1);
|
||||
|
||||
while ((ch = *str++) != '\0' && x < LCD_WIDTH)
|
||||
{
|
||||
int width;
|
||||
|
|
23
firmware/export/bidi.h
Normal file
23
firmware/export/bidi.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2005 by Gadi Cohen
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef BIDI_H
|
||||
extern unsigned char *bidi_l2v(const unsigned char *str, int orientation);
|
||||
extern bool bidi_support_enabled;
|
||||
extern void set_bidi_support(bool setting);
|
||||
#endif
|
Loading…
Reference in a new issue