diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/diacritic.c | 2 | ||||
-rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 134 |
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 | ||
83 | struct 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 */ |
92 | static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) | 84 | static 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 */ |
215 | void LCDFN(putsxy)(int x, int y, const unsigned char *str) | 219 | void LCDFN(putsxy)(int x, int y, const unsigned char *str) |
216 | { | 220 | { |