diff options
author | Jens Arnold <amiconn@rockbox.org> | 2006-10-07 16:37:30 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2006-10-07 16:37:30 +0000 |
commit | 803331841e3fa14cb84cf23794c282b250e7068d (patch) | |
tree | 5a3a91c4adecee392eb1ac9de99273375824999a | |
parent | 5c6f32af9563764cf7b3f9529956ac27808246cf (diff) | |
download | rockbox-803331841e3fa14cb84cf23794c282b250e7068d.tar.gz rockbox-803331841e3fa14cb84cf23794c282b250e7068d.zip |
Splash function: Fixed several bugs and problems: (1) Off-by-one bug caused a buffer overflow with splash text longer than the screen. (2) Last line wasn't centered properly in the same situation. (3) On player, string display length must be calculated using utf8length() instead of strlen() since unicode support was added (old bug). (4) Handle splash texts with multiple spaces properly, including correct length calculation and stripping on wrap. (5) Don't reset fg/bg colours to default if not centering (old bug). * Increased buffer sizes to account for (a) larger screens (b) utf-8 (c) words wider than the screen. * More efficient code.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11144 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/gui/splash.c | 187 |
1 files changed, 106 insertions, 81 deletions
diff --git a/apps/gui/splash.c b/apps/gui/splash.c index f41d174881..0995968415 100644 --- a/apps/gui/splash.c +++ b/apps/gui/splash.c | |||
@@ -18,105 +18,123 @@ | |||
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #include "stdarg.h" | 19 | #include "stdarg.h" |
20 | #include "string.h" | 20 | #include "string.h" |
21 | #include "rbunicode.h" | ||
21 | #include "stdio.h" | 22 | #include "stdio.h" |
22 | #include "kernel.h" | 23 | #include "kernel.h" |
23 | #include "screen_access.h" | 24 | #include "screen_access.h" |
24 | 25 | ||
26 | #ifndef MAX | ||
27 | #define MAX(a, b) (((a)>(b))?(a):(b)) | ||
28 | #endif | ||
25 | 29 | ||
26 | #ifdef HAVE_LCD_BITMAP | 30 | #ifdef HAVE_LCD_BITMAP |
27 | 31 | ||
28 | #define MAXLETTERS 128 /* 16*8 */ | 32 | #define MAXLINES (LCD_HEIGHT/6) |
29 | #define MAXLINES 10 | 33 | #define MAXBUFFER 512 |
30 | 34 | ||
31 | #else | 35 | #else /* HAVE_LCD_CHARCELLS */ |
32 | 36 | ||
33 | #define MAXLETTERS 22 /* 11 * 2 */ | 37 | #define MAXLINES 2 |
34 | #define MAXLINES 2 | 38 | #define MAXBUFFER 64 |
35 | 39 | ||
36 | #endif | 40 | #endif |
37 | 41 | ||
38 | static void splash(struct screen * screen, | 42 | static void splash(struct screen * screen, bool center, |
39 | bool center, const char *fmt, va_list ap) | 43 | const char *fmt, va_list ap) |
40 | { | 44 | { |
45 | char splash_buf[MAXBUFFER]; | ||
46 | short widths[MAXLINES]; | ||
47 | char *lines[MAXLINES]; | ||
48 | |||
41 | char *next; | 49 | char *next; |
42 | char *store=NULL; | 50 | char *lastbreak = NULL; |
51 | char *store = NULL; | ||
52 | int line = 0; | ||
43 | int x = 0; | 53 | int x = 0; |
44 | int w, h = 1; | 54 | int y, i; |
45 | unsigned char splash_buf[MAXLETTERS]; | 55 | int space_w, w, h; |
46 | unsigned short widths[MAXLINES]; | ||
47 | unsigned char *text = splash_buf; | ||
48 | int line = 0, i_line = 0; | ||
49 | bool first=true; | ||
50 | #ifdef HAVE_LCD_BITMAP | 56 | #ifdef HAVE_LCD_BITMAP |
51 | int maxw=0; | 57 | int maxw = 0; |
52 | int space; | ||
53 | int y; | ||
54 | screen->getstringsize(" ", &space, &y); | ||
55 | #if LCD_DEPTH > 1 | 58 | #if LCD_DEPTH > 1 |
56 | unsigned prevbg = LCD_DEFAULT_BG; | 59 | unsigned prevbg = 0; |
57 | unsigned prevfg = LCD_DEFAULT_FG; | 60 | unsigned prevfg = 0; |
58 | #endif | 61 | #endif |
59 | #else | 62 | |
60 | screen->double_height (false); /* HAVE_LCD_CHARCELLS */ | 63 | screen->getstringsize(" ", &space_w, &h); |
61 | int space = 1; | 64 | #else /* HAVE_LCD_CHARCELLS */ |
62 | int y = 0; | 65 | |
66 | space_w = h = 1; | ||
67 | screen->double_height (false); | ||
63 | #endif | 68 | #endif |
64 | screen->stop_scroll(); | 69 | y = h; |
65 | vsnprintf( splash_buf, sizeof(splash_buf), fmt, ap ); | 70 | |
66 | va_end( ap ); | 71 | vsnprintf(splash_buf, sizeof(splash_buf), fmt, ap); |
67 | 72 | va_end(ap); | |
68 | /* measure sizes & concatenates tokenise words into lines. */ | 73 | |
74 | /* break splash string into display lines, doing proper word wrap */ | ||
75 | |||
69 | next = strtok_r(splash_buf, " ", &store); | 76 | next = strtok_r(splash_buf, " ", &store); |
70 | while (next) { | 77 | if (!next) |
78 | return; /* nothing to display */ | ||
79 | |||
80 | lines[0] = next; | ||
81 | while (true) | ||
82 | { | ||
71 | #ifdef HAVE_LCD_BITMAP | 83 | #ifdef HAVE_LCD_BITMAP |
72 | screen->getstringsize(next, &w, &h); | 84 | screen->getstringsize(next, &w, NULL); |
73 | #else | 85 | #else |
74 | w = strlen(next); | 86 | w = utf8length(next); |
75 | h = 1; /* store height in characters */ | ||
76 | #endif | 87 | #endif |
77 | if(!first) { | 88 | if (lastbreak) |
78 | if(x + w > screen->width) { /* Too wide, wrap */ | 89 | { |
79 | y += h; | 90 | if (x + (next - lastbreak) * space_w + w > screen->width) |
80 | line++; | 91 | { /* too wide, wrap */ |
92 | widths[line] = x; | ||
93 | #ifdef HAVE_LCD_BITMAP | ||
94 | if (x > maxw) | ||
95 | maxw = x; | ||
96 | #endif | ||
97 | if ((y + h > screen->height) || (line >= (MAXLINES-1))) | ||
98 | break; /* screen full or out of lines */ | ||
81 | x = 0; | 99 | x = 0; |
82 | if((y > (screen->height-h)) || (line > screen->nb_lines)) | 100 | y += h; |
83 | /* STOP */ | 101 | lines[++line] = next; |
84 | break; | ||
85 | } | 102 | } |
86 | else | 103 | else |
87 | next[-1] = ' '; /* re-concatenate string */ | 104 | { |
105 | /* restore & calculate spacing */ | ||
106 | *lastbreak = ' '; | ||
107 | x += (next - lastbreak) * space_w; | ||
108 | } | ||
88 | } | 109 | } |
89 | else | 110 | x += w; |
90 | first = false; | 111 | lastbreak = next + strlen(next); |
91 | 112 | next = strtok_r(NULL, " ", &store); | |
92 | x += w + space; | 113 | if (!next) |
93 | widths[line] = x - space; /* don't count the trailing space */ | 114 | { /* no more words */ |
115 | widths[line] = x; | ||
94 | #ifdef HAVE_LCD_BITMAP | 116 | #ifdef HAVE_LCD_BITMAP |
95 | /* store the widest line */ | 117 | if (x > maxw) |
96 | if(widths[line]>maxw) | 118 | maxw = x; |
97 | maxw = widths[line]; | ||
98 | #endif | 119 | #endif |
99 | next = strtok_r(NULL, " ", &store); | 120 | break; |
121 | } | ||
100 | } | 122 | } |
101 | 123 | ||
102 | if(center) { | 124 | /* prepare screen */ |
103 | #ifdef HAVE_LCD_BITMAP | ||
104 | /* Start displaying the message at position y. */ | ||
105 | y = (screen->height - y)/2; | ||
106 | #else | ||
107 | y = 0; /* vertical center on 2 lines would be silly */ | ||
108 | #endif | ||
109 | } else | ||
110 | y = 0; | ||
111 | 125 | ||
126 | screen->stop_scroll(); | ||
127 | |||
128 | #ifdef HAVE_LCD_BITMAP | ||
112 | /* If we center the display, then just clear the box we need and put | 129 | /* If we center the display, then just clear the box we need and put |
113 | a nice little frame and put the text in there! */ | 130 | a nice little frame and put the text in there! */ |
114 | #ifdef HAVE_LCD_BITMAP | 131 | if (center) |
115 | if(center && (y > 2)) { | 132 | { |
116 | int xx = (screen->width - maxw)/2 - 2; | 133 | y = (screen->height - y) / 2; /* height => y start position */ |
117 | /* The new graphics routines handle clipping, so no need to check */ | 134 | x = (screen->width - maxw) / 2 - 2; |
118 | #if LCD_DEPTH > 1 | 135 | #if LCD_DEPTH > 1 |
119 | if(screen->depth>1) { | 136 | if (screen->depth > 1) |
137 | { | ||
120 | prevbg = screen->get_background(); | 138 | prevbg = screen->get_background(); |
121 | prevfg = screen->get_foreground(); | 139 | prevfg = screen->get_foreground(); |
122 | screen->set_background(LCD_LIGHTGRAY); | 140 | screen->set_background(LCD_LIGHTGRAY); |
@@ -124,33 +142,40 @@ static void splash(struct screen * screen, | |||
124 | } | 142 | } |
125 | #endif | 143 | #endif |
126 | screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); | 144 | screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); |
127 | screen->fillrect(xx, y-2, maxw+4, screen->height-y*2+4); | 145 | screen->fillrect(x, y-2, maxw+4, screen->height-y*2+4); |
128 | screen->set_drawmode(DRMODE_SOLID); | 146 | screen->set_drawmode(DRMODE_SOLID); |
129 | screen->drawrect(xx, y-2, maxw+4, screen->height-y*2+4); | 147 | screen->drawrect(x, y-2, maxw+4, screen->height-y*2+4); |
130 | } | 148 | } |
131 | else | 149 | else |
132 | #endif | 150 | { |
151 | y = 0; | ||
152 | x = 0; | ||
133 | screen->clear_display(); | 153 | screen->clear_display(); |
154 | } | ||
155 | #else /* HAVE_LCD_CHARCELLS */ | ||
156 | y = 0; /* vertical center on 2 lines would be silly */ | ||
157 | x = 0; | ||
158 | screen->clear_display(); | ||
159 | #endif | ||
160 | |||
161 | /* print the message to screen */ | ||
162 | |||
163 | for (i = 0; i <= line; i++) | ||
164 | { | ||
165 | if (center) | ||
166 | x = MAX((screen->width - widths[i]) / 2, 0); | ||
134 | 167 | ||
135 | /* print the message to screen */ | ||
136 | while(line-- >= 0) { | ||
137 | if (center) { | ||
138 | x = (screen->width-widths[i_line++])/2; | ||
139 | if(x < 0) | ||
140 | x = 0; | ||
141 | } else | ||
142 | x = 0; | ||
143 | #ifdef HAVE_LCD_BITMAP | 168 | #ifdef HAVE_LCD_BITMAP |
144 | screen->putsxy(x, y, text); | 169 | screen->putsxy(x, y, lines[i]); |
145 | #else | 170 | #else |
146 | screen->puts(x, y, text); | 171 | screen->puts(x, y, lines[i]); |
147 | #endif | 172 | #endif |
148 | text += strlen(text) + 1; | 173 | y += h; |
149 | y +=h; | 174 | } |
150 | } | ||
151 | 175 | ||
152 | #if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH > 1) | 176 | #if defined(HAVE_LCD_BITMAP) && (LCD_DEPTH > 1) |
153 | if(screen->depth > 1) { | 177 | if (center && (screen->depth > 1)) |
178 | { | ||
154 | screen->set_background(prevbg); | 179 | screen->set_background(prevbg); |
155 | screen->set_foreground(prevfg); | 180 | screen->set_foreground(prevfg); |
156 | } | 181 | } |