summaryrefslogtreecommitdiff
path: root/apps/plugins/textviewer/tv_text_processor.c
diff options
context:
space:
mode:
authorYoshihisa Uchida <uchida@rockbox.org>2010-04-14 10:16:00 +0000
committerYoshihisa Uchida <uchida@rockbox.org>2010-04-14 10:16:00 +0000
commit2ca2684ede50f145985ae147ca52aef27f7580b2 (patch)
tree9e7733fbdc4b3022c8bb084921699e1eb34f3ec4 /apps/plugins/textviewer/tv_text_processor.c
parent0d24df8b952c105cf8e532ff48b636bc81945938 (diff)
downloadrockbox-2ca2684ede50f145985ae147ca52aef27f7580b2.zip
rockbox-2ca2684ede50f145985ae147ca52aef27f7580b2.tar.gz
rockbox-2ca2684ede50f145985ae147ca52aef27f7580b2.tar.bz2
rockbox-2ca2684ede50f145985ae147ca52aef27f7580b2.tar.xz
new text viewer
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25644 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/textviewer/tv_text_processor.c')
-rw-r--r--apps/plugins/textviewer/tv_text_processor.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/apps/plugins/textviewer/tv_text_processor.c b/apps/plugins/textviewer/tv_text_processor.c
new file mode 100644
index 0000000..3ad80db
--- /dev/null
+++ b/apps/plugins/textviewer/tv_text_processor.c
@@ -0,0 +1,505 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 Gilles Roux, 2003 Garrett Derner
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "plugin.h"
+#include "tv_drawtext.h"
+
+#define WRAP_TRIM 44 /* Max number of spaces to trim (arbitrary) */
+#define NARROW_MAX_COLUMNS 64 /* Max displayable string len [narrow] (over-estimate) */
+#define WIDE_MAX_COLUMNS 128 /* Max displayable string len [wide] (over-estimate) */
+#define MAX_WIDTH 910 /* Max line length in WIDE mode */
+#define READ_PREV_ZONE (block_size*9/10) /* Arbitrary number less than SMALL_BLOCK_SIZE */
+#define SMALL_BLOCK_SIZE block_size /* Smallest file chunk we will read */
+#define LARGE_BLOCK_SIZE (block_size << 1) /* Preferable size of file chunk to read */
+#define TOP_SECTOR buffer
+#define MID_SECTOR (buffer + SMALL_BLOCK_SIZE)
+#define BOTTOM_SECTOR (buffer + (SMALL_BLOCK_SIZE << 1))
+#undef SCROLLBAR_WIDTH
+#define SCROLLBAR_WIDTH rb->global_settings->scrollbar_width
+#define MAX_PAGE 9999
+
+/* Is a scrollbar called for on the current screen? */
+#define NEED_SCROLLBAR() \
+ ((!(ONE_SCREEN_FITS_ALL())) && (prefs.scrollbar_mode==SB_ON))
+
+static void increment_current_line(void)
+{
+ if (cline < display_lines)
+ cline++;
+ else if (cpage < MAX_PAGE)
+ {
+ cpage++;
+ cline = 1;
+ }
+}
+
+static void decrement_current_line(void)
+{
+ if (cline > 1)
+ cline--;
+ else if (cpage > 1)
+ {
+ cpage--;
+ cline = display_lines;
+ }
+}
+
+static void viewer_scroll_up(void)
+{
+ unsigned char *p;
+
+ p = find_prev_line(screen_top_ptr);
+ if (p == NULL && !BUFFER_BOF()) {
+ read_and_synch(-1);
+ p = find_prev_line(screen_top_ptr);
+ }
+ if (p != NULL)
+ screen_top_ptr = p;
+
+ decrement_current_line();
+}
+
+static void viewer_scroll_down(bool autoscroll)
+{
+ if (cpage == lpage)
+ return;
+
+ if (next_line_ptr != NULL)
+ screen_top_ptr = next_line_ptr;
+
+ if (prefs.scroll_mode == LINE || autoscroll)
+ increment_current_line();
+}
+
+static void viewer_scroll_to_top_line(void)
+{
+ int line;
+
+ for (line = cline; line > 1; line--)
+ viewer_scroll_up();
+}
+
+#ifdef HAVE_LCD_BITMAP
+static void viewer_scrollbar(void) {
+ int items, min_shown, max_shown, sb_begin_y, sb_height;
+
+ items = (int) file_size; /* (SH1 int is same as long) */
+ min_shown = (int) file_pos + (screen_top_ptr - buffer);
+
+ if (next_screen_ptr == NULL)
+ max_shown = items;
+ else
+ max_shown = min_shown + (next_screen_ptr - screen_top_ptr);
+
+ sb_begin_y = header_height;
+ sb_height = LCD_HEIGHT - header_height - footer_height;
+
+ rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN],0, sb_begin_y,
+ SCROLLBAR_WIDTH-1, sb_height,
+ items, min_shown, max_shown, VERTICAL);
+}
+
+static void viewer_show_header(void)
+{
+ if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
+ rb->gui_syncstatusbar_draw(rb->statusbars, true);
+
+ if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
+ rb->lcd_putsxy(0, header_height - pf->height, file_name);
+}
+
+static void viewer_show_footer(void)
+{
+ if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
+ rb->gui_syncstatusbar_draw(rb->statusbars, true);
+
+ if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
+ {
+ unsigned char buf[12];
+
+ if (cline == 1)
+ rb->snprintf(buf, sizeof(buf), "%d", cpage);
+ else
+ rb->snprintf(buf, sizeof(buf), "%d - %d", cpage, cpage+1);
+
+ rb->lcd_putsxy(0, LCD_HEIGHT - footer_height, buf);
+ }
+}
+#endif
+
+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;
+ 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];
+ unsigned char *endptr;
+
+ /* If col==-1 do all calculations but don't display */
+ if (col != -1) {
+#ifdef HAVE_LCD_BITMAP
+ left_col = prefs.need_scrollbar? SCROLLBAR_WIDTH:0;
+#else
+ left_col = 0;
+#endif
+ rb->lcd_clear_display();
+ }
+ max_line_len = 0;
+ line_begin = line_end = screen_top_ptr;
+
+ for (i = 0; i < display_lines; i++) {
+ if (BUFFER_OOB(line_end))
+ {
+ if (lpage == cpage)
+ break; /* Happens after display last line at BUFFER_EOF() */
+
+ if (lpage == 0 && cline == 1)
+ {
+ lpage = cpage;
+ last_screen_top_ptr = screen_top_ptr;
+ last_file_pos = file_pos;
+ }
+ }
+
+ get_next_line_position(&line_begin, &line_end, &line_is_short);
+ if (line_end == NULL)
+ {
+ if (BUFFER_OOB(line_begin))
+ break;
+ line_end = buffer_end + 1;
+ }
+
+ line_len = line_end - line_begin;
+
+ /* calculate line_len */
+ str = oldstr = line_begin;
+ j = -1;
+ while (str < line_end) {
+ oldstr = str;
+ str = crop_at_width(str);
+ j++;
+ }
+ line_width = j*draw_columns;
+ while (oldstr < line_end) {
+ oldstr = get_ucs(oldstr, &ch);
+ line_width += glyph_width(ch);
+ }
+
+ if (prefs.line_mode == JOIN) {
+ if (line_begin[0] == 0) {
+ line_begin++;
+ if (prefs.word_mode == CHOP)
+ line_end++;
+ else
+ line_len--;
+ }
+ for (j=k=spaces=0; j < line_len; j++) {
+ if (k == max_columns)
+ break;
+
+ c = line_begin[j];
+ switch (c) {
+ case ' ':
+ spaces++;
+ break;
+ case 0:
+ spaces = 0;
+ scratch_buffer[k++] = ' ';
+ break;
+ default:
+ while (spaces) {
+ spaces--;
+ scratch_buffer[k++] = ' ';
+ if (k == max_columns - 1)
+ break;
+ }
+ scratch_buffer[k++] = c;
+ break;
+ }
+ }
+ if (col != -1) {
+ scratch_buffer[k] = 0;
+ endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
+ *endptr = 0;
+ }
+ }
+ else if (prefs.line_mode == REFLOW) {
+ if (line_begin[0] == 0) {
+ line_begin++;
+ if (prefs.word_mode == CHOP)
+ line_end++;
+ else
+ line_len--;
+ }
+
+ indent_spaces = 0;
+ if (!line_is_short) {
+ multiple_spacing = false;
+ width=spaces=0;
+ for (str = line_begin; str < line_end; ) {
+ str = get_ucs(str, &ch);
+ switch (ch) {
+ case ' ':
+ case 0:
+ if ((str == line_begin) && (prefs.word_mode==WRAP))
+ /* special case: indent the paragraph,
+ * don't count spaces */
+ indent_spaces = par_indent_spaces;
+ else if (!multiple_spacing)
+ spaces++;
+ multiple_spacing = true;
+ break;
+ default:
+ multiple_spacing = false;
+ width += glyph_width(ch);
+ break;
+ }
+ }
+ if (multiple_spacing) spaces--;
+
+ if (spaces) {
+ /* total number of spaces to insert between words */
+ extra_spaces = (max_width-width)/glyph_width(' ')
+ - indent_spaces;
+ /* number of spaces between each word*/
+ spaces_per_word = extra_spaces / spaces;
+ /* number of words with n+1 spaces (to fill up) */
+ extra_spaces = extra_spaces % spaces;
+ if (spaces_per_word > 2) { /* too much spacing is awful */
+ spaces_per_word = 3;
+ extra_spaces = 0;
+ }
+ } else { /* this doesn't matter much... no spaces anyway */
+ spaces_per_word = extra_spaces = 0;
+ }
+ } else { /* end of a paragraph: don't fill line */
+ spaces_per_word = 1;
+ extra_spaces = 0;
+ }
+
+ multiple_spacing = false;
+ for (j=k=spaces=0; j < line_len; j++) {
+ if (k == max_columns)
+ break;
+
+ c = line_begin[j];
+ switch (c) {
+ case ' ':
+ case 0:
+ if (j==0 && prefs.word_mode==WRAP) { /* indent paragraph */
+ for (j=0; j<par_indent_spaces; j++)
+ scratch_buffer[k++] = ' ';
+ j=0;
+ }
+ else if (!multiple_spacing) {
+ for (width = spaces<extra_spaces ? -1:0; width < spaces_per_word; width++)
+ scratch_buffer[k++] = ' ';
+ spaces++;
+ }
+ multiple_spacing = true;
+ break;
+ default:
+ scratch_buffer[k++] = c;
+ multiple_spacing = false;
+ break;
+ }
+ }
+ if (col != -1) {
+ scratch_buffer[k] = 0;
+ endptr = decode2utf8(scratch_buffer, utf8_buffer, col, draw_columns);
+ *endptr = 0;
+ }
+ }
+ 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(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 (col != -1 && line_width > col)
+ {
+ int dpage = (cline+i <= display_lines)?cpage:cpage+1;
+ int dline = cline+i - ((cline+i <= display_lines)?0:display_lines);
+ bool bflag = (viewer_find_bookmark(dpage, dline) >= 0);
+#ifdef HAVE_LCD_BITMAP
+ int dy = i * pf->height + header_height;
+#endif
+ if (bflag)
+#ifdef HAVE_LCD_BITMAP
+ {
+ rb->lcd_set_drawmode(DRMODE_BG|DRMODE_FG);
+ rb->lcd_fillrect(left_col, dy, LCD_WIDTH, pf->height);
+ rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+ }
+ rb->lcd_putsxy(left_col, dy, utf8_buffer);
+ rb->lcd_set_drawmode(DRMODE_SOLID);
+#else
+ {
+ rb->lcd_puts(left_col, i, BOOKMARK_ICON);
+ }
+ rb->lcd_puts(left_col+1, i, utf8_buffer);
+#endif
+ }
+ if (line_width > max_line_len)
+ max_line_len = line_width;
+
+ if (i == 0)
+ next_line_ptr = line_end;
+ }
+ next_screen_ptr = line_end;
+ if (BUFFER_OOB(next_screen_ptr))
+ next_screen_ptr = NULL;
+
+#ifdef HAVE_LCD_BITMAP
+ next_screen_to_draw_ptr = prefs.page_mode==OVERLAP? line_begin: next_screen_ptr;
+
+ if (prefs.need_scrollbar)
+ viewer_scrollbar();
+#else
+ next_screen_to_draw_ptr = next_screen_ptr;
+#endif
+
+#ifdef HAVE_LCD_BITMAP
+ /* show header */
+ viewer_show_header();
+
+ /* show footer */
+ viewer_show_footer();
+#endif
+
+ if (col != -1)
+ rb->lcd_update();
+}
+
+#ifdef HAVE_LCD_BITMAP
+static void init_need_scrollbar(void) {
+ /* Call viewer_draw in quiet mode to initialize next_screen_ptr,
+ and thus ONE_SCREEN_FITS_ALL(), and thus NEED_SCROLLBAR() */
+ viewer_draw(-1);
+ prefs.need_scrollbar = NEED_SCROLLBAR();
+ draw_columns = prefs.need_scrollbar? display_columns-SCROLLBAR_WIDTH : display_columns;
+ par_indent_spaces = draw_columns/(5*glyph_width(' '));
+ calc_max_width();
+}
+
+static void init_header_and_footer(void)
+{
+ header_height = 0;
+ footer_height = 0;
+ if (rb->global_settings->statusbar == STATUSBAR_TOP)
+ {
+ if (prefs.header_mode == HD_SBAR || prefs.header_mode == HD_BOTH)
+ header_height = STATUSBAR_HEIGHT;
+
+ if (prefs.footer_mode == FT_SBAR)
+ prefs.footer_mode = FT_NONE;
+ else if (prefs.footer_mode == FT_BOTH)
+ prefs.footer_mode = FT_PAGE;
+ }
+ else if (rb->global_settings->statusbar == STATUSBAR_BOTTOM)
+ {
+ if (prefs.footer_mode == FT_SBAR || prefs.footer_mode == FT_BOTH)
+ footer_height = STATUSBAR_HEIGHT;
+
+ if (prefs.header_mode == HD_SBAR)
+ prefs.header_mode = HD_NONE;
+ else if (prefs.header_mode == HD_BOTH)
+ prefs.header_mode = HD_PATH;
+ }
+ else /* STATUSBAR_OFF || STATUSBAR_CUSTOM */
+ {
+ if (prefs.header_mode == HD_SBAR)
+ prefs.header_mode = HD_NONE;
+ else if (prefs.header_mode == HD_BOTH)
+ prefs.header_mode = HD_PATH;
+
+ if (prefs.footer_mode == FT_SBAR)
+ prefs.footer_mode = FT_NONE;
+ else if (prefs.footer_mode == FT_BOTH)
+ prefs.footer_mode = FT_PAGE;
+ }
+
+ if (prefs.header_mode == HD_NONE || prefs.header_mode == HD_PATH ||
+ prefs.footer_mode == FT_NONE || prefs.footer_mode == FT_PAGE)
+ rb->gui_syncstatusbar_draw(rb->statusbars, false);
+
+ if (prefs.header_mode == HD_PATH || prefs.header_mode == HD_BOTH)
+ header_height += pf->height;
+ if (prefs.footer_mode == FT_PAGE || prefs.footer_mode == FT_BOTH)
+ footer_height += pf->height;
+
+ display_lines = (LCD_HEIGHT - header_height - footer_height) / pf->height;
+
+ lpage = 0;
+ last_file_pos = 0;
+ last_screen_top_ptr = NULL;
+}
+
+static void change_font(unsigned char *font)
+{
+ unsigned char buf[MAX_PATH];
+
+ if (font == NULL || *font == '\0')
+ return;
+
+ rb->snprintf(buf, MAX_PATH, "%s/%s.fnt", FONT_DIR, font);
+ if (rb->font_load(NULL, buf) < 0)
+ rb->splash(HZ/2, "font load failed.");
+}
+#endif
+
+/* When a file is UTF-8 file with BOM, if prefs.encoding is UTF-8,
+ * then file size decreases only BOM_SIZE.
+ */
+static void get_filesize(void)
+{
+ file_size = rb->filesize(fd);
+ if (file_size == -1)
+ return;
+
+ if (prefs.encoding == UTF_8 && is_bom)
+ file_size -= BOM_SIZE;
+}