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.tar.gz
rockbox-41a53d2c1c536d20823f357af887c9ff74991efd.zip
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 f8c0c33e19..c50a1269d4 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3238,3 +3238,9 @@ desc: in browse_id3
3238eng: "<No gain>" 3238eng: "<No gain>"
3239voice "" 3239voice ""
3240new: 3240new:
3241
3242id: LANG_BIDI_SUPPORT
3243desc: in settings_menu, option to enable reversal of hebrew/arabic text
3244eng: "BiDi Hebrew/Arabic"
3245voice ""
3246new:
diff --git a/apps/settings.c b/apps/settings.c
index d37e02692c..63e7a3b9d9 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -40,6 +40,7 @@
40#include "power.h" 40#include "power.h"
41#include "backlight.h" 41#include "backlight.h"
42#include "powermgmt.h" 42#include "powermgmt.h"
43#include "bidi.h"
43#include "status.h" 44#include "status.h"
44#include "atoi.h" 45#include "atoi.h"
45#include "screens.h" 46#include "screens.h"
@@ -265,10 +266,14 @@ static const struct bit_entry rtc_bits[] =
265 {1, S_O(remote_flip_display), false, "remote flip display", off_on }, 266 {1, S_O(remote_flip_display), false, "remote flip display", off_on },
266#endif 267#endif
267 268
269#ifdef HAVE_LCD_BITMAP /* move to LCD next time we bump version */
270 {1, S_O(bidi_support), false, "bidi hebrew/arabic", off_on },
271#endif
272
268 /* new stuff to be added here */ 273 /* new stuff to be added here */
269 /* If values are just added to the end, no need to bump the version. */ 274 /* If values are just added to the end, no need to bump the version. */
270 275
271 /* Current sum of bits: 268 (worst case, but w/o remote lcd) */ 276 /* Current sum of bits: 277 (worst case, but w/o remote lcd) */
272 /* Sum of all bit sizes must not grow beyond 288! */ 277 /* Sum of all bit sizes must not grow beyond 288! */
273}; 278};
274 279
@@ -820,6 +825,7 @@ void settings_apply(void)
820#endif 825#endif
821 826
822#ifdef HAVE_LCD_BITMAP 827#ifdef HAVE_LCD_BITMAP
828 set_bidi_support(global_settings.bidi_support);
823 lcd_set_invert_display(global_settings.invert); 829 lcd_set_invert_display(global_settings.invert);
824 lcd_set_flip(global_settings.flip_display); 830 lcd_set_flip(global_settings.flip_display);
825 button_set_flip(global_settings.flip_display); 831 button_set_flip(global_settings.flip_display);
diff --git a/apps/settings.h b/apps/settings.h
index e0a61bf21d..ff121868cb 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -197,6 +197,7 @@ struct user_settings
197 bool invert_cursor; /* invert the current file in dir browser and menu 197 bool invert_cursor; /* invert the current file in dir browser and menu
198 instead of using the default cursor */ 198 instead of using the default cursor */
199 bool flip_display; /* turn display (and button layout) by 180 degrees */ 199 bool flip_display; /* turn display (and button layout) by 180 degrees */
200 bool bidi_support; /* reverse hebrew/arabic chars: 0=off, 1=on */
200 int poweroff; /* power off timer */ 201 int poweroff; /* power off timer */
201 int backlight_timeout; /* backlight off timeout: 0-18 0=never, 202 int backlight_timeout; /* backlight off timeout: 0-18 0=never,
202 1=always, 203 1=always,
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 50f139637c..54267e99c0 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -38,6 +38,7 @@
38#include "fat.h" /* For dotfile settings */ 38#include "fat.h" /* For dotfile settings */
39#include "sleeptimer.h" 39#include "sleeptimer.h"
40#include "powermgmt.h" 40#include "powermgmt.h"
41#include "bidi.h"
41#include "rtc.h" 42#include "rtc.h"
42#include "ata.h" 43#include "ata.h"
43#include "tree.h" 44#include "tree.h"
@@ -279,6 +280,18 @@ static bool invert_cursor(void)
279} 280}
280 281
281/** 282/**
283 * Menu to reverse Hebrew and Arabic text according to BiDi algorythm
284 */
285static bool bidi_support(void)
286{
287 return set_bool_options( str(LANG_BIDI_SUPPORT),
288 &global_settings.bidi_support,
289 STR(LANG_SET_BOOL_YES),
290 STR(LANG_SET_BOOL_NO),
291 set_bidi_support);
292}
293
294/**
282 * Menu to configure the battery display on status bar 295 * Menu to configure the battery display on status bar
283 */ 296 */
284static bool battery_display(void) 297static bool battery_display(void)
@@ -1421,6 +1434,7 @@ static bool lcd_settings_menu(void)
1421 { ID2P(LANG_INVERT), invert }, 1434 { ID2P(LANG_INVERT), invert },
1422 { ID2P(LANG_FLIP_DISPLAY), flip_display }, 1435 { ID2P(LANG_FLIP_DISPLAY), flip_display },
1423 { ID2P(LANG_INVERT_CURSOR), invert_cursor }, 1436 { ID2P(LANG_INVERT_CURSOR), invert_cursor },
1437 { ID2P(LANG_BIDI_SUPPORT), bidi_support },
1424#endif 1438#endif
1425 }; 1439 };
1426 1440
diff --git a/docs/CREDITS b/docs/CREDITS
index 4c8b32fc16..2e7e064faf 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -129,3 +129,5 @@ Ryan Jackson
129Per Holmäng 129Per Holmäng
130Frederic Devernay 130Frederic Devernay
131José M. Fandiño 131José M. Fandiño
132Gadi Cohen
133Naftali Goldstein
diff --git a/firmware/SOURCES b/firmware/SOURCES
index be471fb51b..84f54e56a3 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -49,6 +49,7 @@ drivers/lcd-player-charset.c
49drivers/lcd-player.c 49drivers/lcd-player.c
50#endif 50#endif
51#ifdef HAVE_LCD_BITMAP 51#ifdef HAVE_LCD_BITMAP
52bidi.c
52#if LCD_DEPTH == 2 53#if LCD_DEPTH == 2
53drivers/lcd-h100.c 54drivers/lcd-h100.c
54#elif LCD_DEPTH == 1 55#elif LCD_DEPTH == 1
diff --git a/firmware/bidi.c b/firmware/bidi.c
new file mode 100644
index 0000000000..765d3dab24
--- /dev/null
+++ b/firmware/bidi.c
@@ -0,0 +1,184 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Gadi Cohen
11 *
12 * Largely based on php_hebrev by Zeev Suraski <zeev@php.net>
13 * Heavily modified by Gadi Cohen aka Kinslayer <dragon@wastelands.net>
14 *
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <ctype.h>
25#include "file.h"
26#include "lcd.h"
27
28#define _HEB_BUFFER_LENGTH MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2
29#define _HEB_BLOCK_TYPE_ENG 1
30#define _HEB_BLOCK_TYPE_HEB 0
31#define _HEB_ORIENTATION_LTR 1
32#define _HEB_ORIENTATION_RTL 0
33
34#define ischar(c) (((((unsigned char) c)>=193) && (((unsigned char) c)<=250)) ? 1 : 0)
35#define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0)
36#define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0)
37#define XOR(a,b) ((a||b) && !(a&&b))
38
39bool bidi_support_enabled = false;
40
41unsigned char *bidi_l2v(const unsigned char *str, int orientation)
42{
43 static unsigned char buf_heb_str[_HEB_BUFFER_LENGTH];
44 static unsigned char buf_broken_str[_HEB_BUFFER_LENGTH];
45 const unsigned char *tmp;
46 unsigned char *heb_str, *target, *opposite_target, *broken_str;
47 int block_start, block_end, block_type, block_length, i;
48 int block_ended;
49 long max_chars=0;
50 int begin, end, char_count, orig_begin;
51
52 if (!str || !*str)
53 return "";
54
55 tmp = str;
56 block_start=block_end=0;
57 block_ended=0;
58
59 heb_str = buf_heb_str;
60 if (orientation) {
61 target = heb_str;
62 opposite_target = heb_str + strlen(str);
63 } else {
64 target = heb_str + strlen(str);
65 opposite_target = heb_str;
66 *target = 0;
67 target--;
68 }
69
70 block_length=0;
71 if (ischar(*tmp))
72 block_type = _HEB_BLOCK_TYPE_HEB;
73 else
74 block_type = _HEB_BLOCK_TYPE_ENG;
75
76 do {
77 while((XOR(ischar((int)*(tmp+1)),block_type)
78 || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1))
79 || (int)*(tmp+1)=='\n')
80 && block_end<(int)strlen(str)-1) {
81 tmp++;
82 block_end++;
83 block_length++;
84 }
85
86 if (block_type != orientation) {
87 while ((_isblank((int)*tmp) || ispunct((int)*tmp))
88 && *tmp!='/' && *tmp!='-' && block_end>block_start) {
89 tmp--;
90 block_end--;
91 }
92 }
93
94 for (i=block_start; i<=block_end; i++) {
95 *target = (block_type == orientation) ? *(str+i) : *(str+block_end-i+block_start);
96 if (block_type!=orientation) {
97 switch (*target) {
98 case '(':
99 *target = ')';
100 break;
101 case ')':
102 *target = '(';
103 break;
104 default:
105 break;
106 }
107 }
108 target += orientation ? 1 : -1;
109 }
110 block_type = !block_type;
111 block_start=block_end+1;
112 } while(block_end<(int)strlen(str)-1);
113
114 broken_str = buf_broken_str;
115 begin=end=strlen(str)-1;
116 target = broken_str;
117
118 while (1) {
119 char_count=0;
120 while ((!max_chars || char_count<max_chars) && begin>0) {
121 char_count++;
122 begin--;
123 if (begin<=0 || _isnewline(heb_str[begin])) {
124 while(begin>0 && _isnewline(heb_str[begin-1])) {
125 begin--;
126 char_count++;
127 }
128 break;
129 }
130 }
131 if (char_count==max_chars) { /* try to avoid breaking words */
132 int new_char_count = char_count;
133 int new_begin = begin;
134
135 while (new_char_count>0) {
136 if (_isblank(heb_str[new_begin]) ||
137 _isnewline(heb_str[new_begin])) {
138 break;
139 }
140 new_begin++;
141 new_char_count--;
142 }
143 if (new_char_count>0) {
144 char_count=new_char_count;
145 begin=new_begin;
146 }
147 }
148 orig_begin=begin;
149
150 if (_isblank(heb_str[begin])) {
151 heb_str[begin]='\n';
152 }
153
154 /* skip leading newlines */
155 while (begin<=end && _isnewline(heb_str[begin])) {
156 begin++;
157 }
158
159 /* copy content */
160 for (i=begin; i<=end; i++) {
161 *target = heb_str[i];
162 target++;
163 }
164
165 for (i=orig_begin; i<=end && _isnewline(heb_str[i]); i++) {
166 *target = heb_str[i];
167 target++;
168 }
169 begin=orig_begin;
170
171 if (begin<=0) {
172 *target = 0;
173 break;
174 }
175 begin--;
176 end=begin;
177 }
178 return broken_str;
179}
180
181void set_bidi_support(bool setting)
182{
183 bidi_support_enabled = setting;
184}
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 5bdb08abd3..bfdceedc35 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -28,6 +28,7 @@
28#include "debug.h" 28#include "debug.h"
29#include "system.h" 29#include "system.h"
30#include "font.h" 30#include "font.h"
31#include "bidi.h"
31 32
32/*** definitions ***/ 33/*** definitions ***/
33 34
@@ -992,6 +993,9 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
992 int ch; 993 int ch;
993 struct font* pf = font_get(curfont); 994 struct font* pf = font_get(curfont);
994 995
996 if (bidi_support_enabled)
997 str = bidi_l2v(str, 1);
998
995 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 999 while ((ch = *str++) != '\0' && x < LCD_WIDTH)
996 { 1000 {
997 int width; 1001 int width;
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index cdeb4f2959..53640ce649 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -28,6 +28,7 @@
28#include "system.h" 28#include "system.h"
29#include "font.h" 29#include "font.h"
30#include "hwcompat.h" 30#include "hwcompat.h"
31#include "bidi.h"
31 32
32/*** definitions ***/ 33/*** definitions ***/
33 34
@@ -846,6 +847,9 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
846 int ch; 847 int ch;
847 struct font* pf = font_get(curfont); 848 struct font* pf = font_get(curfont);
848 849
850 if (bidi_support_enabled)
851 str = bidi_l2v(str, 1);
852
849 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 853 while ((ch = *str++) != '\0' && x < LCD_WIDTH)
850 { 854 {
851 int width; 855 int width;
diff --git a/firmware/export/bidi.h b/firmware/export/bidi.h
new file mode 100644
index 0000000000..88e2eeb07e
--- /dev/null
+++ b/firmware/export/bidi.h
@@ -0,0 +1,23 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Gadi Cohen
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef BIDI_H
20extern unsigned char *bidi_l2v(const unsigned char *str, int orientation);
21extern bool bidi_support_enabled;
22extern void set_bidi_support(bool setting);
23#endif