utf-8 fix, a fixed patch from Sergey Kuleshov
fluxgen fluxgen
2 files changed,
128 insertions(+),
17 deletions(-)
M
src/FbTk/Font.cc
→
src/FbTk/Font.cc
@@ -1,5 +1,5 @@
// Font.cc -// Copyright (c) 2002 Henrik Kinnunen (fluxgen@linuxmail.org) +// Copyright (c) 2002-2004 Henrik Kinnunen (fluxgen@linuxmail.org) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"),@@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -//$Id: Font.cc,v 1.7 2004/06/07 11:46:05 rathnor Exp $ +//$Id: Font.cc,v 1.8 2004/08/10 11:21:50 fluxgen Exp $ #include "Font.hh"@@ -44,7 +44,6 @@ // standard font system
#include "XFontImp.hh" #include "GContext.hh" - //use gnu extensions #ifndef _GNU_SOURCE #define _GNU_SOURCE@@ -58,12 +57,59 @@ #include <iostream>
#include <cstring> #include <cstdlib> #include <typeinfo> + +#include <cstdlib> + using namespace std; #ifdef HAVE_SETLOCALE #include <locale.h> #endif //HAVE_SETLOCALE +/** + Recodes the text from one encoding to another + assuming cd is correct + @param cd the iconv type + @param msg text to be converted + @param len number of chars to convert + @return the recoded string, or 0 on failure +*/ +static char* recode(iconv_t cd, + const char *msg, size_t size) { + + // If empty message, yes this can happen, return + if(strlen(msg) == 0) + return 0; + + + size_t inbytesleft = strlen(msg); + size_t outbytesleft = 4*inbytesleft; + char *new_msg = new char[outbytesleft]; + char *new_msg_ptr = new_msg; + char *msg_ptr = strdup(msg); + + if (iconv(cd, &msg_ptr, &inbytesleft, &new_msg, &outbytesleft) == -1) { + // iconv can fail for three reasons + // 1) Invalid multibyte sequence is encountered in the input + // 2) An incomplete multibyte sequence + // 3) The output buffer has no more room for the next converted character. + // So we the delete new message and return original message + delete new_msg; + free(msg_ptr); + return 0; + } + free(msg_ptr); + + *new_msg_ptr = '\0'; + + if(inbytesleft != 0) { + delete new_msg; + return 0; + } + + return new_msg; +} + namespace FbTk { bool Font::m_multibyte = false;@@ -71,21 +117,53 @@ bool Font::m_utf8mode = false;
Font::Font(const char *name, bool antialias): m_fontimp(0), - m_antialias(false), m_rotated(false), m_shadow(false) { - + m_antialias(false), m_rotated(false), m_shadow(false), + m_iconv((iconv_t)-1) { + // MB_CUR_MAX returns the size of a char in the current locale if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte m_multibyte = true; - char *s; // temporary string for enviroment variable + char *envstr; // temporary string for enviroment variable // check for utf-8 mode - if (((s = getenv("LC_ALL")) && *s) || - ((s = getenv("LC_CTYPE")) && *s) || - ((s = getenv("LANG")) && *s)) { - if (strstr(s, "UTF-8")) + if (((envstr = getenv("LC_ALL")) && *envstr) || + ((envstr = getenv("LC_CTYPE")) && *envstr) || + ((envstr = getenv("LANG")) && *envstr)) { + if (strstr(envstr, "UTF-8")) + m_utf8mode = true; + m_locale = envstr; + int index = m_locale.find("."); + if (index != 0) + m_locale = m_locale.substr(index + 1); + else + m_locale = "UTF-8"; + } + // if locale isn't UTF-8 we try to + // create a iconv pointer so we can + // convert non utf-8 strings to utf-8 + if (m_locale != "UTF-8") { +#ifdef DEBUG + cerr<<"FbTk::Font: m_locale = "<<m_locale<<endl; +#endif // DEBUG + m_iconv = iconv_open(m_locale.c_str(), "UTF-8"); + if(m_iconv == (iconv_t)(-1)) { + cerr<<"FbTk::Font: code error: from "<<m_locale<<" to: UTF-8"<<endl; + // if we failed with iconv then we can't convert + // the strings to utf-8, so we disable utf8 mode + m_utf8mode = false; + } else { + // success, we can now enable utf8mode + // and if antialias is on later we can recode + // the non utf-8 string to utf-8 and use utf-8 + // drawing functions m_utf8mode = true; + } } +#ifdef DEBUG + cerr<<"FbTk::Font m_iconv = "<<(int)m_iconv<<endl; +#endif // DEBUG + // create the right font implementation // antialias is prio 1 #ifdef USE_XFT@@ -103,7 +181,7 @@ else // basic font implementation
#endif // USE_XMB m_fontimp.reset(new XFontImp()); } - + if (name != 0) { load(name); }@@ -111,7 +189,8 @@
} Font::~Font() { - + if (m_iconv != (iconv_t)(-1)) + iconv_close(m_iconv); } void Font::setAntialias(bool flag) {@@ -186,6 +265,16 @@ return m_fontimp->load(new_name.c_str());
} unsigned int Font::textWidth(const char * const text, unsigned int size) const { + if (isAntialias() && m_iconv != (iconv_t)(-1)) { + char* rtext = recode(m_iconv, text, size); + if (rtext != 0) + size = strlen(rtext); + unsigned int r = m_fontimp->textWidth(rtext ? rtext : text, size); + if (rtext != 0) + delete rtext; + return r; + } + return m_fontimp->textWidth(text, size); }@@ -200,21 +289,35 @@
int Font::descent() const { return m_fontimp->descent(); } + void Font::drawText(Drawable w, int screen, GC gc, const char *text, size_t len, int x, int y, bool rotate) const { if (text == 0 || len == 0) return; + char* rtext = 0; + // so we don't end up in a loop with m_shadow static bool first_run = true; + if (isAntialias() && m_iconv != (iconv_t)(-1) && first_run) { + rtext = recode(m_iconv, text, len); + if (rtext != 0) { + len = strlen(rtext); + // ok, we can't use utf8 mode since the string is invalid + } + } + + + const char *real_text = rtext ? rtext : text; + // draw shadow first if (first_run && m_shadow) { FbTk::GContext shadow_gc(w); shadow_gc.setForeground(FbTk::Color("black", screen)); first_run = false; // so we don't end up in a loop - drawText(w, screen, shadow_gc.gc(), text, len, x + 1, y + 1); + drawText(w, screen, shadow_gc.gc(), real_text, len, x + 1, y + 1); first_run = true; }@@ -228,16 +331,18 @@ try {
XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp.get()); font->setRotate(false); // disable rotation temporarly - font->drawText(w, screen, gc, text, len, x, y); + font->drawText(w, screen, gc, real_text, len, x, y); font->setRotate(true); // enable rotation } catch (std::bad_cast &bc) { // draw normal... - m_fontimp->drawText(w, screen, gc, text, len, x, y); + m_fontimp->drawText(w, screen, gc, real_text, len, x, y); } } else - m_fontimp->drawText(w, screen, gc, text, len, x, y); + m_fontimp->drawText(w, screen, gc, real_text, len, x, y); + if (rtext != 0) + delete rtext; }@@ -263,4 +368,6 @@ m_rotated = (angle == 0 ? false : true);
m_angle = angle; } + }; +
M
src/FbTk/Font.hh
→
src/FbTk/Font.hh
@@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -//$Id: Font.hh,v 1.7 2003/12/19 17:07:53 fluxgen Exp $ +//$Id: Font.hh,v 1.8 2004/08/10 11:22:10 fluxgen Exp $ #ifndef FBTK_FONT_HH #define FBTK_FONT_HH@@ -29,6 +29,8 @@ #include <X11/Xresource.h>
#include <string> #include <memory> + +#include <iconv.h> namespace FbTk {@@ -100,6 +102,8 @@ bool m_antialias; ///< is font antialias
bool m_rotated; ///< wheter we're rotated or not float m_angle; ///< rotation angle bool m_shadow; ///< shadow text + std::string m_locale; ///< system encoding + iconv_t m_iconv; }; } //end namespace FbTk