diff options
Diffstat (limited to 'firmware/bidi.c')
-rw-r--r-- | firmware/bidi.c | 186 |
1 files changed, 140 insertions, 46 deletions
diff --git a/firmware/bidi.c b/firmware/bidi.c index dcb44999ec..93c1dd0951 100644 --- a/firmware/bidi.c +++ b/firmware/bidi.c | |||
@@ -24,75 +24,168 @@ | |||
24 | #include <ctype.h> | 24 | #include <ctype.h> |
25 | #include "file.h" | 25 | #include "file.h" |
26 | #include "lcd.h" | 26 | #include "lcd.h" |
27 | #include "rbunicode.h" | ||
28 | #include "arabjoin.h" | ||
27 | 29 | ||
28 | #define _HEB_BUFFER_LENGTH MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2 | 30 | //#define _HEB_BUFFER_LENGTH (MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2) * 2 |
29 | #define _HEB_BLOCK_TYPE_ENG 1 | 31 | #define _HEB_BLOCK_TYPE_ENG 1 |
30 | #define _HEB_BLOCK_TYPE_HEB 0 | 32 | #define _HEB_BLOCK_TYPE_HEB 0 |
31 | #define _HEB_ORIENTATION_LTR 1 | 33 | #define _HEB_ORIENTATION_LTR 1 |
32 | #define _HEB_ORIENTATION_RTL 0 | 34 | #define _HEB_ORIENTATION_RTL 0 |
33 | 35 | ||
34 | #define ischar(c) (((((unsigned char) c)>=193) && (((unsigned char) c)<=250)) ? 1 : 0) | 36 | #define ischar(c) ((c > 0x0589 && c < 0x0700) || (c >= 0xfb50 && c <= 0xfefc) ? 1 : 0) |
35 | #define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0) | 37 | #define _isblank(c) ((c==' ' || c=='\t') ? 1 : 0) |
36 | #define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0) | 38 | #define _isnewline(c) ((c=='\n' || c=='\r') ? 1 : 0) |
37 | #define XOR(a,b) ((a||b) && !(a&&b)) | 39 | #define XOR(a,b) ((a||b) && !(a&&b)) |
38 | 40 | ||
39 | bool bidi_support_enabled = false; | 41 | arab_t * arab_lookup(unsigned short uchar) |
42 | { | ||
43 | if (uchar >= 0x621 && uchar <= 0x63a) | ||
44 | return &(jointable[uchar - 0x621]); | ||
45 | if (uchar >= 0x640 && uchar <= 0x64a) | ||
46 | return &(jointable[uchar - 0x621 - 5]); | ||
47 | if (uchar >= 0x671 && uchar <= 0x6d5) | ||
48 | return &(jointable[uchar - 0x621 - 5 - 38]); | ||
49 | if (uchar == 0x200D) /* Support for the zero-width joiner */ | ||
50 | return ‍ | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | void arabjoin(unsigned short * stringprt, int length){ | ||
55 | |||
56 | bool connected = false; | ||
57 | unsigned short * writeprt = stringprt; | ||
58 | |||
59 | arab_t * prev = 0; | ||
60 | arab_t * cur; | ||
61 | arab_t * ligature = 0; | ||
62 | short uchar; | ||
40 | 63 | ||
41 | unsigned char *bidi_l2v(const char *str, int orientation) | 64 | int i; |
65 | for (i = 0; i <= length; i++) { | ||
66 | cur = arab_lookup(uchar = *stringprt++); | ||
67 | |||
68 | /* Skip non-arabic chars */ | ||
69 | if (cur == 0) { | ||
70 | if (prev) { | ||
71 | /* Finish the last char */ | ||
72 | if (connected) { | ||
73 | *writeprt++ = prev->final; | ||
74 | connected = false; | ||
75 | } else | ||
76 | *writeprt++ = prev->isolated; | ||
77 | prev = 0; | ||
78 | *writeprt++ = uchar; | ||
79 | } else { | ||
80 | *writeprt++ = uchar; | ||
81 | } | ||
82 | continue; | ||
83 | } | ||
84 | |||
85 | /* nothing to do for arabic char if the previous was non-arabic */ | ||
86 | if (prev == 0) { | ||
87 | prev = cur; | ||
88 | continue; | ||
89 | } | ||
90 | |||
91 | /* if it's LAM, check for LAM+ALEPH ligatures */ | ||
92 | if (prev->isolated == 0xfedd) { | ||
93 | switch (cur->isolated) { | ||
94 | case 0xfe8d: | ||
95 | ligature = &(lamaleph[0]); | ||
96 | break; | ||
97 | case 0xfe87: | ||
98 | ligature = &(lamaleph[1]); | ||
99 | break; | ||
100 | case 0xfe83: | ||
101 | ligature = &(lamaleph[2]); | ||
102 | break; | ||
103 | case 0xfe81: | ||
104 | ligature = &(lamaleph[3]); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | if (ligature) { /* replace the 2 glyphs by their ligature */ | ||
109 | prev = ligature; | ||
110 | ligature = 0; | ||
111 | } else { | ||
112 | if (connected) { /* previous char has something connected to it */ | ||
113 | if (prev->medial && cur->final) /* Can we connect to it? */ | ||
114 | *writeprt++ = prev->medial; | ||
115 | else { | ||
116 | *writeprt++ = prev->final; | ||
117 | connected = false; | ||
118 | } | ||
119 | } else { | ||
120 | if (prev->initial && cur->final) { /* Can we connect to it? */ | ||
121 | *writeprt++ = prev->initial; | ||
122 | connected = true; | ||
123 | } else | ||
124 | *writeprt++ = prev->isolated; | ||
125 | } | ||
126 | prev = cur; | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | unsigned short *bidi_l2v(const unsigned char *str, int orientation) | ||
42 | { | 132 | { |
43 | static unsigned char buf_heb_str[_HEB_BUFFER_LENGTH]; | 133 | int length = utf8length(str); |
44 | static unsigned char buf_broken_str[_HEB_BUFFER_LENGTH]; | 134 | static unsigned short utf16_buf[MAX_PATH+1]; |
45 | const unsigned char *tmp; | 135 | static unsigned short bidi_buf[MAX_PATH+1]; |
46 | unsigned char *heb_str, *target, *opposite_target, *broken_str; | 136 | unsigned short *heb_str, *target, *tmp; // *broken_str |
47 | int block_start, block_end, block_type, block_length, i; | 137 | int block_start, block_end, block_type, block_length, i; |
48 | int block_ended; | 138 | //long max_chars=0; |
49 | long max_chars=0; | 139 | //int begin, end, char_count, orig_begin; |
50 | int begin, end, char_count, orig_begin; | ||
51 | 140 | ||
52 | if (!str || !*str) | 141 | if (!str || !*str) |
53 | return (unsigned char *)""; | 142 | return &(unsigned short){0}; |
143 | |||
144 | //tmp = str; | ||
145 | target = tmp = utf16_buf; | ||
146 | while (*str) | ||
147 | str = utf8decode(str, target++); | ||
148 | *target = 0; | ||
54 | 149 | ||
55 | tmp = (unsigned char *)str; | 150 | /* properly join any arabic chars */ |
56 | block_start=block_end=0; | 151 | arabjoin(utf16_buf, length); |
57 | block_ended=0; | ||
58 | 152 | ||
59 | heb_str = buf_heb_str; | 153 | block_start=block_end=block_length=0; |
154 | |||
155 | heb_str = bidi_buf; | ||
60 | if (orientation) { | 156 | if (orientation) { |
61 | target = heb_str; | 157 | target = heb_str; |
62 | opposite_target = heb_str + strlen(str); | ||
63 | } else { | 158 | } else { |
64 | target = heb_str + strlen(str); | 159 | target = heb_str + length; |
65 | opposite_target = heb_str; | ||
66 | *target = 0; | 160 | *target = 0; |
67 | target--; | 161 | target--; |
68 | } | 162 | } |
69 | 163 | ||
70 | block_length=0; | ||
71 | if (ischar(*tmp)) | 164 | if (ischar(*tmp)) |
72 | block_type = _HEB_BLOCK_TYPE_HEB; | 165 | block_type = _HEB_BLOCK_TYPE_HEB; |
73 | else | 166 | else |
74 | block_type = _HEB_BLOCK_TYPE_ENG; | 167 | block_type = _HEB_BLOCK_TYPE_ENG; |
75 | 168 | ||
76 | do { | 169 | do { |
77 | while((XOR(ischar((int)*(tmp+1)),block_type) | 170 | while((XOR(ischar(*(tmp+1)),block_type) |
78 | || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) | 171 | || _isblank(*(tmp+1)) || ispunct((int)*(tmp+1)) |
79 | || (int)*(tmp+1)=='\n') | 172 | || *(tmp+1)=='\n') |
80 | && block_end<(int)strlen(str)-1) { | 173 | && block_end < length-1) { |
81 | tmp++; | 174 | tmp++; |
82 | block_end++; | 175 | block_end++; |
83 | block_length++; | 176 | block_length++; |
84 | } | 177 | } |
85 | 178 | ||
86 | if (block_type != orientation) { | 179 | if (block_type != orientation) { |
87 | while ((_isblank((int)*tmp) || ispunct((int)*tmp)) | 180 | while ((_isblank(*tmp) || ispunct((int)*tmp)) |
88 | && *tmp!='/' && *tmp!='-' && block_end>block_start) { | 181 | && *tmp!='/' && *tmp!='-' && block_end>block_start) { |
89 | tmp--; | 182 | tmp--; |
90 | block_end--; | 183 | block_end--; |
91 | } | 184 | } |
92 | } | 185 | } |
93 | 186 | ||
94 | for (i=block_start; i<=block_end; i++) { | 187 | for (i=block_start; i<=block_end; i++) { |
95 | *target = (block_type == orientation) ? *(str+i) : *(str+block_end-i+block_start); | 188 | *target = (block_type == orientation) ? *(utf16_buf+i) : *(utf16_buf+block_end-i+block_start); |
96 | if (block_type!=orientation) { | 189 | if (block_type!=orientation) { |
97 | switch (*target) { | 190 | switch (*target) { |
98 | case '(': | 191 | case '(': |
@@ -109,12 +202,15 @@ unsigned char *bidi_l2v(const char *str, int orientation) | |||
109 | } | 202 | } |
110 | block_type = !block_type; | 203 | block_type = !block_type; |
111 | block_start=block_end+1; | 204 | block_start=block_end+1; |
112 | } while(block_end<(int)strlen(str)-1); | 205 | } while(block_end<length-1); |
113 | 206 | ||
114 | broken_str = buf_broken_str; | 207 | *target = 0; |
115 | begin=end=strlen(str)-1; | 208 | |
209 | #if 0 /* Is this code really necessary? */ | ||
210 | broken_str = utf16_buf; | ||
211 | begin=end=length-1; | ||
116 | target = broken_str; | 212 | target = broken_str; |
117 | 213 | ||
118 | while (1) { | 214 | while (1) { |
119 | char_count=0; | 215 | char_count=0; |
120 | while ((!max_chars || char_count<max_chars) && begin>0) { | 216 | while ((!max_chars || char_count<max_chars) && begin>0) { |
@@ -147,9 +243,9 @@ unsigned char *bidi_l2v(const char *str, int orientation) | |||
147 | } | 243 | } |
148 | orig_begin=begin; | 244 | orig_begin=begin; |
149 | 245 | ||
150 | if (_isblank(heb_str[begin])) { | 246 | /* if (_isblank(heb_str[begin])) { |
151 | heb_str[begin]='\n'; | 247 | heb_str[begin]='\n'; |
152 | } | 248 | } */ |
153 | 249 | ||
154 | /* skip leading newlines */ | 250 | /* skip leading newlines */ |
155 | while (begin<=end && _isnewline(heb_str[begin])) { | 251 | while (begin<=end && _isnewline(heb_str[begin])) { |
@@ -176,9 +272,7 @@ unsigned char *bidi_l2v(const char *str, int orientation) | |||
176 | end=begin; | 272 | end=begin; |
177 | } | 273 | } |
178 | return broken_str; | 274 | return broken_str; |
275 | #endif | ||
276 | return heb_str; | ||
179 | } | 277 | } |
180 | 278 | ||
181 | void set_bidi_support(bool setting) | ||
182 | { | ||
183 | bidi_support_enabled = setting; | ||
184 | } | ||