1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Gadi Cohen
12 * Largely based on php_hebrev by Zeev Suraski <zeev@php.net>
13 * Heavily modified by Gadi Cohen aka Kinslayer <dragon@wastelands.net>
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
29 #include "rbunicode.h"
31 #include "scroll_engine.h"
34 /* #define _HEB_BUFFER_LENGTH (MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2) * 2 */
35 #define _HEB_BLOCK_TYPE_ENG 1
36 #define _HEB_BLOCK_TYPE_HEB 0
37 #define _HEB_ORIENTATION_LTR 1
38 #define _HEB_ORIENTATION_RTL 0
40 #define ischar(c) ((c > 0x0589 && c < 0x0700) || \
41 (c >= 0xfb50 && c <= 0xfefc) ? 1 : 0)
42 #define _isblank(c) ((c==' ' || c=='\t') ? 1 : 0)
43 #define _isnewline(c) ((c=='\n' || c=='\r') ? 1 : 0)
44 #define XOR(a,b) ((a||b) && !(a&&b))
47 static const arab_t
* arab_lookup(unsigned short uchar
)
49 if (uchar
>= 0x621 && uchar
<= 0x63a)
50 return &(jointable
[uchar
- 0x621]);
51 if (uchar
>= 0x640 && uchar
<= 0x64a)
52 return &(jointable
[uchar
- 0x621 - 5]);
53 if (uchar
>= 0x671 && uchar
<= 0x6d5)
54 return &(jointable
[uchar
- 0x621 - 5 - 38]);
55 if (uchar
== 0x200D) /* Support for the zero-width joiner */
60 static void arabjoin(unsigned short * stringprt
, int length
)
62 bool connected
= false;
63 unsigned short * writeprt
= stringprt
;
65 const arab_t
* prev
= 0;
67 const arab_t
* ligature
= 0;
71 for (i
= 0; i
<= length
; i
++) {
72 cur
= arab_lookup(uchar
= *stringprt
++);
74 /* Skip non-arabic chars */
77 /* Finish the last char */
79 *writeprt
++ = prev
->final
;
82 *writeprt
++ = prev
->isolated
;
91 /* nothing to do for arabic char if the previous was non-arabic */
97 /* if it's LAM, check for LAM+ALEPH ligatures */
98 if (prev
->isolated
== 0xfedd) {
99 switch (cur
->isolated
) {
101 ligature
= &(lamaleph
[0]);
104 ligature
= &(lamaleph
[1]);
107 ligature
= &(lamaleph
[2]);
110 ligature
= &(lamaleph
[3]);
114 if (ligature
) { /* replace the 2 glyphs by their ligature */
118 if (connected
) { /* previous char has something connected to it */
119 if (prev
->medial
&& cur
->final
) /* Can we connect to it? */
120 *writeprt
++ = prev
->medial
;
122 *writeprt
++ = prev
->final
;
126 if (prev
->initial
&& cur
->final
) { /* Can we connect to it? */
127 *writeprt
++ = prev
->initial
;
130 *writeprt
++ = prev
->isolated
;
136 #endif /* !BOOTLOADER */
138 unsigned short *bidi_l2v(const unsigned char *str
, int orientation
)
140 static unsigned short utf16_buf
[SCROLL_LINE_SIZE
];
141 unsigned short *target
, *tmp
;
143 static unsigned short bidi_buf
[SCROLL_LINE_SIZE
];
144 unsigned short *heb_str
; /* *broken_str */
145 int block_start
, block_end
, block_type
, block_length
, i
;
146 int length
= utf8length(str
);
150 int begin, end, char_count, orig_begin;
154 target
= tmp
= utf16_buf
;
156 str
= utf8decode(str
, target
++);
163 #else /* !BOOTLOADER */
164 if (target
== utf16_buf
) /* empty string */
167 /* properly join any arabic chars */
168 arabjoin(utf16_buf
, length
);
170 block_start
=block_end
=block_length
=0;
176 target
= heb_str
+ length
;
182 block_type
= _HEB_BLOCK_TYPE_HEB
;
184 block_type
= _HEB_BLOCK_TYPE_ENG
;
187 while((XOR(ischar(*(tmp
+1)),block_type
)
188 || _isblank(*(tmp
+1)) || ispunct((int)*(tmp
+1))
190 && block_end
< length
-1) {
196 if (block_type
!= orientation
) {
197 while ((_isblank(*tmp
) || ispunct((int)*tmp
))
198 && *tmp
!='/' && *tmp
!='-' && block_end
>block_start
) {
204 for (i
=block_start
; i
<=block_end
; i
++) {
205 *target
= (block_type
== orientation
) ?
206 *(utf16_buf
+i
) : *(utf16_buf
+block_end
-i
+block_start
);
207 if (block_type
!=orientation
) {
219 target
+= orientation
? 1 : -1;
221 block_type
= !block_type
;
222 block_start
=block_end
+1;
223 } while(block_end
<length
-1);
227 #if 0 /* Is this code really necessary? */
228 broken_str
= utf16_buf
;
234 while ((!max_chars
|| char_count
<max_chars
) && begin
>0) {
237 if (begin
<=0 || _isnewline(heb_str
[begin
])) {
238 while(begin
>0 && _isnewline(heb_str
[begin
-1])) {
245 if (char_count
==max_chars
) { /* try to avoid breaking words */
246 int new_char_count
= char_count
;
247 int new_begin
= begin
;
249 while (new_char_count
>0) {
250 if (_isblank(heb_str
[new_begin
]) ||
251 _isnewline(heb_str
[new_begin
])) {
257 if (new_char_count
>0) {
258 char_count
=new_char_count
;
264 /* if (_isblank(heb_str[begin])) {
268 /* skip leading newlines */
269 while (begin
<=end
&& _isnewline(heb_str
[begin
])) {
274 for (i
=begin
; i
<=end
; i
++) {
275 *target
= heb_str
[i
];
279 for (i
=orig_begin
; i
<=end
&& _isnewline(heb_str
[i
]); i
++) {
280 *target
= heb_str
[i
];
295 #endif /* !BOOTLOADER */