diff options
Diffstat (limited to 'src/FbTk/Font.cc')
-rw-r--r-- | src/FbTk/Font.cc | 139 |
1 files changed, 123 insertions, 16 deletions
diff --git a/src/FbTk/Font.cc b/src/FbTk/Font.cc index 453a195..75d89f1 100644 --- a/src/FbTk/Font.cc +++ b/src/FbTk/Font.cc | |||
@@ -1,5 +1,5 @@ | |||
1 | // Font.cc | 1 | // Font.cc |
2 | // Copyright (c) 2002 Henrik Kinnunen (fluxgen@linuxmail.org) | 2 | // Copyright (c) 2002-2004 Henrik Kinnunen (fluxgen@linuxmail.org) |
3 | // | 3 | // |
4 | // Permission is hereby granted, free of charge, to any person obtaining a | 4 | // Permission is hereby granted, free of charge, to any person obtaining a |
5 | // copy of this software and associated documentation files (the "Software"), | 5 | // copy of this software and associated documentation files (the "Software"), |
@@ -19,7 +19,7 @@ | |||
19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
20 | // DEALINGS IN THE SOFTWARE. | 20 | // DEALINGS IN THE SOFTWARE. |
21 | 21 | ||
22 | //$Id: Font.cc,v 1.7 2004/06/07 11:46:05 rathnor Exp $ | 22 | //$Id: Font.cc,v 1.8 2004/08/10 11:21:50 fluxgen Exp $ |
23 | 23 | ||
24 | 24 | ||
25 | #include "Font.hh" | 25 | #include "Font.hh" |
@@ -44,7 +44,6 @@ | |||
44 | #include "XFontImp.hh" | 44 | #include "XFontImp.hh" |
45 | 45 | ||
46 | #include "GContext.hh" | 46 | #include "GContext.hh" |
47 | |||
48 | //use gnu extensions | 47 | //use gnu extensions |
49 | #ifndef _GNU_SOURCE | 48 | #ifndef _GNU_SOURCE |
50 | #define _GNU_SOURCE | 49 | #define _GNU_SOURCE |
@@ -58,12 +57,59 @@ | |||
58 | #include <cstring> | 57 | #include <cstring> |
59 | #include <cstdlib> | 58 | #include <cstdlib> |
60 | #include <typeinfo> | 59 | #include <typeinfo> |
60 | |||
61 | #include <cstdlib> | ||
62 | |||
61 | using namespace std; | 63 | using namespace std; |
62 | 64 | ||
63 | #ifdef HAVE_SETLOCALE | 65 | #ifdef HAVE_SETLOCALE |
64 | #include <locale.h> | 66 | #include <locale.h> |
65 | #endif //HAVE_SETLOCALE | 67 | #endif //HAVE_SETLOCALE |
66 | 68 | ||
69 | /** | ||
70 | Recodes the text from one encoding to another | ||
71 | assuming cd is correct | ||
72 | @param cd the iconv type | ||
73 | @param msg text to be converted | ||
74 | @param len number of chars to convert | ||
75 | @return the recoded string, or 0 on failure | ||
76 | */ | ||
77 | static char* recode(iconv_t cd, | ||
78 | const char *msg, size_t size) { | ||
79 | |||
80 | // If empty message, yes this can happen, return | ||
81 | if(strlen(msg) == 0) | ||
82 | return 0; | ||
83 | |||
84 | |||
85 | size_t inbytesleft = strlen(msg); | ||
86 | size_t outbytesleft = 4*inbytesleft; | ||
87 | char *new_msg = new char[outbytesleft]; | ||
88 | char *new_msg_ptr = new_msg; | ||
89 | char *msg_ptr = strdup(msg); | ||
90 | |||
91 | if (iconv(cd, &msg_ptr, &inbytesleft, &new_msg, &outbytesleft) == -1) { | ||
92 | // iconv can fail for three reasons | ||
93 | // 1) Invalid multibyte sequence is encountered in the input | ||
94 | // 2) An incomplete multibyte sequence | ||
95 | // 3) The output buffer has no more room for the next converted character. | ||
96 | // So we the delete new message and return original message | ||
97 | delete new_msg; | ||
98 | free(msg_ptr); | ||
99 | return 0; | ||
100 | } | ||
101 | free(msg_ptr); | ||
102 | |||
103 | *new_msg_ptr = '\0'; | ||
104 | |||
105 | if(inbytesleft != 0) { | ||
106 | delete new_msg; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | return new_msg; | ||
111 | } | ||
112 | |||
67 | namespace FbTk { | 113 | namespace FbTk { |
68 | 114 | ||
69 | bool Font::m_multibyte = false; | 115 | bool Font::m_multibyte = false; |
@@ -71,21 +117,53 @@ bool Font::m_utf8mode = false; | |||
71 | 117 | ||
72 | Font::Font(const char *name, bool antialias): | 118 | Font::Font(const char *name, bool antialias): |
73 | m_fontimp(0), | 119 | m_fontimp(0), |
74 | m_antialias(false), m_rotated(false), m_shadow(false) { | 120 | m_antialias(false), m_rotated(false), m_shadow(false), |
75 | 121 | m_iconv((iconv_t)-1) { | |
122 | |||
76 | // MB_CUR_MAX returns the size of a char in the current locale | 123 | // MB_CUR_MAX returns the size of a char in the current locale |
77 | if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte | 124 | if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte |
78 | m_multibyte = true; | 125 | m_multibyte = true; |
79 | 126 | ||
80 | char *s; // temporary string for enviroment variable | 127 | char *envstr; // temporary string for enviroment variable |
81 | // check for utf-8 mode | 128 | // check for utf-8 mode |
82 | if (((s = getenv("LC_ALL")) && *s) || | 129 | if (((envstr = getenv("LC_ALL")) && *envstr) || |
83 | ((s = getenv("LC_CTYPE")) && *s) || | 130 | ((envstr = getenv("LC_CTYPE")) && *envstr) || |
84 | ((s = getenv("LANG")) && *s)) { | 131 | ((envstr = getenv("LANG")) && *envstr)) { |
85 | if (strstr(s, "UTF-8")) | 132 | if (strstr(envstr, "UTF-8")) |
86 | m_utf8mode = true; | 133 | m_utf8mode = true; |
134 | m_locale = envstr; | ||
135 | int index = m_locale.find("."); | ||
136 | if (index != 0) | ||
137 | m_locale = m_locale.substr(index + 1); | ||
138 | else | ||
139 | m_locale = "UTF-8"; | ||
140 | } | ||
141 | // if locale isn't UTF-8 we try to | ||
142 | // create a iconv pointer so we can | ||
143 | // convert non utf-8 strings to utf-8 | ||
144 | if (m_locale != "UTF-8") { | ||
145 | #ifdef DEBUG | ||
146 | cerr<<"FbTk::Font: m_locale = "<<m_locale<<endl; | ||
147 | #endif // DEBUG | ||
148 | m_iconv = iconv_open(m_locale.c_str(), "UTF-8"); | ||
149 | if(m_iconv == (iconv_t)(-1)) { | ||
150 | cerr<<"FbTk::Font: code error: from "<<m_locale<<" to: UTF-8"<<endl; | ||
151 | // if we failed with iconv then we can't convert | ||
152 | // the strings to utf-8, so we disable utf8 mode | ||
153 | m_utf8mode = false; | ||
154 | } else { | ||
155 | // success, we can now enable utf8mode | ||
156 | // and if antialias is on later we can recode | ||
157 | // the non utf-8 string to utf-8 and use utf-8 | ||
158 | // drawing functions | ||
159 | m_utf8mode = true; | ||
160 | } | ||
87 | } | 161 | } |
88 | 162 | ||
163 | #ifdef DEBUG | ||
164 | cerr<<"FbTk::Font m_iconv = "<<(int)m_iconv<<endl; | ||
165 | #endif // DEBUG | ||
166 | |||
89 | // create the right font implementation | 167 | // create the right font implementation |
90 | // antialias is prio 1 | 168 | // antialias is prio 1 |
91 | #ifdef USE_XFT | 169 | #ifdef USE_XFT |
@@ -103,7 +181,7 @@ Font::Font(const char *name, bool antialias): | |||
103 | #endif // USE_XMB | 181 | #endif // USE_XMB |
104 | m_fontimp.reset(new XFontImp()); | 182 | m_fontimp.reset(new XFontImp()); |
105 | } | 183 | } |
106 | 184 | ||
107 | if (name != 0) { | 185 | if (name != 0) { |
108 | load(name); | 186 | load(name); |
109 | } | 187 | } |
@@ -111,7 +189,8 @@ Font::Font(const char *name, bool antialias): | |||
111 | } | 189 | } |
112 | 190 | ||
113 | Font::~Font() { | 191 | Font::~Font() { |
114 | 192 | if (m_iconv != (iconv_t)(-1)) | |
193 | iconv_close(m_iconv); | ||
115 | } | 194 | } |
116 | 195 | ||
117 | void Font::setAntialias(bool flag) { | 196 | void Font::setAntialias(bool flag) { |
@@ -186,6 +265,16 @@ bool Font::load(const std::string &name) { | |||
186 | } | 265 | } |
187 | 266 | ||
188 | unsigned int Font::textWidth(const char * const text, unsigned int size) const { | 267 | unsigned int Font::textWidth(const char * const text, unsigned int size) const { |
268 | if (isAntialias() && m_iconv != (iconv_t)(-1)) { | ||
269 | char* rtext = recode(m_iconv, text, size); | ||
270 | if (rtext != 0) | ||
271 | size = strlen(rtext); | ||
272 | unsigned int r = m_fontimp->textWidth(rtext ? rtext : text, size); | ||
273 | if (rtext != 0) | ||
274 | delete rtext; | ||
275 | return r; | ||
276 | } | ||
277 | |||
189 | return m_fontimp->textWidth(text, size); | 278 | return m_fontimp->textWidth(text, size); |
190 | } | 279 | } |
191 | 280 | ||
@@ -200,21 +289,35 @@ int Font::ascent() const { | |||
200 | int Font::descent() const { | 289 | int Font::descent() const { |
201 | return m_fontimp->descent(); | 290 | return m_fontimp->descent(); |
202 | } | 291 | } |
292 | |||
203 | void Font::drawText(Drawable w, int screen, GC gc, | 293 | void Font::drawText(Drawable w, int screen, GC gc, |
204 | const char *text, size_t len, int x, int y, | 294 | const char *text, size_t len, int x, int y, |
205 | bool rotate) const { | 295 | bool rotate) const { |
206 | if (text == 0 || len == 0) | 296 | if (text == 0 || len == 0) |
207 | return; | 297 | return; |
208 | 298 | ||
299 | char* rtext = 0; | ||
300 | |||
209 | // so we don't end up in a loop with m_shadow | 301 | // so we don't end up in a loop with m_shadow |
210 | static bool first_run = true; | 302 | static bool first_run = true; |
211 | 303 | ||
304 | if (isAntialias() && m_iconv != (iconv_t)(-1) && first_run) { | ||
305 | rtext = recode(m_iconv, text, len); | ||
306 | if (rtext != 0) { | ||
307 | len = strlen(rtext); | ||
308 | // ok, we can't use utf8 mode since the string is invalid | ||
309 | } | ||
310 | } | ||
311 | |||
312 | |||
313 | const char *real_text = rtext ? rtext : text; | ||
314 | |||
212 | // draw shadow first | 315 | // draw shadow first |
213 | if (first_run && m_shadow) { | 316 | if (first_run && m_shadow) { |
214 | FbTk::GContext shadow_gc(w); | 317 | FbTk::GContext shadow_gc(w); |
215 | shadow_gc.setForeground(FbTk::Color("black", screen)); | 318 | shadow_gc.setForeground(FbTk::Color("black", screen)); |
216 | first_run = false; // so we don't end up in a loop | 319 | first_run = false; // so we don't end up in a loop |
217 | drawText(w, screen, shadow_gc.gc(), text, len, x + 1, y + 1); | 320 | drawText(w, screen, shadow_gc.gc(), real_text, len, x + 1, y + 1); |
218 | first_run = true; | 321 | first_run = true; |
219 | } | 322 | } |
220 | 323 | ||
@@ -228,16 +331,18 @@ void Font::drawText(Drawable w, int screen, GC gc, | |||
228 | XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp.get()); | 331 | XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp.get()); |
229 | font->setRotate(false); // disable rotation temporarly | 332 | font->setRotate(false); // disable rotation temporarly |
230 | 333 | ||
231 | font->drawText(w, screen, gc, text, len, x, y); | 334 | font->drawText(w, screen, gc, real_text, len, x, y); |
232 | font->setRotate(true); // enable rotation | 335 | font->setRotate(true); // enable rotation |
233 | } catch (std::bad_cast &bc) { | 336 | } catch (std::bad_cast &bc) { |
234 | // draw normal... | 337 | // draw normal... |
235 | m_fontimp->drawText(w, screen, gc, text, len, x, y); | 338 | m_fontimp->drawText(w, screen, gc, real_text, len, x, y); |
236 | } | 339 | } |
237 | 340 | ||
238 | } else | 341 | } else |
239 | m_fontimp->drawText(w, screen, gc, text, len, x, y); | 342 | m_fontimp->drawText(w, screen, gc, real_text, len, x, y); |
240 | 343 | ||
344 | if (rtext != 0) | ||
345 | delete rtext; | ||
241 | 346 | ||
242 | } | 347 | } |
243 | 348 | ||
@@ -263,4 +368,6 @@ void Font::rotate(float angle) { | |||
263 | m_angle = angle; | 368 | m_angle = angle; |
264 | } | 369 | } |
265 | 370 | ||
371 | |||
266 | }; | 372 | }; |
373 | |||