summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-bitmap-common.c
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/lcd-bitmap-common.c
parent507465be9447c3e3ba31d3cfaf5576ac55aed2f5 (diff)
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/lcd-bitmap-common.c')
-rw-r--r--firmware/drivers/lcd-bitmap-common.c134
1 files changed, 69 insertions, 65 deletions
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,
}
#endif
-struct lcd_bitmap_char
-{
- char is_rtl;
- char is_diacritic;
- unsigned char width;
- unsigned char base_width;
-};
-
/* put a string at a given pixel position, skipping first ofs pixel columns */
static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
{
- unsigned short *ucs;
+ unsigned short ch, *ucs;
struct font* pf = font_get(current_vp->font);
int vp_flags = current_vp->flags;
- int i, len;
- static struct lcd_bitmap_char chars[SCROLL_LINE_SIZE];
+ unsigned i;
+ static int rtl_next_non_diacritic_width, last_non_diacritic_width;
if ((vp_flags & VP_FLAG_ALIGNMENT_MASK) != 0)
{
@@ -118,62 +110,55 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
}
ucs = bidi_l2v(str, 1);
+
+ rtl_next_non_diacritic_width = 0;
+ last_non_diacritic_width = 0;
/* Mark diacritic and rtl flags for each character */
- for (i = 0; i < SCROLL_LINE_SIZE && ucs[i]; i++)
+ for (i = 0; i < SCROLL_LINE_SIZE && (ch = ucs[i]); i++)
{
- bool is_rtl;
- chars[i].is_diacritic = is_diacritic(ucs[i], &is_rtl);
- chars[i].is_rtl=is_rtl;
- }
- len = i;
+ bool is_rtl, is_diac;
+ const unsigned char *bits;
+ int width, base_width, drawmode = 0, base_ofs = 0;
+ unsigned short next_ch = ucs[i + 1];
- /* Get proportional width and glyph bits */
- for (i = 0; i < len; i++)
- chars[i].width = font_get_width(pf, ucs[i]);
+ if (x >= current_vp->width)
+ break;
- /* Calculate base width for each character */
- for (i = 0; i < len; i++)
- {
- if (chars[i].is_rtl)
+ is_diac = is_diacritic(ch, &is_rtl);
+
+ /* Get proportional width and glyph bits */
+ width = font_get_width(pf, ch);
+
+ /* Calculate base width */
+ if (is_rtl)
{
/* Forward-seek the next non-diacritic character for base width */
- if (chars[i].is_diacritic)
+ if (is_diac)
{
- int j;
-
- /* Jump to next non-diacritic character, and calc its width */
- for (j = i; j < len && chars[j].is_diacritic; j++);
-
- /* Set all related diacritic char's base-width accordingly */
- for (; i <= j; i++)
- chars[i].base_width = chars[j].width;
+ if (!rtl_next_non_diacritic_width)
+ {
+ unsigned j;
+
+ /* Jump to next non-diacritic char, and calc its width */
+ for (j = i + 1; ucs[j] && is_diacritic(ucs[j], NULL); j++);
+ rtl_next_non_diacritic_width = ucs[j] ?
+ font_get_width(pf, ucs[j]) : 0;
+ }
+ base_width = rtl_next_non_diacritic_width;
}
else
{
- chars[i].base_width = chars[i].width;
+ rtl_next_non_diacritic_width = 0; /* Mark */
+ base_width = width;
}
}
else
{
- static int last_non_diacritic_width = 0;
-
- if (!chars[i].is_diacritic)
- last_non_diacritic_width = chars[i].width;
+ if (!is_diac)
+ last_non_diacritic_width = width;
- chars[i].base_width = last_non_diacritic_width;
+ base_width = last_non_diacritic_width;
}
- }
-
- for (i = 0; i < len; i++)
- {
- const unsigned char *bits;
- unsigned short ch = ucs[i];
- int width = chars[i].width;
- int drawmode = 0, base_ofs = 0;
- bool next_is_diacritic;
-
- if (x >= current_vp->width)
- break;
if (ofs > width)
{
@@ -181,36 +166,55 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
continue;
}
- if (chars[i].is_diacritic)
+ if (is_diac)
{
+ /* XXX: Suggested by amiconn:
+ * This will produce completely wrong results if the original
+ * drawmode is DRMODE_COMPLEMENT. We need to pre-render the current
+ * character with all its diacritics at least (in mono) and then
+ * finally draw that. And we'll need an extra buffer that can hold
+ * one char's bitmap. Basically we can't just change the draw mode
+ * to something else irrespective of the original mode and expect
+ * the result to look as intended and with DRMODE_COMPLEMENT (which
+ * means XORing pixels), overdrawing this way will cause odd results
+ * if the diacritics and the base char both have common pixels set.
+ * So we need to combine the char and its diacritics in a temp
+ * buffer using OR, and then draw the final bitmap instead of the
+ * chars, without touching the drawmode
+ **/
drawmode = current_vp->drawmode;
current_vp->drawmode = DRMODE_FG;
- base_ofs = (chars[i].base_width - width) / 2;
+ base_ofs = (base_width - width) / 2;
}
bits = font_get_bits(pf, ch);
- LCDFN(mono_bitmap_part)(bits, ofs, 0, width,
- x + base_ofs, y, width - ofs, pf->height);
+ LCDFN(mono_bitmap_part)(bits, ofs, 0, width, MAX(x + base_ofs, 0), y,
+ width - ofs, pf->height);
- if (chars[i].is_diacritic)
+ if (is_diac)
{
current_vp->drawmode = drawmode;
}
- /* Increment if next char is not diacritic (non-rtl),
- * or current char is non-diacritic and next char is diacritic (rtl)*/
- next_is_diacritic = (ucs[i + 1] && chars[i + 1].is_diacritic);
-
- if (ucs[i + 1] &&
- ((chars[i].is_rtl && !chars[i].is_diacritic) ||
- (!chars[i].is_rtl && (chars[i + 1].is_rtl || !chars[i + 1].is_diacritic))))
+ if (next_ch)
{
- x += chars[i].base_width - ofs;
- ofs = 0;
+ bool next_is_rtl;
+ bool next_is_diacritic = is_diacritic(next_ch, &next_is_rtl);
+
+ /* Increment if:
+ * LTR: Next char is not diacritic,
+ * RTL: Current char is non-diacritic and next char is diacritic */
+ if ((is_rtl && !is_diac) ||
+ (!is_rtl && (!next_is_diacritic || next_is_rtl)))
+ {
+ x += base_width - ofs;
+ ofs = 0;
+ }
}
}
}
+
/* put a string at a given pixel position */
void LCDFN(putsxy)(int x, int y, const unsigned char *str)
{