1
0
Fork 0
forked from len0rd/rockbox

Text viewer: Fix RTL languages and diacritic characters support

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25515 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Tomer Shalev 2010-04-07 17:22:16 +00:00
parent 8b904e2bb4
commit 9e4bd41e41
3 changed files with 125 additions and 55 deletions

View file

@ -41,6 +41,7 @@
#include "storage.h" #include "storage.h"
#include "pcmbuf.h" #include "pcmbuf.h"
#include "errno.h" #include "errno.h"
#include "diacritic.h"
#if CONFIG_CHARGING #if CONFIG_CHARGING
#include "power.h" #include "power.h"
@ -710,6 +711,10 @@ static const struct plugin_api rockbox_api = {
appsversion, appsversion,
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
the API gets incompatible */ the API gets incompatible */
#ifdef HAVE_LCD_BITMAP
is_diacritic,
#endif
}; };
int plugin_load(const char* plugin, const void* parameter) int plugin_load(const char* plugin, const void* parameter)

View file

@ -135,7 +135,7 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* 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 /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
@ -863,6 +863,10 @@ struct plugin_api {
const char *appsversion; const char *appsversion;
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
the API gets incompatible */ the API gets incompatible */
#ifdef HAVE_LCD_BITMAP
int (*is_diacritic)(const unsigned short char_code, bool *is_rtl);
#endif
}; };
/* plugin header */ /* plugin header */

View file

@ -636,11 +636,14 @@ static int bookmark_count;
static bool is_bom = false; static bool is_bom = false;
/* calculate the width of a UCS character (zero width for diacritics) */ /* 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) if (ch == 0)
ch = ' '; ch = ' ';
if (rb->is_diacritic(ch, NULL))
return 0;
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
return rb->font_get_width(pf, ch); return rb->font_get_width(pf, ch);
#else #else
@ -730,6 +733,10 @@ static int col = 0;
static inline void advance_conters(unsigned short ch, int* k, int* width) 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); *width += glyph_width(ch);
(*k)++; (*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) 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++) while(s <= size)
if (p[i] == 0) {
return (unsigned char*) p+i; if (*p == 0)
return (unsigned char*)p;
oldp = p;
p = get_ucs(p, &ch);
s += (p - oldp);
}
return NULL; 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; k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1;
if (!BUFFER_OOB(&p[size])) i = size;
for (j=k; j < ((int) sizeof(line_break)) - 1; j++) if (!BUFFER_OOB(&p[i]))
if (p[size] == line_break[j]) for (j=k; j < ((int) sizeof(line_break)) - 1; j++) {
return (unsigned char*) p+size; if (p[i] == line_break[j])
return (unsigned char*) p+i;
}
for (i=size-1; i>=0; i--) if (prefs.word_mode == WRAP) {
for (j=k; j < (int) sizeof(line_break); j++) for (i=size-1; i>=0; i--) {
{ for (j=k; j < (int) sizeof(line_break) - 1; j++) {
if (!((p[i] == '-') && (prefs.word_mode == WRAP)))
if (p[i] == line_break[j]) if (p[i] == line_break[j])
return (unsigned char*) p+i; return (unsigned char*) p+i;
}
} }
}
return NULL; 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) static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short)
{ {
const unsigned char *next_line = NULL; 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; bool first_chars;
unsigned char c; unsigned short ch;
if (is_short != NULL) if (is_short != NULL)
*is_short = true; *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. */ or possibly set next_line at second hard return in a row. */
next_line = NULL; next_line = NULL;
first_chars=true; 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)) if (BUFFER_OOB(cur_line+j))
return NULL; return NULL;
if (line_is_full(k, width)) { if (line_is_full(k, width)) {
size = search_len = j; size = search_len = j_prev;
break; break;
} }
c = cur_line[j]; oldp = p = &cur_line[j];
switch (c) { p = get_ucs(p, &ch);
j_next = j + (p - oldp);
switch (ch) {
case ' ': case ' ':
if (prefs.line_mode == REFLOW) { if (prefs.line_mode == REFLOW) {
if (newlines > 0) { 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 */ if (prefs.word_mode == WRAP) /* Find last space */
next_line = find_last_space(cur_line, size); next_line = find_last_space(cur_line, size);
if (next_line == NULL) if (next_line == NULL) {
next_line = crop_at_width(cur_line); next_line = crop_at_width(cur_line);
else }
if (prefs.word_mode == WRAP) else {
for (i=0; if (prefs.word_mode == WRAP) {
i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line); for (i=0;i<WRAP_TRIM;i++) {
i++) if (!(isspace(next_line[0]) && !BUFFER_OOB(next_line)))
break;
next_line++; next_line++;
}
}
}
} }
if (prefs.line_mode == EXPAND) if (prefs.line_mode == EXPAND)
@ -1230,18 +1260,26 @@ static void viewer_show_footer(void)
} }
#endif #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) static void viewer_draw(int col)
{ {
int i, j, k, line_len, line_width, spaces, left_col=0; 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; bool multiple_spacing, line_is_short;
unsigned short ch; unsigned short ch;
unsigned char *str, *oldstr; unsigned char *str, *oldstr;
unsigned char *line_begin; unsigned char *line_begin;
unsigned char *line_end; unsigned char *line_end;
unsigned char c; unsigned char c;
unsigned char scratch_buffer[max_columns + 1]; int max_chars = max_columns * DIACRITIC_FACTOR;
unsigned char utf8_buffer[max_columns*4 + 1]; unsigned char scratch_buffer[max_chars + 1];
unsigned char utf8_buffer[max_chars * 4 + 1];
unsigned char *endptr; unsigned char *endptr;
/* If col==-1 do all calculations but don't display */ /* If col==-1 do all calculations but don't display */
@ -1287,11 +1325,33 @@ static void viewer_draw(int col)
oldstr = str; oldstr = str;
str = crop_at_width(str); str = crop_at_width(str);
j++; j++;
if (oldstr == str)
{
oldstr = line_end;
break;
}
} }
/* width of un-displayed part of the line */
line_width = j*draw_columns; line_width = j*draw_columns;
spaces_width = 0;
while (oldstr < line_end) { while (oldstr < line_end) {
oldstr = get_ucs(oldstr, &ch); 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) { if (prefs.line_mode == JOIN) {
@ -1303,7 +1363,7 @@ static void viewer_draw(int col)
line_len--; line_len--;
} }
for (j=k=spaces=0; j < line_len; j++) { for (j=k=spaces=0; j < line_len; j++) {
if (k == max_columns) if (k == max_chars)
break; break;
c = line_begin[j]; c = line_begin[j];
@ -1319,7 +1379,7 @@ static void viewer_draw(int col)
while (spaces) { while (spaces) {
spaces--; spaces--;
scratch_buffer[k++] = ' '; scratch_buffer[k++] = ' ';
if (k == max_columns - 1) if (k == max_chars - 1)
break; break;
} }
scratch_buffer[k++] = c; scratch_buffer[k++] = c;
@ -1388,7 +1448,7 @@ static void viewer_draw(int col)
multiple_spacing = false; multiple_spacing = false;
for (j=k=spaces=0; j < line_len; j++) { for (j=k=spaces=0; j < line_len; j++) {
if (k == max_columns) if (k == max_chars)
break; break;
c = line_begin[j]; c = line_begin[j];
@ -1420,31 +1480,32 @@ static void viewer_draw(int col)
} }
} }
else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */ else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */
if (col != -1) if ((col != -1) && (line_width > col)) {
if (line_width > col) { str = oldstr = line_begin;
str = oldstr = line_begin; k = col;
k = col; width = 0;
width = 0; while( (width<draw_columns) && (oldstr<line_end) )
while( (width<draw_columns) && (oldstr<line_end) ) {
{ oldstr = get_ucs(oldstr, &ch);
oldstr = get_ucs(oldstr, &ch); if (k > 0) {
if (k > 0) { k -= glyph_width(ch);
k -= glyph_width(ch); line_begin = oldstr;
line_begin = oldstr; } else {
} else { width += glyph_width(ch);
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) if (col != -1 && line_width > col)
{ {
int dpage = (cline+i <= display_lines)?cpage:cpage+1; int dpage = (cline+i <= display_lines)?cpage:cpage+1;