summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorTomer Shalev <shalev.tomer@gmail.com>2009-11-26 18:09:56 +0000
committerTomer Shalev <shalev.tomer@gmail.com>2009-11-26 18:09:56 +0000
commit39bfe3153ac06167d80f16df3a1cdd6c7dda20b0 (patch)
treec7b9053f06bab3b21fea94da688dbc384442c3e0 /firmware/drivers
parent507465be9447c3e3ba31d3cfaf5576ac55aed2f5 (diff)
downloadrockbox-39bfe3153ac06167d80f16df3a1cdd6c7dda20b0.tar.gz
rockbox-39bfe3153ac06167d80f16df3a1cdd6c7dda20b0.zip
Fix diacritic and save some bin size
- Fix bug which cause wrong placement of characters in some specific conditions - Fix multiple similar entries in cache - Protect against negative x values passed to drawing function git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23765 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/diacritic.c2
-rw-r--r--firmware/drivers/lcd-bitmap-common.c134
2 files changed, 70 insertions, 66 deletions
diff --git a/firmware/drivers/diacritic.c b/firmware/drivers/diacritic.c
index 5074beb2ad..728492a06e 100644
--- a/firmware/drivers/diacritic.c
+++ b/firmware/drivers/diacritic.c
@@ -354,7 +354,7 @@ int is_diacritic(unsigned short char_code, bool *is_rtl)
354 for (i = 1; i < DIAC_NUM_RANGES; i++) 354 for (i = 1; i < DIAC_NUM_RANGES; i++)
355 { 355 {
356 /* Found */ 356 /* Found */
357 if (char_code < DIAC_VAL(i)) 357 if (char_code <= DIAC_VAL(i))
358 break; 358 break;
359 } 359 }
360 360
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index 3853912640..4a711d5378 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -80,22 +80,14 @@ static void lcd_gradient_rect(int x1, int x2, int y, unsigned h,
80} 80}
81#endif 81#endif
82 82
83struct lcd_bitmap_char
84{
85 char is_rtl;
86 char is_diacritic;
87 unsigned char width;
88 unsigned char base_width;
89};
90
91/* put a string at a given pixel position, skipping first ofs pixel columns */ 83/* put a string at a given pixel position, skipping first ofs pixel columns */
92static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) 84static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
93{ 85{
94 unsigned short *ucs; 86 unsigned short ch, *ucs;
95 struct font* pf = font_get(current_vp->font); 87 struct font* pf = font_get(current_vp->font);
96 int vp_flags = current_vp->flags; 88 int vp_flags = current_vp->flags;
97 int i, len; 89 unsigned i;
98 static struct lcd_bitmap_char chars[SCROLL_LINE_SIZE]; 90 static int rtl_next_non_diacritic_width, last_non_diacritic_width;
99 91
100 if ((vp_flags & VP_FLAG_ALIGNMENT_MASK) != 0) 92 if ((vp_flags & VP_FLAG_ALIGNMENT_MASK) != 0)
101 { 93 {
@@ -118,62 +110,55 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
118 } 110 }
119 111
120 ucs = bidi_l2v(str, 1); 112 ucs = bidi_l2v(str, 1);
113
114 rtl_next_non_diacritic_width = 0;
115 last_non_diacritic_width = 0;
121 /* Mark diacritic and rtl flags for each character */ 116 /* Mark diacritic and rtl flags for each character */
122 for (i = 0; i < SCROLL_LINE_SIZE && ucs[i]; i++) 117 for (i = 0; i < SCROLL_LINE_SIZE && (ch = ucs[i]); i++)
123 { 118 {
124 bool is_rtl; 119 bool is_rtl, is_diac;
125 chars[i].is_diacritic = is_diacritic(ucs[i], &is_rtl); 120 const unsigned char *bits;
126 chars[i].is_rtl=is_rtl; 121 int width, base_width, drawmode = 0, base_ofs = 0;
127 } 122 unsigned short next_ch = ucs[i + 1];
128 len = i;
129 123
130 /* Get proportional width and glyph bits */ 124 if (x >= current_vp->width)
131 for (i = 0; i < len; i++) 125 break;
132 chars[i].width = font_get_width(pf, ucs[i]);
133 126
134 /* Calculate base width for each character */ 127 is_diac = is_diacritic(ch, &is_rtl);
135 for (i = 0; i < len; i++) 128
136 { 129 /* Get proportional width and glyph bits */
137 if (chars[i].is_rtl) 130 width = font_get_width(pf, ch);
131
132 /* Calculate base width */
133 if (is_rtl)
138 { 134 {
139 /* Forward-seek the next non-diacritic character for base width */ 135 /* Forward-seek the next non-diacritic character for base width */
140 if (chars[i].is_diacritic) 136 if (is_diac)
141 { 137 {
142 int j; 138 if (!rtl_next_non_diacritic_width)
143 139 {
144 /* Jump to next non-diacritic character, and calc its width */ 140 unsigned j;
145 for (j = i; j < len && chars[j].is_diacritic; j++); 141
146 142 /* Jump to next non-diacritic char, and calc its width */
147 /* Set all related diacritic char's base-width accordingly */ 143 for (j = i + 1; ucs[j] && is_diacritic(ucs[j], NULL); j++);
148 for (; i <= j; i++) 144 rtl_next_non_diacritic_width = ucs[j] ?
149 chars[i].base_width = chars[j].width; 145 font_get_width(pf, ucs[j]) : 0;
146 }
147 base_width = rtl_next_non_diacritic_width;
150 } 148 }
151 else 149 else
152 { 150 {
153 chars[i].base_width = chars[i].width; 151 rtl_next_non_diacritic_width = 0; /* Mark */
152 base_width = width;
154 } 153 }
155 } 154 }
156 else 155 else
157 { 156 {
158 static int last_non_diacritic_width = 0; 157 if (!is_diac)
159 158 last_non_diacritic_width = width;
160 if (!chars[i].is_diacritic)
161 last_non_diacritic_width = chars[i].width;
162 159
163 chars[i].base_width = last_non_diacritic_width; 160 base_width = last_non_diacritic_width;
164 } 161 }
165 }
166
167 for (i = 0; i < len; i++)
168 {
169 const unsigned char *bits;
170 unsigned short ch = ucs[i];
171 int width = chars[i].width;
172 int drawmode = 0, base_ofs = 0;
173 bool next_is_diacritic;
174
175 if (x >= current_vp->width)
176 break;
177 162
178 if (ofs > width) 163 if (ofs > width)
179 { 164 {
@@ -181,36 +166,55 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
181 continue; 166 continue;
182 } 167 }
183 168
184 if (chars[i].is_diacritic) 169 if (is_diac)
185 { 170 {
171 /* XXX: Suggested by amiconn:
172 * This will produce completely wrong results if the original
173 * drawmode is DRMODE_COMPLEMENT. We need to pre-render the current
174 * character with all its diacritics at least (in mono) and then
175 * finally draw that. And we'll need an extra buffer that can hold
176 * one char's bitmap. Basically we can't just change the draw mode
177 * to something else irrespective of the original mode and expect
178 * the result to look as intended and with DRMODE_COMPLEMENT (which
179 * means XORing pixels), overdrawing this way will cause odd results
180 * if the diacritics and the base char both have common pixels set.
181 * So we need to combine the char and its diacritics in a temp
182 * buffer using OR, and then draw the final bitmap instead of the
183 * chars, without touching the drawmode
184 **/
186 drawmode = current_vp->drawmode; 185 drawmode = current_vp->drawmode;
187 current_vp->drawmode = DRMODE_FG; 186 current_vp->drawmode = DRMODE_FG;
188 187
189 base_ofs = (chars[i].base_width - width) / 2; 188 base_ofs = (base_width - width) / 2;
190 } 189 }
191 190
192 bits = font_get_bits(pf, ch); 191 bits = font_get_bits(pf, ch);
193 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, 192 LCDFN(mono_bitmap_part)(bits, ofs, 0, width, MAX(x + base_ofs, 0), y,
194 x + base_ofs, y, width - ofs, pf->height); 193 width - ofs, pf->height);
195 194
196 if (chars[i].is_diacritic) 195 if (is_diac)
197 { 196 {
198 current_vp->drawmode = drawmode; 197 current_vp->drawmode = drawmode;
199 } 198 }
200 199
201 /* Increment if next char is not diacritic (non-rtl), 200 if (next_ch)
202 * or current char is non-diacritic and next char is diacritic (rtl)*/
203 next_is_diacritic = (ucs[i + 1] && chars[i + 1].is_diacritic);
204
205 if (ucs[i + 1] &&
206 ((chars[i].is_rtl && !chars[i].is_diacritic) ||
207 (!chars[i].is_rtl && (chars[i + 1].is_rtl || !chars[i + 1].is_diacritic))))
208 { 201 {
209 x += chars[i].base_width - ofs; 202 bool next_is_rtl;
210 ofs = 0; 203 bool next_is_diacritic = is_diacritic(next_ch, &next_is_rtl);
204
205 /* Increment if:
206 * LTR: Next char is not diacritic,
207 * RTL: Current char is non-diacritic and next char is diacritic */
208 if ((is_rtl && !is_diac) ||
209 (!is_rtl && (!next_is_diacritic || next_is_rtl)))
210 {
211 x += base_width - ofs;
212 ofs = 0;
213 }
211 } 214 }
212 } 215 }
213} 216}
217
214/* put a string at a given pixel position */ 218/* put a string at a given pixel position */
215void LCDFN(putsxy)(int x, int y, const unsigned char *str) 219void LCDFN(putsxy)(int x, int y, const unsigned char *str)
216{ 220{