From 41a53d2c1c536d20823f357af887c9ff74991efd Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Mon, 8 Aug 2005 19:23:28 +0000 Subject: 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 --- firmware/SOURCES | 1 + firmware/bidi.c | 184 ++++++++++++++++++++++++++++++++++++++++ firmware/drivers/lcd-h100.c | 4 + firmware/drivers/lcd-recorder.c | 4 + firmware/export/bidi.h | 23 +++++ 5 files changed, 216 insertions(+) create mode 100644 firmware/bidi.c create mode 100644 firmware/export/bidi.h (limited to 'firmware') 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 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 0000000000..765d3dab24 --- /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 + * Heavily modified by Gadi Cohen aka Kinslayer + * + * 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 +#include +#include +#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_count0) { + 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 5bdb08abd3..bfdceedc35 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 cdeb4f2959..53640ce649 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 0000000000..88e2eeb07e --- /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 -- cgit v1.2.3