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.tar.gz rockbox-9e4bd41e416a2d48284947e9ccc09844d3db93ee.zip |
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 c9f649b096..2f54c0d314 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "storage.h" | 41 | #include "storage.h" |
42 | #include "pcmbuf.h" | 42 | #include "pcmbuf.h" |
43 | #include "errno.h" | 43 | #include "errno.h" |
44 | #include "diacritic.h" | ||
44 | 45 | ||
45 | #if CONFIG_CHARGING | 46 | #if CONFIG_CHARGING |
46 | #include "power.h" | 47 | #include "power.h" |
@@ -710,6 +711,10 @@ static const struct plugin_api rockbox_api = { | |||
710 | appsversion, | 711 | appsversion, |
711 | /* new stuff at the end, sort into place next time | 712 | /* new stuff at the end, sort into place next time |
712 | the API gets incompatible */ | 713 | the API gets incompatible */ |
714 | |||
715 | #ifdef HAVE_LCD_BITMAP | ||
716 | is_diacritic, | ||
717 | #endif | ||
713 | }; | 718 | }; |
714 | 719 | ||
715 | int plugin_load(const char* plugin, const void* parameter) | 720 | int plugin_load(const char* plugin, const void* parameter) |
diff --git a/apps/plugin.h b/apps/plugin.h index c3466bc457..464a581dab 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -135,7 +135,7 @@ void* plugin_get_buffer(size_t *buffer_size); | |||
135 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 135 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
136 | 136 | ||
137 | /* increase this every time the api struct changes */ | 137 | /* increase this every time the api struct changes */ |
138 | #define PLUGIN_API_VERSION 182 | 138 | #define PLUGIN_API_VERSION 183 |
139 | 139 | ||
140 | /* update this to latest version if a change to the api struct breaks | 140 | /* update this to latest version if a change to the api struct breaks |
141 | backwards compatibility (and please take the opportunity to sort in any | 141 | backwards compatibility (and please take the opportunity to sort in any |
@@ -863,6 +863,10 @@ struct plugin_api { | |||
863 | const char *appsversion; | 863 | const char *appsversion; |
864 | /* new stuff at the end, sort into place next time | 864 | /* new stuff at the end, sort into place next time |
865 | the API gets incompatible */ | 865 | the API gets incompatible */ |
866 | |||
867 | #ifdef HAVE_LCD_BITMAP | ||
868 | int (*is_diacritic)(const unsigned short char_code, bool *is_rtl); | ||
869 | #endif | ||
866 | }; | 870 | }; |
867 | 871 | ||
868 | /* plugin header */ | 872 | /* plugin header */ |
diff --git a/apps/plugins/viewer.c b/apps/plugins/viewer.c index 80b279c638..8751b43e93 100644 --- a/apps/plugins/viewer.c +++ b/apps/plugins/viewer.c | |||
@@ -636,11 +636,14 @@ static int bookmark_count; | |||
636 | static bool is_bom = false; | 636 | static bool is_bom = false; |
637 | 637 | ||
638 | /* calculate the width of a UCS character (zero width for diacritics) */ | 638 | /* calculate the width of a UCS character (zero width for diacritics) */ |
639 | static int glyph_width(int ch) | 639 | static int glyph_width(unsigned short ch) |
640 | { | 640 | { |
641 | if (ch == 0) | 641 | if (ch == 0) |
642 | ch = ' '; | 642 | ch = ' '; |
643 | 643 | ||
644 | if (rb->is_diacritic(ch, NULL)) | ||
645 | return 0; | ||
646 | |||
644 | #ifdef HAVE_LCD_BITMAP | 647 | #ifdef HAVE_LCD_BITMAP |
645 | return rb->font_get_width(pf, ch); | 648 | return rb->font_get_width(pf, ch); |
646 | #else | 649 | #else |
@@ -730,6 +733,10 @@ static int col = 0; | |||
730 | 733 | ||
731 | static inline void advance_conters(unsigned short ch, int* k, int* width) | 734 | static inline void advance_conters(unsigned short ch, int* k, int* width) |
732 | { | 735 | { |
736 | /* diacritics do not count */ | ||
737 | if (rb->is_diacritic(ch, NULL)) | ||
738 | return; | ||
739 | |||
733 | *width += glyph_width(ch); | 740 | *width += glyph_width(ch); |
734 | (*k)++; | 741 | (*k)++; |
735 | } | 742 | } |
@@ -760,11 +767,18 @@ static unsigned char* crop_at_width(const unsigned char* p) | |||
760 | 767 | ||
761 | static unsigned char* find_first_feed(const unsigned char* p, int size) | 768 | static unsigned char* find_first_feed(const unsigned char* p, int size) |
762 | { | 769 | { |
763 | int i; | 770 | int s = 0; |
771 | unsigned short ch; | ||
772 | const unsigned char *oldp = p; | ||
764 | 773 | ||
765 | for (i=0; i < size; i++) | 774 | while(s <= size) |
766 | if (p[i] == 0) | 775 | { |
767 | return (unsigned char*) p+i; | 776 | if (*p == 0) |
777 | return (unsigned char*)p; | ||
778 | oldp = p; | ||
779 | p = get_ucs(p, &ch); | ||
780 | s += (p - oldp); | ||
781 | } | ||
768 | 782 | ||
769 | return NULL; | 783 | return NULL; |
770 | } | 784 | } |
@@ -786,18 +800,21 @@ static unsigned char* find_last_space(const unsigned char* p, int size) | |||
786 | 800 | ||
787 | k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1; | 801 | k = (prefs.line_mode==JOIN) || (prefs.line_mode==REFLOW) ? 0:1; |
788 | 802 | ||
789 | if (!BUFFER_OOB(&p[size])) | 803 | i = size; |
790 | for (j=k; j < ((int) sizeof(line_break)) - 1; j++) | 804 | if (!BUFFER_OOB(&p[i])) |
791 | if (p[size] == line_break[j]) | 805 | for (j=k; j < ((int) sizeof(line_break)) - 1; j++) { |
792 | return (unsigned char*) p+size; | 806 | if (p[i] == line_break[j]) |
807 | return (unsigned char*) p+i; | ||
808 | } | ||
793 | 809 | ||
794 | for (i=size-1; i>=0; i--) | 810 | if (prefs.word_mode == WRAP) { |
795 | for (j=k; j < (int) sizeof(line_break); j++) | 811 | for (i=size-1; i>=0; i--) { |
796 | { | 812 | for (j=k; j < (int) sizeof(line_break) - 1; j++) { |
797 | if (!((p[i] == '-') && (prefs.word_mode == WRAP))) | ||
798 | if (p[i] == line_break[j]) | 813 | if (p[i] == line_break[j]) |
799 | return (unsigned char*) p+i; | 814 | return (unsigned char*) p+i; |
815 | } | ||
800 | } | 816 | } |
817 | } | ||
801 | 818 | ||
802 | return NULL; | 819 | return NULL; |
803 | } | 820 | } |
@@ -805,9 +822,9 @@ static unsigned char* find_last_space(const unsigned char* p, int size) | |||
805 | static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short) | 822 | static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_short) |
806 | { | 823 | { |
807 | const unsigned char *next_line = NULL; | 824 | const unsigned char *next_line = NULL; |
808 | int size, i, j, k, width, search_len, spaces, newlines; | 825 | int size, i, j, j_next, j_prev, k, width, search_len, spaces, newlines; |
809 | bool first_chars; | 826 | bool first_chars; |
810 | unsigned char c; | 827 | unsigned short ch; |
811 | 828 | ||
812 | if (is_short != NULL) | 829 | if (is_short != NULL) |
813 | *is_short = true; | 830 | *is_short = true; |
@@ -829,16 +846,25 @@ static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_sho | |||
829 | or possibly set next_line at second hard return in a row. */ | 846 | or possibly set next_line at second hard return in a row. */ |
830 | next_line = NULL; | 847 | next_line = NULL; |
831 | first_chars=true; | 848 | first_chars=true; |
832 | for (j=k=width=spaces=newlines=0; ; j++) { | 849 | j_next=j=k=width=spaces=newlines=0; |
850 | while (1) { | ||
851 | const unsigned char *p, *oldp; | ||
852 | |||
853 | j_prev = j; | ||
854 | j = j_next; | ||
855 | |||
833 | if (BUFFER_OOB(cur_line+j)) | 856 | if (BUFFER_OOB(cur_line+j)) |
834 | return NULL; | 857 | return NULL; |
835 | if (line_is_full(k, width)) { | 858 | if (line_is_full(k, width)) { |
836 | size = search_len = j; | 859 | size = search_len = j_prev; |
837 | break; | 860 | break; |
838 | } | 861 | } |
839 | 862 | ||
840 | c = cur_line[j]; | 863 | oldp = p = &cur_line[j]; |
841 | switch (c) { | 864 | p = get_ucs(p, &ch); |
865 | j_next = j + (p - oldp); | ||
866 | |||
867 | switch (ch) { | ||
842 | case ' ': | 868 | case ' ': |
843 | if (prefs.line_mode == REFLOW) { | 869 | if (prefs.line_mode == REFLOW) { |
844 | if (newlines > 0) { | 870 | if (newlines > 0) { |
@@ -909,14 +935,18 @@ static unsigned char* find_next_line(const unsigned char* cur_line, bool *is_sho | |||
909 | if (prefs.word_mode == WRAP) /* Find last space */ | 935 | if (prefs.word_mode == WRAP) /* Find last space */ |
910 | next_line = find_last_space(cur_line, size); | 936 | next_line = find_last_space(cur_line, size); |
911 | 937 | ||
912 | if (next_line == NULL) | 938 | if (next_line == NULL) { |
913 | next_line = crop_at_width(cur_line); | 939 | next_line = crop_at_width(cur_line); |
914 | else | 940 | } |
915 | if (prefs.word_mode == WRAP) | 941 | else { |
916 | for (i=0; | 942 | if (prefs.word_mode == WRAP) { |
917 | i<WRAP_TRIM && isspace(next_line[0]) && !BUFFER_OOB(next_line); | 943 | for (i=0;i<WRAP_TRIM;i++) { |
918 | i++) | 944 | if (!(isspace(next_line[0]) && !BUFFER_OOB(next_line))) |
945 | break; | ||
919 | next_line++; | 946 | next_line++; |
947 | } | ||
948 | } | ||
949 | } | ||
920 | } | 950 | } |
921 | 951 | ||
922 | if (prefs.line_mode == EXPAND) | 952 | if (prefs.line_mode == EXPAND) |
@@ -1230,18 +1260,26 @@ static void viewer_show_footer(void) | |||
1230 | } | 1260 | } |
1231 | #endif | 1261 | #endif |
1232 | 1262 | ||
1263 | /* We draw a diacritic char over a non-diacritic one. Therefore, such chars are | ||
1264 | * not considered to occupy space, therefore buffers might have more than | ||
1265 | * max_columns characters. The DIACRITIC_FACTOR is the max ratio between all | ||
1266 | * characters and non-diacritic characters in the buffer | ||
1267 | */ | ||
1268 | #define DIACRITIC_FACTOR 2 | ||
1269 | |||
1233 | static void viewer_draw(int col) | 1270 | static void viewer_draw(int col) |
1234 | { | 1271 | { |
1235 | int i, j, k, line_len, line_width, spaces, left_col=0; | 1272 | int i, j, k, line_len, line_width, spaces, left_col=0; |
1236 | int width, extra_spaces, indent_spaces, spaces_per_word; | 1273 | int width, extra_spaces, indent_spaces, spaces_per_word, spaces_width; |
1237 | bool multiple_spacing, line_is_short; | 1274 | bool multiple_spacing, line_is_short; |
1238 | unsigned short ch; | 1275 | unsigned short ch; |
1239 | unsigned char *str, *oldstr; | 1276 | unsigned char *str, *oldstr; |
1240 | unsigned char *line_begin; | 1277 | unsigned char *line_begin; |
1241 | unsigned char *line_end; | 1278 | unsigned char *line_end; |
1242 | unsigned char c; | 1279 | unsigned char c; |
1243 | unsigned char scratch_buffer[max_columns + 1]; | 1280 | int max_chars = max_columns * DIACRITIC_FACTOR; |
1244 | unsigned char utf8_buffer[max_columns*4 + 1]; | 1281 | unsigned char scratch_buffer[max_chars + 1]; |
1282 | unsigned char utf8_buffer[max_chars * 4 + 1]; | ||
1245 | unsigned char *endptr; | 1283 | unsigned char *endptr; |
1246 | 1284 | ||
1247 | /* If col==-1 do all calculations but don't display */ | 1285 | /* If col==-1 do all calculations but don't display */ |
@@ -1287,11 +1325,33 @@ static void viewer_draw(int col) | |||
1287 | oldstr = str; | 1325 | oldstr = str; |
1288 | str = crop_at_width(str); | 1326 | str = crop_at_width(str); |
1289 | j++; | 1327 | j++; |
1328 | if (oldstr == str) | ||
1329 | { | ||
1330 | oldstr = line_end; | ||
1331 | break; | ||
1332 | } | ||
1290 | } | 1333 | } |
1334 | /* width of un-displayed part of the line */ | ||
1291 | line_width = j*draw_columns; | 1335 | line_width = j*draw_columns; |
1336 | spaces_width = 0; | ||
1292 | while (oldstr < line_end) { | 1337 | while (oldstr < line_end) { |
1293 | oldstr = get_ucs(oldstr, &ch); | 1338 | oldstr = get_ucs(oldstr, &ch); |
1294 | line_width += glyph_width(ch); | 1339 | /* add width of displayed part of the line */ |
1340 | if (ch) | ||
1341 | { | ||
1342 | int dw = glyph_width(ch); | ||
1343 | |||
1344 | /* avoid counting spaces at the end of the line */ | ||
1345 | if (ch == ' ') | ||
1346 | { | ||
1347 | spaces_width += dw; | ||
1348 | } | ||
1349 | else | ||
1350 | { | ||
1351 | line_width += dw + spaces_width; | ||
1352 | spaces_width = 0; | ||
1353 | } | ||
1354 | } | ||
1295 | } | 1355 | } |
1296 | 1356 | ||
1297 | if (prefs.line_mode == JOIN) { | 1357 | if (prefs.line_mode == JOIN) { |
@@ -1303,7 +1363,7 @@ static void viewer_draw(int col) | |||
1303 | line_len--; | 1363 | line_len--; |
1304 | } | 1364 | } |
1305 | for (j=k=spaces=0; j < line_len; j++) { | 1365 | for (j=k=spaces=0; j < line_len; j++) { |
1306 | if (k == max_columns) | 1366 | if (k == max_chars) |
1307 | break; | 1367 | break; |
1308 | 1368 | ||
1309 | c = line_begin[j]; | 1369 | c = line_begin[j]; |
@@ -1319,7 +1379,7 @@ static void viewer_draw(int col) | |||
1319 | while (spaces) { | 1379 | while (spaces) { |
1320 | spaces--; | 1380 | spaces--; |
1321 | scratch_buffer[k++] = ' '; | 1381 | scratch_buffer[k++] = ' '; |
1322 | if (k == max_columns - 1) | 1382 | if (k == max_chars - 1) |
1323 | break; | 1383 | break; |
1324 | } | 1384 | } |
1325 | scratch_buffer[k++] = c; | 1385 | scratch_buffer[k++] = c; |
@@ -1388,7 +1448,7 @@ static void viewer_draw(int col) | |||
1388 | 1448 | ||
1389 | multiple_spacing = false; | 1449 | multiple_spacing = false; |
1390 | for (j=k=spaces=0; j < line_len; j++) { | 1450 | for (j=k=spaces=0; j < line_len; j++) { |
1391 | if (k == max_columns) | 1451 | if (k == max_chars) |
1392 | break; | 1452 | break; |
1393 | 1453 | ||
1394 | c = line_begin[j]; | 1454 | c = line_begin[j]; |
@@ -1420,31 +1480,32 @@ static void viewer_draw(int col) | |||
1420 | } | 1480 | } |
1421 | } | 1481 | } |
1422 | else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */ | 1482 | else { /* prefs.line_mode != JOIN && prefs.line_mode != REFLOW */ |
1423 | if (col != -1) | 1483 | if ((col != -1) && (line_width > col)) { |
1424 | if (line_width > col) { | 1484 | str = oldstr = line_begin; |
1425 | str = oldstr = line_begin; | 1485 | k = col; |
1426 | k = col; | 1486 | width = 0; |
1427 | width = 0; | 1487 | while( (width<draw_columns) && (oldstr<line_end) ) |
1428 | while( (width<draw_columns) && (oldstr<line_end) ) | 1488 | { |
1429 | { | 1489 | oldstr = get_ucs(oldstr, &ch); |
1430 | oldstr = get_ucs(oldstr, &ch); | 1490 | if (k > 0) { |
1431 | if (k > 0) { | 1491 | k -= glyph_width(ch); |
1432 | k -= glyph_width(ch); | 1492 | line_begin = oldstr; |
1433 | line_begin = oldstr; | 1493 | } else { |
1434 | } else { | 1494 | width += glyph_width(ch); |
1435 | width += glyph_width(ch); | ||
1436 | } | ||
1437 | } | 1495 | } |
1438 | |||
1439 | if(prefs.view_mode==WIDE) | ||
1440 | endptr = rb->iso_decode(line_begin, utf8_buffer, | ||
1441 | prefs.encoding, oldstr-line_begin); | ||
1442 | else | ||
1443 | endptr = rb->iso_decode(line_begin, utf8_buffer, | ||
1444 | prefs.encoding, line_end-line_begin); | ||
1445 | *endptr = 0; | ||
1446 | } | 1496 | } |
1497 | |||
1498 | if(prefs.view_mode==WIDE) | ||
1499 | endptr = rb->iso_decode(line_begin, utf8_buffer, | ||
1500 | prefs.encoding, oldstr-line_begin); | ||
1501 | else | ||
1502 | endptr = rb->iso_decode(line_begin, utf8_buffer, | ||
1503 | prefs.encoding, line_end-line_begin); | ||
1504 | *endptr = 0; | ||
1505 | } | ||
1447 | } | 1506 | } |
1507 | |||
1508 | /* display on screen the displayed part of the line */ | ||
1448 | if (col != -1 && line_width > col) | 1509 | if (col != -1 && line_width > col) |
1449 | { | 1510 | { |
1450 | int dpage = (cline+i <= display_lines)?cpage:cpage+1; | 1511 | int dpage = (cline+i <= display_lines)?cpage:cpage+1; |