summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2005-08-08 19:23:28 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2005-08-08 19:23:28 +0000
commit41a53d2c1c536d20823f357af887c9ff74991efd (patch)
tree365987aa7fdada4786fc280b50319d0cb1bb2acb
parent1874a33298f6b639893e4bc8e556fd71e2c068d3 (diff)
downloadrockbox-41a53d2c1c536d20823f357af887c9ff74991efd.zip
rockbox-41a53d2c1c536d20823f357af887c9ff74991efd.tar.gz
rockbox-41a53d2c1c536d20823f357af887c9ff74991efd.tar.bz2
rockbox-41a53d2c1c536d20823f357af887c9ff74991efd.tar.xz
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
-rw-r--r--apps/lang/english.lang6
-rw-r--r--apps/settings.c8
-rw-r--r--apps/settings.h1
-rw-r--r--apps/settings_menu.c14
-rw-r--r--docs/CREDITS2
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/bidi.c184
-rw-r--r--firmware/drivers/lcd-h100.c4
-rw-r--r--firmware/drivers/lcd-recorder.c4
-rw-r--r--firmware/export/bidi.h23
10 files changed, 246 insertions, 1 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index f8c0c33..c50a126 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -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:
diff --git a/apps/settings.c b/apps/settings.c
index d37e026..63e7a3b 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -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);
diff --git a/apps/settings.h b/apps/settings.h
index e0a61bf..ff12186 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -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,
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 50f1396..54267e9 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -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"
@@ -279,6 +280,18 @@ static bool invert_cursor(void)
}
/**
+ * 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
*/
static bool battery_display(void)
@@ -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
};
diff --git a/docs/CREDITS b/docs/CREDITS
index 4c8b32f..2e7e064 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -129,3 +129,5 @@ Ryan Jackson
Per Holmäng
Frederic Devernay
José M. Fandiño
+Gadi Cohen
+Naftali Goldstein
diff --git a/firmware/SOURCES b/firmware/SOURCES
index be471fb..84f54e5 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -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
diff --git a/firmware/bidi.c b/firmware/bidi.c
new file mode 100644
index 0000000..765d3da
--- /dev/null
+++ b/firmware/bidi.c
@@ -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;
+}
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 5bdb08a..bfdceed 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -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;
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index cdeb4f2..53640ce 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -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;
diff --git a/firmware/export/bidi.h b/firmware/export/bidi.h
new file mode 100644
index 0000000..88e2eeb
--- /dev/null
+++ b/firmware/export/bidi.h
@@ -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