Index: firmware/font.c =================================================================== --- firmware/font.c (revision 23650) +++ firmware/font.c (working copy) @@ -35,6 +35,7 @@ #include "debug.h" #include "panic.h" #include "rbunicode.h" +#include "diacritic.h" #ifndef BOOTLOADER /* Font cache includes */ @@ -604,6 +605,8 @@ for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch)) { + if (is_diacritic(ch, NULL)) + continue; /* get proportional width and glyph bits*/ width += font_get_width(pf,ch); Index: firmware/SOURCES =================================================================== --- firmware/SOURCES (revision 23650) +++ firmware/SOURCES (working copy) @@ -95,6 +95,7 @@ drivers/lcd-16bit.c #endif #endif /* LCD_DEPTH */ +drivers/diacritic.c #endif /* HAVE_LCD_BITMAP */ #ifdef HAVE_REMOTE_LCD Index: firmware/include/diacritic.h =================================================================== --- firmware/include/diacritic.h (revision 0) +++ firmware/include/diacritic.h (revision 0) @@ -0,0 +1,26 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: dir.h 18950 2008-10-31 21:25:04Z gevaerts $ + * + * Copyright (C) 2009 Phinitnun Chanasabaeng + * + * 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. + * + ****************************************************************************/ +#ifndef _DIACRITIC_H_ +#define _DIACRITIC_H_ +#include "system.h" + +int is_diacritic(unsigned short ch, bool *is_rtl); +#endif Index: firmware/drivers/lcd-bitmap-common.c =================================================================== --- firmware/drivers/lcd-bitmap-common.c (revision 23650) +++ firmware/drivers/lcd-bitmap-common.c (working copy) @@ -29,6 +29,7 @@ ****************************************************************************/ #include "stdarg.h" #include "sprintf.h" +#include "diacritic.h" #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */ #define LCDFN(fn) lcd_ ## fn @@ -79,16 +80,23 @@ } #endif +struct lcd_bitmap_char +{ + bool is_rtl; + bool is_diacritic; + int width; + int 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 ch; unsigned short *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]; - ucs = bidi_l2v(str, 1); - if ((vp_flags & VP_FLAG_ALIGNMENT_MASK) != 0) { int w; @@ -109,13 +117,59 @@ } } - while ((ch = *ucs++) != 0 && x < current_vp->width) + ucs = bidi_l2v(str, 1); + /* Mark diacritic and rtl flags for each character */ + for (i = 0; i < SCROLL_LINE_SIZE && ucs[i]; i++) + chars[i].is_diacritic = is_diacritic(ucs[i], &chars[i].is_rtl); + len = i; + + /* Get proportional width and glyph bits */ + for (i = 0; i < len; i++) + chars[i].width = font_get_width(pf, ucs[i]); + + /* Calculate base width for each character */ + for (i = 0; i < len; i++) { - int width; + if (chars[i].is_rtl) + { + /* Forward-seek the next non-diacritic character for base width */ + if (chars[i].is_diacritic) + { + 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; + } + else + { + chars[i].base_width = chars[i].width; + } + } + else + { + static int last_non_diacritic_width = 0; + + if (!chars[i].is_diacritic) + last_non_diacritic_width = chars[i].width; + + chars[i].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; - /* get proportional width and glyph bits */ - width = font_get_width(pf, ch); + if (x >= current_vp->width) + break; if (ofs > width) { @@ -123,13 +177,34 @@ continue; } + if (chars[i].is_diacritic) + { + drawmode = current_vp->drawmode; + current_vp->drawmode = DRMODE_FG; + + base_ofs = (chars[i].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, x, y, width - ofs, - pf->height); + if (chars[i].is_diacritic) + { + current_vp->drawmode = drawmode; + } - x += width - ofs; - ofs = 0; + /* 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)))) + { + x += chars[i].base_width - ofs; + ofs = 0; + } } } /* put a string at a given pixel position */ Index: firmware/drivers/diacritic.c =================================================================== --- firmware/drivers/diacritic.c (revision 0) +++ firmware/drivers/diacritic.c (revision 0) @@ -0,0 +1,182 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 Phinitnun Chanasabaeng + * + * Rockbox diacritic positioning + * + * 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 "diacritic.h" +#include "system.h" + +struct diac_range +{ + unsigned short begin; + unsigned short end; + bool is_rtl; +}; + +/* sorted by its unicode value */ +const struct diac_range diacritic[] = +{ + {0x0300, 0x0357, 0}, /* Combining Diacritical Marks */ + {0x035d, 0x036f, 0}, + {0x0483, 0x0489, 0}, /* Cyrillic */ + {0x0591, 0x05bd, 1}, /* Hebrew */ + {0x05bf, 0x05bf, 1}, + {0x05c1, 0x05c2, 1}, + {0x05c4, 0x05c5, 1}, + {0x05c7, 0x05c7, 1}, + {0x0610, 0x061a, 1}, /* Arabic */ + {0x064b, 0x0658, 1}, + {0x0670, 0x0670, 1}, + {0x06d6, 0x06dc, 1}, + {0x06df, 0x06e4, 1}, + {0x06e7, 0x06e8, 1}, + {0x06ea, 0x06ed, 1}, + {0x0711, 0x0711, 0}, /* Syriac */ + {0x0730, 0x074a, 0}, + {0x07a6, 0x07b0, 0}, /* Thaana */ + {0x0816, 0x0819, 0}, /* Samaritan */ + {0x081b, 0x0823, 0}, + {0x0825, 0x0827, 0}, + {0x0829, 0x082d, 0}, + {0x0900, 0x0903, 0}, /* Devanagari */ + {0x093c, 0x093c, 0}, + {0x093e, 0x094e, 0}, + {0x0951, 0x0955, 0}, + {0x0962, 0x0963, 0}, + {0x0981, 0x0983, 0}, /* Bengali */ + {0x09bc, 0x09bc, 0}, + {0x09be, 0x09cd, 0}, + {0x09d7, 0x09d7, 0}, + {0x09e2, 0x09e3, 0}, + {0x0a01, 0x0a03, 0}, /* Gurmukhi */ + {0x0a3c, 0x0a51, 0}, + {0x0a70, 0x0a71, 0}, + {0x0a75, 0x0a75, 0}, + {0x0a81, 0x0a83, 0}, /* Gujarati */ + {0x0abc, 0x0abc, 0}, + {0x0abe, 0x0acd, 0}, + {0x0ae2, 0x0ae3, 0}, + {0x0b01, 0x0b03, 0}, /* Oriya */ + {0x0b3c, 0x0b3c, 0}, + {0x0b3e, 0x0b57, 0}, + {0x0b82, 0x0b82, 0}, /* Tamil */ + {0x0bce, 0x0bed, 0}, + {0x0bd7, 0x0bd7, 0}, + {0x0c01, 0x0c03, 0}, /* Telugu */ + {0x0c3e, 0x0c56, 0}, + {0x0c82, 0x0c83, 0}, /* Kannada */ + {0x0cbc, 0x0cd6, 0}, + {0x0ce3, 0x0ce3, 0}, + {0x0d4a, 0x0d4c, 0}, /* Malayalam */ + {0x0d82, 0x0d83, 0}, /* Sinhala */ + {0x0dca, 0x0df3, 0}, + {0x0e31, 0x0e31, 0}, /* Thai */ + {0x0e34, 0x0e3a, 0}, + {0x0e47, 0x0e4e, 0}, + {0x0eb1, 0x0eb1, 0}, /* Lao */ + {0x0eb4, 0x0ebc, 0}, + {0x0ec8, 0x0ecd, 0}, + {0x102b, 0x103e, 0}, /* Myanmar */ + {0x1056, 0x1059, 0}, + {0x105e, 0x1060, 0}, + {0x1062, 0x1064, 0}, + {0x1067, 0x106d, 0}, + {0x1071, 0x1074, 0}, + {0x1082, 0x108d, 0}, + {0x108f, 0x108f, 0}, + {0x109a, 0x109d, 0}, + {0x1732, 0x1734, 0}, /* Hanunoo */ + {0x1752, 0x1753, 0}, /* Buhid */ + {0x1772, 0x1773, 0}, /* Tagbanwa */ + {0x17b6, 0x17d3, 0}, /* Khmer */ + {0x17dd, 0x17dd, 0}, + {0x1920, 0x193b, 0}, /* Limbu */ + {0x1a55, 0x1a7f, 0}, /* Tai Tham */ + {0x1b00, 0x1b04, 0}, /* Balinese */ + {0x1b34, 0x1b44, 0}, + {0x1b6b, 0x1b73, 0}, + {0x1b80, 0x1b82, 0}, /* Sundanese */ + {0x1ba1, 0x1baa, 0}, + {0x1c24, 0x1c37, 0}, /* Lepcha */ + {0x1cd0, 0x1cd2, 0}, /* Vedic Extensions */ + {0x1cd4, 0x1ce8, 0}, + {0x1ced, 0x1ced, 0}, + {0x1cf2, 0x1cf2, 0}, + {0x1dc0, 0x1de6, 0}, /* Combining Diacritical Marks Supplement */ + {0x1dfd, 0x1dff, 0}, + {0x20d0, 0x20ea, 0}, /* Combining Diacritical Marks for Symbols */ + {0x20ee, 0x20f0, 0}, + {0x2de0, 0x2dff, 0}, /* Cyrillic Extended-A */ + {0x3099, 0x309a, 0}, /* Hiragana */ + {0xa6f0, 0xa6f1, 0}, /* Bamum */ + {0xa8e0, 0xa8f1, 0}, /* Devanagari Extended */ + {0xa947, 0xa949, 0}, /* Rejang */ + {0xa94b, 0xa94d, 0}, + {0xa980, 0xa983, 0}, /* Javanese */ + {0xa9b3, 0xa9c0, 0}, + {0xaa7b, 0xaa7b, 0}, /* Myanmar Extended-A */ + {0xaab0, 0xaab0, 0}, /* Tai Viet */ + {0xaab2, 0xaab4, 0}, + {0xaab7, 0xaab8, 0}, + {0xaabe, 0xaabf, 0}, + {0xaac1, 0xaac1, 0}, + {0xabe3, 0xabea, 0}, /* Meetei Mayek */ + {0xabec, 0xabed, 0}, + {0xfb1e, 0xfb1e, 0}, /* Alpha Presentation Forms */ + {0xfe20, 0xfe26, 0}, /* Combining Half Marks */ +}; + +int is_diacritic(unsigned short ch, bool *is_rtl) +{ + static unsigned int prev_index = 0; /* set up previous index */ + unsigned int n; + + /* ignore groups of non-diacritic character to avoid searching */ + if ((ch >= 0x0020 && ch <= 0x02ff) || /* Latin and its extended. */ + (ch >= 0x0370 && ch <= 0x03ff) || + (ch >= 0x10a0 && ch <= 0x1714) || + (ch >= 0x2100 && ch <= 0x2ddd) || + (ch >= 0x3100 && ch <= 0xa697) || + (ch >= 0xac00 && ch <= 0xfad9)) + { + return 0; + } + + for (n = prev_index; n < ARRAYLEN(diacritic); n++) + { + if (ch >= diacritic[n].begin && ch <= diacritic[n].end) + { + prev_index = n; + if (is_rtl) + *is_rtl = diacritic[n].is_rtl; + + return 1; + } + } + + if (prev_index) /* if not found when stated at prev_index */ + { + prev_index = 0; /* reset previous index */ + + return is_diacritic(ch, is_rtl); + } + + return 0; +}