another test for cvs notifications
[wmaker-crm.git] / WINGs / wfont.c
blob3e866901eb36634efc042dab16c230e75e02c0b7
2 #include "wconfig.h"
4 #ifdef XFT
6 #include <X11/Xft/Xft.h>
7 #include <fontconfig/fontconfig.h>
9 #if defined(HAVE_MBSNRTOWCS)
10 # define __USE_GNU
11 #endif
13 #ifdef HAVE_WCHAR_H
14 # include <wchar.h>
15 #endif
17 #include <stdlib.h>
19 #include "WINGsP.h"
21 #include <wraster.h>
22 #include <assert.h>
23 #include <X11/Xlocale.h>
27 #if defined(HAVE_MBSNRTOWCS)
29 static size_t
30 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
32 mbstate_t ps;
33 size_t n;
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;
41 return n;
44 #elif defined(HAVE_MBRTOWC)
46 // This is 8 times slower than the version above.
47 static size_t
48 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
50 mbstate_t ps;
51 const char *ptr;
52 size_t n;
53 int nb;
55 if (nbytes==0)
56 return 0;
58 memset(&ps, 0, sizeof(mbstate_t));
60 if (dest == NULL) {
61 for (ptr=*src, n=0; nbytes>0; n++) {
62 nb = mbrtowc(NULL, ptr, nbytes, &ps);
63 if (nb == -1) {
64 return ((size_t)-1);
65 } else if (nb==0 || nb==-2) {
66 return n;
68 ptr += nb;
69 nbytes -= nb;
73 for (ptr=*src, n=0; n<len && nbytes>0; n++, dest++) {
74 nb = mbrtowc(dest, ptr, nbytes, &ps);
75 if (nb == -2) {
76 *src = ptr;
77 return n;
78 } else if (nb == -1) {
79 *src = ptr;
80 return ((size_t)-1);
81 } else if (nb == 0) {
82 *src = NULL;
83 return n;
85 ptr += nb;
86 nbytes -= nb;
89 *src = ptr;
90 return n;
93 #else
95 // Not only 8 times slower than the version based on mbsnrtowcs
96 // but also this version is not thread safe nor reentrant
98 static size_t
99 wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len)
101 const char *ptr;
102 size_t n;
103 int nb;
105 if (nbytes==0)
106 return 0;
108 mbtowc(NULL, NULL, 0); /* reset shift state */
110 if (dest == NULL) {
111 for (ptr=*src, n=0; nbytes>0; n++) {
112 nb = mbtowc(NULL, ptr, nbytes);
113 if (nb == -1) {
114 mbtowc(NULL, NULL, 0);
115 nb = mbtowc(NULL, ptr, strlen(ptr));
116 return (nb == -1 ? (size_t)-1 : n);
117 } else if (nb==0) {
118 return n;
120 ptr += nb;
121 nbytes -= nb;
125 for (ptr=*src, n=0; n<len && nbytes>0; n++, dest++) {
126 nb = mbtowc(dest, ptr, nbytes);
127 if (nb == -1) {
128 mbtowc(NULL, NULL, 0);
129 nb = mbtowc(NULL, ptr, strlen(ptr));
130 *src = ptr;
131 return (nb == -1 ? (size_t)-1 : n);
132 } else if (nb == 0) {
133 *src = NULL;
134 return n;
136 ptr += nb;
137 nbytes -= nb;
140 *src = ptr;
141 return n;
144 #endif
147 #define DEFAULT_SIZE 12
149 static char*
150 fixXLFD(char *xlfd, int size)
152 char *fname, *ptr;
154 fname = wmalloc(strlen(xlfd) + 20);
155 if (strstr(xlfd, "%d")!=NULL)
156 sprintf(fname, xlfd, size ? size : DEFAULT_SIZE);
157 else
158 strcpy(fname, xlfd);
160 if ((ptr = strchr(fname, ','))) {
161 *ptr = 0;
164 return fname;
168 static Bool
169 hasProperty(FcPattern *pattern, const char *property)
171 FcValue val;
173 if (FcPatternGet(pattern, property, 0, &val)==FcResultMatch) {
174 return True;
177 return False;
181 static Bool
182 hasPropertyWithStringValue(FcPattern *pattern, const char *object, char *value)
184 FcChar8 *str;
185 int id;
187 if (!value || value[0]==0)
188 return True;
190 id = 0;
191 while (FcPatternGetString(pattern, object, id, &str)==FcResultMatch) {
192 if (strcasecmp(value, (char*)str) == 0) {
193 return True;
195 id++;
198 return False;
202 // also handle an xlfd with %d for size?
203 static char*
204 makeFontOfSize(char *font, int size, char *fallback)
206 FcPattern *pattern;
207 char *result;
209 if (font[0]=='-') {
210 char *fname;
212 fname = fixXLFD(font, size);
213 pattern = XftXlfdParse(fname, False, False);
214 wfree(fname);
215 } else {
216 pattern = FcNameParse(font);
219 //FcPatternPrint(pattern);
220 if (size > 0) {
221 FcPatternDel(pattern, "pixelsize");
222 FcPatternAddDouble(pattern, "pixelsize", (double)size);
223 } else if (size==0 && !hasProperty(pattern, "size") &&
224 !hasProperty(pattern, "pixelsize")) {
225 FcPatternAddDouble(pattern, "pixelsize", (double)DEFAULT_SIZE);
228 if (fallback && !hasPropertyWithStringValue(pattern, "family", fallback)) {
229 FcPatternAddString(pattern, "family", fallback);
232 result = FcNameUnparse(pattern);
233 FcPatternDestroy(pattern);
235 return result;
239 WMFont*
240 WMCreateFont(WMScreen *scrPtr, char *fontName)
242 WMFont *font;
243 Display *display = scrPtr->display;
244 char *fname, *ptr;
246 /* This is for back-compat (to allow reading of old xlfd descriptions) */
247 if (fontName[0]=='-' && (ptr = strchr(fontName, ','))) {
248 // warn for deprecation
249 fname = wmalloc(ptr - fontName + 1);
250 strncpy(fname, fontName, ptr - fontName);
251 fname[ptr - fontName] = 0;
252 } else {
253 fname = wstrdup(fontName);
256 font = WMHashGet(scrPtr->fontCache, fname);
257 if (font) {
258 WMRetainFont(font);
259 wfree(fname);
260 return font;
263 font = wmalloc(sizeof(WMFont));
264 memset(font, 0, sizeof(WMFont));
266 font->screen = scrPtr;
268 // remove
269 printf("WMCreateFont: %s\n", fname);
271 if (fname[0] == '-') {
272 // Backward compat thing. Remove in a later version
273 font->font = XftFontOpenXlfd(display, scrPtr->screen, fname);
274 } else {
275 font->font = XftFontOpenName(display, scrPtr->screen, fname);
277 if (!font->font) {
278 wfree(font);
279 wfree(fname);
280 return NULL;
282 font->height = font->font->ascent+font->font->descent;
283 font->y = font->font->ascent;
285 font->refCount = 1;
287 font->name = fname;
289 assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL);
291 return font;
295 WMFont*
296 WMRetainFont(WMFont *font)
298 wassertrv(font!=NULL, NULL);
300 font->refCount++;
302 return font;
306 void
307 WMReleaseFont(WMFont *font)
309 wassertr(font!=NULL);
311 font->refCount--;
312 if (font->refCount < 1) {
313 XftFontClose(font->screen->display, font->font);
314 if (font->name) {
315 WMHashRemove(font->screen->fontCache, font->name);
316 wfree(font->name);
318 wfree(font);
323 Bool
324 WMIsAntialiasingEnabled(WMScreen *scrPtr)
326 return scrPtr->antialiasedText;
330 unsigned int
331 WMFontHeight(WMFont *font)
333 wassertrv(font!=NULL, 0);
335 return font->height;
339 char*
340 WMGetFontName(WMFont *font)
342 wassertrv(font!=NULL, NULL);
344 return font->name;
348 WMFont*
349 WMDefaultSystemFont(WMScreen *scrPtr)
351 return WMRetainFont(scrPtr->normalFont);
355 WMFont*
356 WMDefaultBoldSystemFont(WMScreen *scrPtr)
358 return WMRetainFont(scrPtr->boldFont);
362 WMFont*
363 WMSystemFontOfSize(WMScreen *scrPtr, int size)
365 WMFont *font;
366 char *fontSpec;
368 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans");
370 font = WMCreateFont(scrPtr, fontSpec);
372 if (!font) {
373 wwarning(_("could not load font %s."), fontSpec);
376 wfree(fontSpec);
378 return font;
382 WMFont*
383 WMBoldSystemFontOfSize(WMScreen *scrPtr, int size)
385 WMFont *font;
386 char *fontSpec;
388 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans");
390 font = WMCreateFont(scrPtr, fontSpec);
392 if (!font) {
393 wwarning(_("could not load font %s."), fontSpec);
396 wfree(fontSpec);
398 return font;
403 WMWidthOfString(WMFont *font, char *text, int length)
405 XGlyphInfo extents;
407 wassertrv(font!=NULL, 0);
408 wassertrv(text!=NULL, 0);
410 if (font->screen->useWideChar) {
411 wchar_t *wtext;
412 const char *mtext;
413 int len;
415 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
416 mtext = text;
417 len = wmbsnrtowcs(wtext, &mtext, length, length);
418 if (len>0) {
419 wtext[len] = L'\0'; /* not really necessary here */
420 XftTextExtents32(font->screen->display, font->font,
421 (XftChar32 *)wtext, len, &extents);
422 } else {
423 if (len==-1) {
424 wwarning(_("Conversion to widechar failed (possible "
425 "invalid multibyte sequence): '%s':(pos %d)\n"),
426 text, mtext-text+1);
428 extents.xOff = 0;
430 wfree(wtext);
431 } else if (font->screen->useMultiByte) {
432 XftTextExtentsUtf8(font->screen->display, font->font,
433 (XftChar8 *)text, length, &extents);
434 } else {
435 XftTextExtents8(font->screen->display, font->font,
436 (XftChar8 *)text, length, &extents);
439 return extents.xOff; /* don't ask :P */
444 void
445 WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font,
446 int x, int y, char *text, int length)
448 XftColor xftcolor;
450 wassertr(font!=NULL);
452 xftcolor.color.red = color->color.red;
453 xftcolor.color.green = color->color.green;
454 xftcolor.color.blue = color->color.blue;
455 xftcolor.color.alpha = color->alpha;;
456 xftcolor.pixel = W_PIXEL(color);
458 XftDrawChange(scr->xftdraw, d);
460 if (font->screen->useWideChar) {
461 wchar_t *wtext;
462 const char *mtext;
463 int len;
465 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
466 mtext = text;
467 len = wmbsnrtowcs(wtext, &mtext, length, length);
468 if (len>0) {
469 XftDrawString32(scr->xftdraw, &xftcolor, font->font,
470 x, y + font->y, (XftChar32*)wtext, len);
471 } else if (len==-1) {
472 wwarning(_("Conversion to widechar failed (possible invalid "
473 "multibyte sequence): '%s':(pos %d)\n"),
474 text, mtext-text+1);
475 /* we can draw normal text, or we can draw as much widechar
476 * text as was already converted until the error. go figure */
477 /*XftDrawString8(scr->xftdraw, &xftcolor, font->font,
478 x, y + font->y, (XftChar8*)text, length);*/
480 wfree(wtext);
481 } else if (font->screen->useMultiByte) {
482 XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font,
483 x, y + font->y, (XftChar8*)text, length);
484 } else {
485 XftDrawString8(scr->xftdraw, &xftcolor, font->font,
486 x, y + font->y, (XftChar8*)text, length);
491 void
492 WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background,
493 WMFont *font, int x, int y, char *text, int length)
495 XftColor textColor;
496 XftColor bgColor;
498 wassertr(font!=NULL);
500 textColor.color.red = color->color.red;
501 textColor.color.green = color->color.green;
502 textColor.color.blue = color->color.blue;
503 textColor.color.alpha = color->alpha;;
504 textColor.pixel = W_PIXEL(color);
506 bgColor.color.red = background->color.red;
507 bgColor.color.green = background->color.green;
508 bgColor.color.blue = background->color.blue;
509 bgColor.color.alpha = background->alpha;;
510 bgColor.pixel = W_PIXEL(background);
512 XftDrawChange(scr->xftdraw, d);
514 XftDrawRect(scr->xftdraw, &bgColor, x, y,
515 WMWidthOfString(font, text, length),
516 font->height);
518 if (font->screen->useWideChar) {
519 wchar_t *wtext;
520 const char *mtext;
521 int len;
523 mtext = text;
524 wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1));
525 len = wmbsnrtowcs(wtext, &mtext, length, length);
526 if (len>0) {
527 XftDrawString32(scr->xftdraw, &textColor, font->font,
528 x, y + font->y, (XftChar32*)wtext, len);
529 } else if (len==-1) {
530 wwarning(_("Conversion to widechar failed (possible invalid "
531 "multibyte sequence): '%s':(pos %d)\n"),
532 text, mtext-text+1);
533 /* we can draw normal text, or we can draw as much widechar
534 * text as was already converted until the error. go figure */
535 /*XftDrawString8(scr->xftdraw, &textColor, font->font,
536 x, y + font->y, (XftChar8*)text, length);*/
538 wfree(wtext);
539 } else if (font->screen->useMultiByte) {
540 XftDrawStringUtf8(scr->xftdraw, &textColor, font->font,
541 x, y + font->y, (XftChar8*)text, length);
542 } else {
543 XftDrawString8(scr->xftdraw, &textColor, font->font,
544 x, y + font->y, (XftChar8*)text, length);
549 WMFont*
550 WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style)
552 FcPattern *pattern;
553 WMFont *copy;
554 char *name;
556 if (!font)
557 return NULL;
559 pattern = FcNameParse(WMGetFontName(font));
560 switch (style) {
561 case WFSNormal:
562 FcPatternDel(pattern, "weight");
563 FcPatternDel(pattern, "slant");
564 FcPatternAddString(pattern, "weight", "regular");
565 FcPatternAddString(pattern, "weight", "medium");
566 FcPatternAddString(pattern, "slant", "roman");
567 break;
568 case WFSBold:
569 FcPatternDel(pattern, "weight");
570 FcPatternAddString(pattern, "weight", "bold");
571 break;
572 case WFSEmphasized:
573 FcPatternDel(pattern, "slant");
574 FcPatternAddString(pattern, "slant", "italic");
575 FcPatternAddString(pattern, "slant", "oblique");
576 break;
577 case WFSBoldEmphasized:
578 FcPatternDel(pattern, "weight");
579 FcPatternDel(pattern, "slant");
580 FcPatternAddString(pattern, "weight", "bold");
581 FcPatternAddString(pattern, "slant", "italic");
582 FcPatternAddString(pattern, "slant", "oblique");
583 break;
586 name = FcNameUnparse(pattern);
587 copy = WMCreateFont(scrPtr, name);
588 FcPatternDestroy(pattern);
589 wfree(name);
591 return copy;
595 #endif /* XFT */