Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wfont_wchar.c
1
2 #include "wconfig.h"
3
4 #ifdef XFT
5
6 #include <X11/Xft/Xft.h>
7 #include <fontconfig/fontconfig.h>
8
9 #if defined(HAVE_MBSNRTOWCS)
10 # define __USE_GNU
11 #endif
12
13 #ifdef HAVE_WCHAR_H
14 # include <wchar.h>
15 #endif
16
17 #include <stdlib.h>
18
19 #include "WINGsP.h"
20
21 #include <wraster.h>
22 #include <assert.h>
23 #include <X11/Xlocale.h>
24
25 // && defined(HAVE_MBSTATE_T___COUNT)
26 // in configure.ac use AC_CHECK_MEMBER(struct mbstate_t.__count,
27 // have=1, have=0, [#include <wchar.h>])
28 #if defined(HAVE_MBSNRTOWCS)
29
30 static size_t wmbsnrtowcs(wchar_t * dest, const char **src, size_t nbytes, size_t len)
31 {
32 mbstate_t ps;
33 size_t n;
34
35 memset(&ps, 0, sizeof(mbstate_t));
36 n = mbsnrtowcs(dest, src, nbytes, len, &ps);
37 if (n != (size_t) - 1 && *src) {
38 *src -= ps.__count;
39 }
40
41 return n;
42 }
43
44 #elif defined(HAVE_MBRTOWC)
45
46 // This is 8 times slower than the version above.
47 static size_t wmbsnrtowcs(wchar_t * dest, const char **src, size_t nbytes, size_t len)
48 {
49 mbstate_t ps;
50 const char *ptr;
51 size_t n;
52 int nb;
53
54 if (nbytes == 0)
55 return 0;
56
57 memset(&ps, 0, sizeof(mbstate_t));
58
59 if (dest == NULL) {
60 for (ptr = *src, n = 0; nbytes > 0; n++) {
61 nb = mbrtowc(NULL, ptr, nbytes, &ps);
62 if (nb == -1) {
63 return ((size_t) - 1);
64 } else if (nb == 0 || nb == -2) {
65 return n;
66 }
67 ptr += nb;
68 nbytes -= nb;
69 }
70 }
71
72 for (ptr = *src, n = 0; n < len && nbytes > 0; n++, dest++) {
73 nb = mbrtowc(dest, ptr, nbytes, &ps);
74 if (nb == -2) {
75 *src = ptr;
76 return n;
77 } else if (nb == -1) {
78 *src = ptr;
79 return ((size_t) - 1);
80 } else if (nb == 0) {
81 *src = NULL;
82 return n;
83 }
84 ptr += nb;
85 nbytes -= nb;
86 }
87
88 *src = ptr;
89 return n;
90 }
91
92 #else
93
94 // Not only 8 times slower than the version based on mbsnrtowcs
95 // but also this version is not thread safe nor reentrant
96
97 static size_t wmbsnrtowcs(wchar_t * dest, const char **src, size_t nbytes, size_t len)
98 {
99 const char *ptr;
100 size_t n;
101 int nb;
102
103 if (nbytes == 0)
104 return 0;
105
106 mbtowc(NULL, NULL, 0); /* reset shift state */
107
108 if (dest == NULL) {
109 for (ptr = *src, n = 0; nbytes > 0; n++) {
110 nb = mbtowc(NULL, ptr, nbytes);
111 if (nb == -1) {
112 mbtowc(NULL, NULL, 0);
113 nb = mbtowc(NULL, ptr, strlen(ptr));
114 return (nb == -1 ? (size_t) - 1 : n);
115 } else if (nb == 0) {
116 return n;
117 }
118 ptr += nb;
119 nbytes -= nb;
120 }
121 }
122
123 for (ptr = *src, n = 0; n < len && nbytes > 0; n++, dest++) {
124 nb = mbtowc(dest, ptr, nbytes);
125 if (nb == -1) {
126 mbtowc(NULL, NULL, 0);
127 nb = mbtowc(NULL, ptr, strlen(ptr));
128 *src = ptr;
129 return (nb == -1 ? (size_t) - 1 : n);
130 } else if (nb == 0) {
131 *src = NULL;
132 return n;
133 }
134 ptr += nb;
135 nbytes -= nb;
136 }
137
138 *src = ptr;
139 return n;
140 }
141
142 #endif
143
144 #define DEFAULT_SIZE 12
145
146 static char *fixXLFD(char *xlfd, int size)
147 {
148 char *fname, *ptr;
149
150 fname = wmalloc(strlen(xlfd) + 20);
151 if (strstr(xlfd, "%d") != NULL)
152 sprintf(fname, xlfd, size ? size : DEFAULT_SIZE);
153 else
154 strcpy(fname, xlfd);
155
156 if ((ptr = strchr(fname, ','))) {
157 *ptr = 0;
158 }
159
160 return fname;
161 }
162
163 static Bool hasProperty(FcPattern * pattern, const char *property)
164 {
165 FcValue val;
166
167 if (FcPatternGet(pattern, property, 0, &val) == FcResultMatch) {
168 return True;
169 }
170
171 return False;
172 }
173
174 static Bool hasPropertyWithStringValue(FcPattern * pattern, const char *object, char *value)
175 {
176 FcChar8 *str;
177 int id;
178
179 if (!value || value[0] == 0)
180 return True;
181
182 id = 0;
183 while (FcPatternGetString(pattern, object, id, &str) == FcResultMatch) {
184 if (strcasecmp(value, (char *)str) == 0) {
185 return True;
186 }
187 id++;
188 }
189
190 return False;
191 }
192
193 // also handle an xlfd with %d for size?
194 static char *makeFontOfSize(char *font, int size, char *fallback)
195 {
196 FcPattern *pattern;
197 char *result;
198
199 if (font[0] == '-') {
200 char *fname;
201
202 fname = fixXLFD(font, size);
203 pattern = XftXlfdParse(fname, False, False);
204 wfree(fname);
205 } else {
206 pattern = FcNameParse(font);
207 }
208
209 //FcPatternPrint(pattern);
210 if (size > 0) {
211 FcPatternDel(pattern, "pixelsize");
212 FcPatternAddDouble(pattern, "pixelsize", (double)size);
213 } else if (size == 0 && !hasProperty(pattern, "size") && !hasProperty(pattern, "pixelsize")) {
214 FcPatternAddDouble(pattern, "pixelsize", (double)DEFAULT_SIZE);
215 }
216
217 if (fallback && !hasPropertyWithStringValue(pattern, "family", fallback)) {
218 FcPatternAddString(pattern, "family", fallback);
219 }
220
221 result = FcNameUnparse(pattern);
222 FcPatternDestroy(pattern);
223
224 return result;
225 }
226
227 WMFont *WMCreateFont(WMScreen * scrPtr, char *fontName)
228 {
229 WMFont *font;
230 Display *display = scrPtr->display;
231 char *fname, *ptr;
232
233 /* This is for back-compat (to allow reading of old xlfd descriptions) */
234 if (fontName[0] == '-' && (ptr = strchr(fontName, ','))) {
235 // warn for deprecation
236 fname = wmalloc(ptr - fontName + 1);
237 strncpy(fname, fontName, ptr - fontName);
238 fname[ptr - fontName] = 0;
239 } else {
240 fname = wstrdup(fontName);
241 }
242
243 font = WMHashGet(scrPtr->fontCache, fname);
244 if (font) {
245 WMRetainFont(font);
246 wfree(fname);
247 return font;
248 }
249
250 font = wmalloc(sizeof(WMFont));
251 memset(font, 0, sizeof(WMFont));
252
253 font->screen = scrPtr;
254
255 // remove
256 printf("WMCreateFont: %s\n", fname);
257
258 if (fname[0] == '-') {
259 // Backward compat thing. Remove in a later version
260 font->font = XftFontOpenXlfd(display, scrPtr->screen, fname);
261 } else {
262 font->font = XftFontOpenName(display, scrPtr->screen, fname);
263 }
264 if (!font->font) {
265 wfree(font);
266 wfree(fname);
267 return NULL;
268 }
269 font->height = font->font->ascent + font->font->descent;
270 font->y = font->font->ascent;
271
272 font->refCount = 1;
273
274 font->name = fname;
275
276 assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL);
277
278 return font;
279 }
280
281 WMFont *WMRetainFont(WMFont * font)
282 {
283 wassertrv(font != NULL, NULL);
284
285 font->refCount++;
286
287 return font;
288 }
289
290 void WMReleaseFont(WMFont * font)
291 {
292 wassertr(font != NULL);
293
294 font->refCount--;
295 if (font->refCount < 1) {
296 XftFontClose(font->screen->display, font->font);
297 if (font->name) {
298 WMHashRemove(font->screen->fontCache, font->name);
299 wfree(font->name);
300 }
301 wfree(font);
302 }
303 }
304
305 Bool WMIsAntialiasingEnabled(WMScreen * scrPtr)
306 {
307 return scrPtr->antialiasedText;
308 }
309
310 unsigned int WMFontHeight(WMFont * font)
311 {
312 wassertrv(font != NULL, 0);
313
314 return font->height;
315 }
316
317 char *WMGetFontName(WMFont * font)
318 {
319 wassertrv(font != NULL, NULL);
320
321 return font->name;
322 }
323
324 WMFont *WMDefaultSystemFont(WMScreen * scrPtr)
325 {
326 return WMRetainFont(scrPtr->normalFont);
327 }
328
329 WMFont *WMDefaultBoldSystemFont(WMScreen * scrPtr)
330 {
331 return WMRetainFont(scrPtr->boldFont);
332 }
333
334 WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size)
335 {
336 WMFont *font;
337 char *fontSpec;
338
339 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans");
340
341 font = WMCreateFont(scrPtr, fontSpec);
342
343 if (!font) {
344 wwarning(_("could not load font %s."), fontSpec);
345 }
346
347 wfree(fontSpec);
348
349 return font;
350 }
351
352 WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
353 {
354 WMFont *font;
355 char *fontSpec;
356
357 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans");
358
359 font = WMCreateFont(scrPtr, fontSpec);
360
361 if (!font) {
362 wwarning(_("could not load font %s."), fontSpec);
363 }
364
365 wfree(fontSpec);
366
367 return font;
368 }
369
370 int WMWidthOfString(WMFont * font, char *text, int length)
371 {
372 XGlyphInfo extents;
373
374 wassertrv(font != NULL, 0);
375 wassertrv(text != NULL, 0);
376
377 if (font->screen->useWideChar) {
378 wchar_t *wtext;
379 const char *mtext;
380 int len;
381
382 wtext = (wchar_t *) wmalloc(sizeof(wchar_t) * (length + 1));
383 mtext = text;
384 len = wmbsnrtowcs(wtext, &mtext, length, length);
385 if (len > 0) {
386 wtext[len] = L'\0'; /* not really necessary here */
387 XftTextExtents32(font->screen->display, font->font, (XftChar32 *) wtext, len, &extents);
388 } else {
389 if (len == -1) {
390 wwarning(_("Conversion to widechar failed (possible "
391 "invalid multibyte sequence): '%s':(pos %d)\n"),
392 text, mtext - text + 1);
393 }
394 extents.xOff = 0;
395 }
396 wfree(wtext);
397 } else if (font->screen->useMultiByte) {
398 XftTextExtentsUtf8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
399 } else {
400 XftTextExtents8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
401 }
402
403 return extents.xOff; /* don't ask :P */
404 }
405
406 void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, int x, int y, char *text, int length)
407 {
408 XftColor xftcolor;
409
410 wassertr(font != NULL);
411
412 xftcolor.color.red = color->color.red;
413 xftcolor.color.green = color->color.green;
414 xftcolor.color.blue = color->color.blue;
415 xftcolor.color.alpha = color->alpha;;
416 xftcolor.pixel = W_PIXEL(color);
417
418 XftDrawChange(scr->xftdraw, d);
419
420 if (font->screen->useWideChar) {
421 wchar_t *wtext;
422 const char *mtext;
423 int len;
424
425 wtext = (wchar_t *) wmalloc(sizeof(wchar_t) * (length + 1));
426 mtext = text;
427 len = wmbsnrtowcs(wtext, &mtext, length, length);
428 if (len > 0) {
429 XftDrawString32(scr->xftdraw, &xftcolor, font->font,
430 x, y + font->y, (XftChar32 *) wtext, len);
431 } else if (len == -1) {
432 wwarning(_("Conversion to widechar failed (possible invalid "
433 "multibyte sequence): '%s':(pos %d)\n"), text, mtext - text + 1);
434 /* we can draw normal text, or we can draw as much widechar
435 * text as was already converted until the error. go figure */
436 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font,
437 x, y + font->y, (XftChar8*)text, length); */
438 }
439 wfree(wtext);
440 } else if (font->screen->useMultiByte) {
441 XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
442 } else {
443 XftDrawString8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
444 }
445 }
446
447 void
448 WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * background,
449 WMFont * font, int x, int y, char *text, int length)
450 {
451 XftColor textColor;
452 XftColor bgColor;
453
454 wassertr(font != NULL);
455
456 textColor.color.red = color->color.red;
457 textColor.color.green = color->color.green;
458 textColor.color.blue = color->color.blue;
459 textColor.color.alpha = color->alpha;;
460 textColor.pixel = W_PIXEL(color);
461
462 bgColor.color.red = background->color.red;
463 bgColor.color.green = background->color.green;
464 bgColor.color.blue = background->color.blue;
465 bgColor.color.alpha = background->alpha;;
466 bgColor.pixel = W_PIXEL(background);
467
468 XftDrawChange(scr->xftdraw, d);
469
470 XftDrawRect(scr->xftdraw, &bgColor, x, y, WMWidthOfString(font, text, length), font->height);
471
472 if (font->screen->useWideChar) {
473 wchar_t *wtext;
474 const char *mtext;
475 int len;
476
477 mtext = text;
478 wtext = (wchar_t *) wmalloc(sizeof(wchar_t) * (length + 1));
479 len = wmbsnrtowcs(wtext, &mtext, length, length);
480 if (len > 0) {
481 XftDrawString32(scr->xftdraw, &textColor, font->font,
482 x, y + font->y, (XftChar32 *) wtext, len);
483 } else if (len == -1) {
484 wwarning(_("Conversion to widechar failed (possible invalid "
485 "multibyte sequence): '%s':(pos %d)\n"), text, mtext - text + 1);
486 /* we can draw normal text, or we can draw as much widechar
487 * text as was already converted until the error. go figure */
488 /*XftDrawString8(scr->xftdraw, &textColor, font->font,
489 x, y + font->y, (XftChar8*)text, length); */
490 }
491 wfree(wtext);
492 } else if (font->screen->useMultiByte) {
493 XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
494 } else {
495 XftDrawString8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
496 }
497 }
498
499 WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style)
500 {
501 FcPattern *pattern;
502 WMFont *copy;
503 char *name;
504
505 if (!font)
506 return NULL;
507
508 pattern = FcNameParse(WMGetFontName(font));
509 switch (style) {
510 case WFSNormal:
511 FcPatternDel(pattern, "weight");
512 FcPatternDel(pattern, "slant");
513 FcPatternAddString(pattern, "weight", "regular");
514 FcPatternAddString(pattern, "weight", "medium");
515 FcPatternAddString(pattern, "slant", "roman");
516 break;
517 case WFSBold:
518 FcPatternDel(pattern, "weight");
519 FcPatternAddString(pattern, "weight", "bold");
520 break;
521 case WFSEmphasized:
522 FcPatternDel(pattern, "slant");
523 FcPatternAddString(pattern, "slant", "italic");
524 FcPatternAddString(pattern, "slant", "oblique");
525 break;
526 case WFSBoldEmphasized:
527 FcPatternDel(pattern, "weight");
528 FcPatternDel(pattern, "slant");
529 FcPatternAddString(pattern, "weight", "bold");
530 FcPatternAddString(pattern, "slant", "italic");
531 FcPatternAddString(pattern, "slant", "oblique");
532 break;
533 }
534
535 name = FcNameUnparse(pattern);
536 copy = WMCreateFont(scrPtr, name);
537 FcPatternDestroy(pattern);
538 wfree(name);
539
540 return copy;
541 }
542
543 #endif /* XFT */