diff options
| author | Tomer Shalev <shalev.tomer@gmail.com> | 2010-04-07 17:22:16 +0000 |
|---|---|---|
| committer | Tomer Shalev <shalev.tomer@gmail.com> | 2010-04-07 17:22:16 +0000 |
| commit | 9e4bd41e416a2d48284947e9ccc09844d3db93ee (patch) | |
| tree | d575c2b63730c4525a79ad42fe511ba03809a651 /apps | |
| parent | 8b904e2bb4e92a6c4cb97db7d2c4e43a624b4e28 (diff) | |
| download | rockbox-9e4bd41e416a2d48284947e9ccc09844d3db93ee.zip rockbox-9e4bd41e416a2d48284947e9ccc09844d3db93ee.tar.gz rockbox-9e4bd41e416a2d48284947e9ccc09844d3db93ee.tar.bz2 rockbox-9e4bd41e416a2d48284947e9ccc09844d3db93ee.tar.xz | |
Text viewer: Fix RTL languages and diacritic characters support
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25515 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/plugin.c | 5 | ||||
| -rw-r--r-- | apps/plugin.h | 6 | ||||
| -rw-r--r-- | apps/plugins/viewer.c | 169 |
3 files changed, 125 insertions, 55 deletions
diff --git a/apps/plugin.c b/apps/plugin.c index c9f649b..2f54c0d 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -41,6 +41,7 @@ #include "storage.h" #include "pcmbuf.h" #include "errno.h" +#include "diacritic.h" #if CONFIG_CHARGING #include "power.h" @@ -710,6 +711,10 @@ static const struct plugin_api rockbox_api = { appsversion, /* new stuff at the end, sort into place next time the API gets incompatible */ + +#ifdef HAVE_LCD_BITMAP + is_diacritic, +#endif }; int plugin_load(const char* plugin, const void* parameter) diff --git a/apps/plugin.h b/apps/plugin.h index c3466bc..464a581 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -135,7 +135,7 @@ void* plugin_get_buffer(size_t *buffer_size); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 182 +#define PLUGIN_API_VERSION 183 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any @@ -863,6 +863,10 @@ struct plugin_api { const char *appsversion; /* new stuff at the end, sort into place next time the API gets incompatible */ + +#ifdef HAVE_LCD_BITMAP + int (*is_diacritic)(const unsigned short char_code, bool *is_rtl); +#endif }; /* plugin header */ diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c index 80b279c..8751b43 100644 --- a/apps/plugins/viewer.c +++ b/apps/plugins/viewer.c @@ -636,11 +636,14 @@ static int bookmark_count; static bool is_bom = false; /* calculate the width of a UCS character (zero width for diacritics) */ -static int glyph_width(int ch) +static int glyph_width(unsigned short ch) { if (ch == 0) ch = ' '; + if (rb->is_diacritic(ch, NULL)) + return 0; + #ifdef HAVE_LCD_BITMAP return rb->font_get_width(pf, ch); #else @@ -730,6 +733,10 @@ static int col = 0; static inline void advance_conters(unsigned short ch, int* k, int* width) { + /* diacritics do not count */ + if (rb->is_diacritic(ch, NULL)) + return; + *width += glyph_width(ch); (*k)++; } @@ -760,11 +767,18 @@ static unsigned char* crop_at_width(const unsigned char* p) static unsigned char* find_first_feed(const unsigned char* p, int size) { - int i; + int s = 0; + unsigned short ch; + const unsigned char *oldp = p; - for (i=0; i < size; i++) - if (p[i] == 0) - return (unsigned char*) p+i; + while(s <= size) + { + if (*p == 0) + return (unsigned char*)p; + oldp = p; + p = get_ucs(p, &ch); + s += (p - oldp); + } return NULL; } @@ -786,18 +800,21 @@ static unsigned char* find_last_space(const unsigned char* p, int size) k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1; - if (!BUFFER_OOB(&p[size])) - for (j=k; j < ((int) sizeof(line_break)) - 1; j++) - if (p[size] == line_break[j]) - return (unsigned char*) p+size; + i = size; + if (!BUFFER_OOB(&p[i])) + for (j=k; j < ((int) sizeof(line_break)) - 1; j++) { + if (p[i] == line_break[j]) + return (unsigned char*) p+i; + } - for (i=size-1; i>=0; i--) - for (j=k; j < (int) sizeof(line_break); j++) - { - if (!((p[i] == '-') && (prefs.word_mode == WRAP))) + if (prefs.word_mode == WRAP) { + for (i=size-1; i>=0; i--) { + for (j=k; j < (int) sizeof(line_break) - 1; j++) { if (p[i] == line_break[j]) return (unsigned char*) p+i; + } } + } return NULL; } @@ -805,9 +822,9 @@ static unsigned char* find_last_space(const unsigned char* p, int size) static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short) { const unsigned char *next_line = NULL; - int size, i, j, k, width, search_len, spaces, newlines; + int size, i, j, j_next, j_prev, k, width, search_len, spaces, newlines; bool first_chars; - unsigned char c; + unsigned short ch; if (is_short != NULL) *is_short = true; @@ -829,16 +846,25 @@ static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_sho or possibly set next_line at second hard return in a row. */ next_line = NULL; first_chars=true; - for (j=k=width=spaces=newlines=0; ; j++) { + j_next=j=k=width=spaces=newlines=0; + while (1) { + const unsigned char *p, *oldp; + + j_prev = j; + j = j_next; + if (BUFFER_OOB(cur_line+j)) return NULL; if (line_is_full(k, width)) { - size = search_len = j; + size = search_len = j_prev; break; } - c = cur_line[j]; - switch (c) { + oldp = p = &cur_line[j]; + p = get_ucs(p, &ch); + j_next = j + (p - oldp); + + switch (ch) { case ' ': if (prefs.line_mode == REFLOW) { if (newlines > 0) { @@ -909,14 +935,18 @@ static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_sho if (prefs.word_mode == WRAP) /* Find last space */ next_line = find_last_space(cur_line, size); - if (next_line == NULL) + if (next_line == NULL) { next_line = crop_at_width(cur_line); - else - if (prefs.word_mode == WRAP) - for (i=0; - i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line); - i++) + } + else { + if (prefs.word_mode == WRAP) { + for (i=0;i<WRAP_TRIM;i++) { + if (!(isspace(next_line[0]) && !BUFFER_OOB(next_line))) + break; next_line++; + } + } + } } if (prefs.line_mode == EXPAND) @@ -1230,18 +1260,26 @@ static void viewer_show_footer(void) } #endif +/* We draw a diacritic char over a non-diacritic one. Therefore, such chars are + * not considered to occupy space, therefore buffers might have more than + * max_columns characters. The DIACRITIC_FACTOR is the max ratio between all + * characters and non-diacritic characters in the buffer + */ +#define DIACRITIC_FACTOR 2 + static void viewer_draw(int col) { int i, j, k, line_len, line_width, spaces, left_col=0; - int width, extra_spaces, indent_spaces, spaces_per_word; + int width, extra_spaces, indent_spaces, spaces_per_word, spaces_width; bool multiple_spacing, line_is_short; unsigned short ch; unsigned char *str, *oldstr; unsigned char *line_begin; unsigned char *line_end; unsigned char c; - unsigned char scratch_buffer[max_columns + 1]; - unsigned char utf8_buffer[max_columns*4 + 1]; + int max_chars = max_columns * DIACRITIC_FACTOR; + unsigned char scratch_buffer[max_chars + 1]; + unsigned char utf8_buffer[max_chars * 4 + 1]; unsigned char *endptr; /* If col==-1 do all calculations but don't display */ @@ -1287,11 +1325,33 @@ static void viewer_draw(int col) oldstr = str; str = crop_at_width(str); j++; + if (oldstr == str) + { + oldstr = line_end; + break; + } } + /* width of un-displayed part of the line */ line_width = j*draw_columns; + spaces_width = 0; while (oldstr < line_end) { oldstr = get_ucs(oldstr, &ch); - line_width += glyph_width(ch); + /* add width of displayed part of the line */ + if (ch) + { + int dw = glyph_width(ch); + + /* avoid counting spaces at the end of the line */ + if (ch == ' ') + { + spaces_width += dw; + } + else + { + line_width += dw + spaces_width; + spaces_width = 0; + } + } } if (prefs.line_mode == JOIN) { @@ -1303,7 +1363,7 @@ static void viewer_draw(int col) line_len--; } for (j=k=spaces=0; j < line_len; j++) { - if (k == max_columns) + if (k == max_chars) break; c = line_begin[j]; @@ -1319,7 +1379,7 @@ static void viewer_draw(int col) while (spaces) { spaces--; scratch_buffer[k++] = ' '; - if (k == max_columns - 1) + if (k == max_chars - 1) break; } scratch_buffer[k++] = c; @@ -1388,7 +1448,7 @@ static void viewer_draw(int col) multiple_spacing = false; for (j=k=spaces=0; j < line_len; j++) { - if (k == max_columns) + if (k == max_chars) break; c = line_begin[j]; @@ -1420,31 +1480,32 @@ static void viewer_draw(int col) } } else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */ - if (col != -1) - if (line_width > col) { - str = oldstr = line_begin; - k = col; - width = 0; - while( (width<draw_columns) && (oldstr<line_end) ) - { - oldstr = get_ucs(oldstr, &ch); - if (k > 0) { - k -= glyph_width(ch); - line_begin = oldstr; - } else { - width += glyph_width(ch); - } + if ((col != -1) && (line_width > col)) { + str = oldstr = line_begin; + k = col; + width = 0; + while( (width<draw_columns) && (oldstr<line_end) ) + { + oldstr = get_ucs(oldstr, &ch); + if (k > 0) { + k -= glyph_width(ch); + line_begin = oldstr; + } else { + width += glyph_width(ch); } - - if(prefs.view_mode==WIDE) - endptr = rb->iso_decode(line_begin, utf8_buffer, - prefs.encoding, oldstr-line_begin); - else - endptr = rb->iso_decode(line_begin, utf8_buffer, - prefs.encoding, line_end-line_begin); - *endptr = 0; } + + if(prefs.view_mode==WIDE) + endptr = rb->iso_decode(line_begin, utf8_buffer, + prefs.encoding, oldstr-line_begin); + else + endptr = rb->iso_decode(line_begin, utf8_buffer, + prefs.encoding, line_end-line_begin); + *endptr = 0; + } } + + /* display on screen the displayed part of the line */ if (col != -1 && line_width > col) { int dpage = (cline+i <= display_lines)?cpage:cpage+1; |