summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorTomer Shalev <shalev.tomer@gmail.com>2010-04-07 17:22:16 +0000
committerTomer Shalev <shalev.tomer@gmail.com>2010-04-07 17:22:16 +0000
commit9e4bd41e416a2d48284947e9ccc09844d3db93ee (patch)
treed575c2b63730c4525a79ad42fe511ba03809a651 /apps
parent8b904e2bb4e92a6c4cb97db7d2c4e43a624b4e28 (diff)
downloadrockbox-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.c5
-rw-r--r--apps/plugin.h6
-rw-r--r--apps/plugins/viewer.c169
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;