diff options
Diffstat (limited to 'src/xine-engine/osd.c')
-rw-r--r-- | src/xine-engine/osd.c | 300 |
1 files changed, 191 insertions, 109 deletions
diff --git a/src/xine-engine/osd.c b/src/xine-engine/osd.c index 98f1732e0..2df12d51f 100644 --- a/src/xine-engine/osd.c +++ b/src/xine-engine/osd.c @@ -60,8 +60,15 @@ #define BINARY_SEARCH 1 -/* unicode value of alias character (it used if conversion fails) */ -#define ALIAS_CHARACTER ' ' +/* unicode value of alias character, + * used if conversion fails + */ +#define ALIAS_CHARACTER_CONV '#' + +/* unicode value of alias character, + * used if character isn't in the font + */ +#define ALIAS_CHARACTER_FONT '_' #ifdef MAX #undef MAX @@ -131,7 +138,12 @@ static osd_object_t *osd_new_object (osd_renderer_t *this, int width, int height memcpy(osd->trans, textpalettes_trans[0], sizeof(textpalettes_trans[0])); osd->handle = -1; - + +#ifndef _MSC_VER + osd->cd = (iconv_t)-1; + osd->encoding = NULL; +#endif + pthread_mutex_unlock (&this->osd_mutex); #ifdef LOG_DEBUG @@ -711,36 +723,141 @@ static int osd_set_font( osd_object_t *osd, const char *fontname, int size) { } -#ifdef BINARY_SEARCH /* - * search the character in the sorted array + * search the character in the sorted array, + * + * returns ALIAS_CHARACTER_FONT if character 'code' isn't found, + * returns 'n' on error */ -static int binsearch(osd_fontchar_t *array, size_t n, uint16_t code) { +static int osd_search(osd_fontchar_t *array, size_t n, uint16_t code) { +#ifdef BINARY_SEARCH size_t i, left, right; if (!n) return 0; left = 0; right = n - 1; - while (right > left) { + while (left < right) { i = (left + right) >> 1; if (code <= array[i].code) right = i; else left = i + 1; } - return array[right].code == code ? right : n; + if (array[right].code == code) + return right; + else + return ALIAS_CHARACTER_FONT < n ? ALIAS_CHARACTER_FONT : n; +#else + size_t i; + + for( i = 0; i < n; i++ ) { + if( font->fontchar[i].code == unicode ) + break; + } + + if (i < n) + return i; + else + return ALIAS_CHARACTER_FONT < n ? ALIAS_CHARACTER_FONT : n; +#endif +} + + +#ifndef _MSC_VER +/* + * get next unicode value + */ +static uint16_t osd_iconv_getunicode(iconv_t *cd, const char *encoding, char **inbuf, size_t *inbytesleft) { + uint16_t unicode; + char *outbuf = (char*)&unicode; + size_t outbytesleft = 2; + size_t count; + + if (cd != (iconv_t)-1) { + /* get unicode value from iconv */ + count = iconv(cd, inbuf, inbytesleft, &outbuf, &outbytesleft); + if (count == (size_t)-1 && errno != E2BIG) { + /* unknown character or character wider than 16 bits, try skip one byte */ + printf(_("osd: unknown sequence starting with byte 0x%02X" + " in encoding \"%s\", skipping\n"), (*inbuf)[0] & 0xFF, encoding); + if (*inbytesleft) { + (*inbytesleft)--; + (*inbuf)++; + } + return ALIAS_CHARACTER_CONV; + } + } else { + /* direct mapping without iconv */ + unicode = (*inbuf)[0]; + (*inbuf)++; + (*inbytesleft)--; + } + + return unicode; +} +#endif + + +/* + * free iconv encoding + */ +static void osd_free_encoding(osd_object_t *osd) { +#ifndef _MSC_VER + if (osd->cd != (iconv_t)-1) { + iconv_close(osd->cd); + osd->cd = (iconv_t)-1; + } + if (osd->encoding) { + free(osd->encoding); + osd->encoding = NULL; + } +#endif } + + +/* + * set encoding of text + * + * NULL ... no conversion (iso-8859-1) + * "" ... locale encoding + */ +static int osd_set_encoding (osd_object_t *osd, const char *encoding) { +#ifndef _MSC_VER + osd_free_encoding(osd); + + if (!encoding) return 1; + if (!encoding[0]) { +#ifdef HAVE_LANGINFO_CODESET + if ((encoding = nl_langinfo(CODESET)) == NULL) { + printf(_("osd: can't find out current locale character set\n")); + return 0; + } +#else + return 0; #endif + } + + /* prepare conversion to UCS-2 */ + if ((osd->cd = iconv_open("UCS-2", encoding)) == (iconv_t)-1) { + printf(_("osd: unsupported conversion %s -> UCS-2, " + "no conversion performed\n"), encoding); + return 0; + } + + osd->encoding = strdup(encoding); + return 1; +#else + return encoding == NULL; +#endif /* _MSC_VER */ +} /* - * render text on x,y position + * render text in current encoding on x,y position * no \n yet - * if encoding == NULL current locale encoding is used */ static int osd_render_text (osd_object_t *osd, int x1, int y1, - const char *text, const char *encoding, - int color_base) { + const char *text, int color_base) { osd_renderer_t *this = osd->renderer; osd_font_t *font; @@ -750,10 +867,6 @@ static int osd_render_text (osd_object_t *osd, int x1, int y1, uint16_t unicode; size_t inbytesleft; -#ifndef _MSC_VER - iconv_t cd; -#endif /* _MSC_VER */ - #ifdef LOG_DEBUG printf("osd_render_text %p (%d,%d) \"%s\"\n", osd, x1, y1, text); #endif @@ -786,53 +899,16 @@ static int osd_render_text (osd_object_t *osd, int x1, int y1, inbuf = text; inbytesleft = strlen(text); - - if (!encoding) { -#ifdef HAVE_LANGINFO_CODESET - if ((encoding = nl_langinfo(CODESET)) == NULL) { - printf(_("osd: can't find out current locale character set\n")); - encoding = "iso-8859-1"; - } -#else - encoding = "iso-8859-1"; -#endif - } - -#ifndef _MSC_VER - /* prepare conversion to UCS-2 */ - if ((cd = iconv_open("UCS-2", encoding)) == (iconv_t)-1) { - printf(_("osd: unsupported conversion %s -> UCS-2, " - "no conversion performed\n"), encoding); - } -#endif /* _MSC_VER */ while( inbytesleft ) { - char *outbuf = (char*)&unicode; - size_t outbytesleft = 2; - size_t count; - #ifndef _MSC_VER - if (cd == (iconv_t)-1) { - /* direct mapping without iconv */ - unicode = inbuf[0]; - inbuf++; - inbytesleft--; - } else { - /* get unicode value from iconv */ - /* FIXME: we cast away the const from inbuf; Why is iconv() not const here, - * does it change inbuf? */ - count = iconv(cd, (char **)&inbuf, &inbytesleft, &outbuf, &outbytesleft); - if (count == (size_t)-1 && errno != E2BIG) { - /* unknown character or character wider than 16 bits, try skip one byte */ - printf(_("osd: unknown sequence starting with byte 0x%02X" - " in encoding \"%s\", skipping\n"), inbuf[0] & 0xFF, encoding); - if (!inbytesleft) break; - inbytesleft--; - inbuf++; - unicode = ALIAS_CHARACTER; - } - } -#endif /* _MSC_VER */ + unicode = osd_iconv_getunicode(osd->cd, osd->encoding, + (char **)&inbuf, &inbytesleft); +#else + unicode = inbuf[0]; + inbuf++; + inbytesleft--; +#endif #ifdef HAVE_FT2 if (osd->ft2 && osd->ft2->useme) { @@ -840,14 +916,7 @@ static int osd_render_text (osd_object_t *osd, int x1, int y1, } else { #endif -#ifdef BINARY_SEARCH - i = binsearch(font->fontchar, font->num_fontchars, unicode); -#else - for( i = 0; i < font->num_fontchars; i++ ) { - if( font->fontchar[i].code == unicode ) - break; - } -#endif + i = osd_search(font->fontchar, font->num_fontchars, unicode); #ifdef LOG_DEBUG printf("font %s [%d, U+%04X == U+%04X] %dx%d -> %d,%d\n", font->name, i, @@ -933,12 +1002,6 @@ static int osd_render_text (osd_object_t *osd, int x1, int y1, } -#ifndef _MSC_VER - if (cd != (iconv_t)-1) { - iconv_close(cd); - } -#endif /* _MSC_VER */ - pthread_mutex_unlock (&this->osd_mutex); return 1; @@ -951,7 +1014,10 @@ static int osd_get_text_size(osd_object_t *osd, const char *text, int *width, in osd_renderer_t *this = osd->renderer; osd_font_t *font; - int i, c; + int i; + const char *inbuf; + uint16_t unicode; + size_t inbytesleft; #ifdef LOG_DEBUG printf("osd_get_text_size %p \"%s\"\n", osd, text); @@ -959,28 +1025,52 @@ static int osd_get_text_size(osd_object_t *osd, const char *text, int *width, in pthread_mutex_lock (&this->osd_mutex); - font = osd->font; - + { + int proceed = 0; + + if ((font = osd->font)) proceed = 1; +#ifdef HAVE_FT2 + if (osd->ft2 && osd->ft2->useme) proceed = 1; +#endif + + if (proceed == 0) { + printf(_("osd: font isn't defined\n")); + pthread_mutex_unlock(&this->osd_mutex); + return 0; + } + } + *width = 0; *height = 0; + inbuf = text; + inbytesleft = strlen(text); + + while( inbytesleft ) { +#ifndef _MSC_VER + unicode = osd_iconv_getunicode(osd->cd, osd->encoding, + (char **)&inbuf, &inbytesleft); +#else + unicode = inbuf[0]; + inbuf++; + inbytesleft--; +#endif + #ifdef HAVE_FT2 - if (osd->ft2 && osd->ft2->useme) { - int first = 1; - FT_GlyphSlot slot = osd->ft2->face->glyph; - - while (*text) { - - i = FT_Get_Char_Index( osd->ft2->face, *text); - + if (osd->ft2 && osd->ft2->useme) { + int first = 1; + FT_GlyphSlot slot = osd->ft2->face->glyph; + + i = FT_Get_Char_Index( osd->ft2->face, unicode); + if (FT_Load_Glyph(osd->ft2->face, i, FT_LOAD_DEFAULT)) { - printf("osd: error loading glyph %i\n", i); - text++; - continue; + printf("osd: error loading glyph %i\n", i); + text++; + continue; } if (slot->format != ft_glyph_format_bitmap) { - if (FT_Render_Glyph(osd->ft2->face->glyph, ft_render_mode_normal)) + if (FT_Render_Glyph(osd->ft2->face->glyph, ft_render_mode_normal)) printf("osd: error in rendering\n"); } if (first) *width += slot->bitmap_left; @@ -989,29 +1079,19 @@ static int osd_get_text_size(osd_object_t *osd, const char *text, int *width, in /* font height from baseline to top */ *height = MAX(*height, slot->bitmap_top); text++; - } - } else { + } else { #endif - - while( font && *text ) { - c = *text & 0xff; - - for( i = 0; i < font->num_fontchars; i++ ) { - if( font->fontchar[i].code == c ) - break; - } - - if ( i != font->num_fontchars ) { - if( font->fontchar[i].height > *height ) - *height = font->fontchar[i].height; - *width += font->fontchar[i].width; - } - text++; - } + i = osd_search(font->fontchar, font->num_fontchars, unicode); + if ( i != font->num_fontchars ) { + if( font->fontchar[i].height > *height ) + *height = font->fontchar[i].height; + *width += font->fontchar[i].width; + } #ifdef HAVE_FT2 - } /* !(osd->ft2 && osd->ft2->useme) */ + } /* !(osd->ft2 && osd->ft2->useme) */ #endif + } pthread_mutex_unlock (&this->osd_mutex); @@ -1090,13 +1170,14 @@ static void osd_free_object (osd_object_t *osd_to_close) { while( osd ) { if ( osd == osd_to_close ) { free( osd->area ); + if( osd->ft2 ) free( osd->ft2 ); + osd_free_encoding(osd); if( last ) last->next = osd->next; else this->osds = osd->next; - if( osd->ft2 ) free( osd->ft2 ); free( osd ); break; } @@ -1214,6 +1295,7 @@ osd_renderer_t *osd_renderer_init( video_overlay_manager_t *video_overlay, confi this->point = osd_point; this->line = osd_line; this->filled_rect = osd_filled_rect; + this->set_encoding = osd_set_encoding; this->render_text = osd_render_text; this->get_text_size = osd_get_text_size; this->close = osd_renderer_close; |