6 #include <X11/Xft/Xft.h>
7 #include <fontconfig/fontconfig.h>
9 #if defined(HAVE_MBSNRTOWCS)
23 #include <X11/Xlocale.h>
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)
30 static size_t wmbsnrtowcs(wchar_t * dest
, const char **src
, size_t nbytes
, size_t len
)
35 memset(&ps
, 0, sizeof(mbstate_t));
36 n
= mbsnrtowcs(dest
, src
, nbytes
, len
, &ps
);
37 if (n
!= (size_t) - 1 && *src
) {
44 #elif defined(HAVE_MBRTOWC)
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
)
57 memset(&ps
, 0, sizeof(mbstate_t));
60 for (ptr
= *src
, n
= 0; nbytes
> 0; n
++) {
61 nb
= mbrtowc(NULL
, ptr
, nbytes
, &ps
);
63 return ((size_t) - 1);
64 } else if (nb
== 0 || nb
== -2) {
72 for (ptr
= *src
, n
= 0; n
< len
&& nbytes
> 0; n
++, dest
++) {
73 nb
= mbrtowc(dest
, ptr
, nbytes
, &ps
);
77 } else if (nb
== -1) {
79 return ((size_t) - 1);
94 // Not only 8 times slower than the version based on mbsnrtowcs
95 // but also this version is not thread safe nor reentrant
97 static size_t wmbsnrtowcs(wchar_t * dest
, const char **src
, size_t nbytes
, size_t len
)
106 mbtowc(NULL
, NULL
, 0); /* reset shift state */
109 for (ptr
= *src
, n
= 0; nbytes
> 0; n
++) {
110 nb
= mbtowc(NULL
, ptr
, nbytes
);
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) {
123 for (ptr
= *src
, n
= 0; n
< len
&& nbytes
> 0; n
++, dest
++) {
124 nb
= mbtowc(dest
, ptr
, nbytes
);
126 mbtowc(NULL
, NULL
, 0);
127 nb
= mbtowc(NULL
, ptr
, strlen(ptr
));
129 return (nb
== -1 ? (size_t) - 1 : n
);
130 } else if (nb
== 0) {
144 #define DEFAULT_SIZE 12
146 static char *fixXLFD(char *xlfd
, int size
)
150 fname
= wmalloc(strlen(xlfd
) + 20);
151 if (strstr(xlfd
, "%d") != NULL
)
152 sprintf(fname
, xlfd
, size
? size
: DEFAULT_SIZE
);
156 if ((ptr
= strchr(fname
, ','))) {
163 static Bool
hasProperty(FcPattern
* pattern
, const char *property
)
167 if (FcPatternGet(pattern
, property
, 0, &val
) == FcResultMatch
) {
174 static Bool
hasPropertyWithStringValue(FcPattern
* pattern
, const char *object
, char *value
)
179 if (!value
|| value
[0] == 0)
183 while (FcPatternGetString(pattern
, object
, id
, &str
) == FcResultMatch
) {
184 if (strcasecmp(value
, (char *)str
) == 0) {
193 // also handle an xlfd with %d for size?
194 static char *makeFontOfSize(char *font
, int size
, char *fallback
)
199 if (font
[0] == '-') {
202 fname
= fixXLFD(font
, size
);
203 pattern
= XftXlfdParse(fname
, False
, False
);
206 pattern
= FcNameParse(font
);
209 //FcPatternPrint(pattern);
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
);
217 if (fallback
&& !hasPropertyWithStringValue(pattern
, "family", fallback
)) {
218 FcPatternAddString(pattern
, "family", fallback
);
221 result
= FcNameUnparse(pattern
);
222 FcPatternDestroy(pattern
);
227 WMFont
*WMCreateFont(WMScreen
* scrPtr
, char *fontName
)
230 Display
*display
= scrPtr
->display
;
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;
240 fname
= wstrdup(fontName
);
243 font
= WMHashGet(scrPtr
->fontCache
, fname
);
250 font
= wmalloc(sizeof(WMFont
));
251 memset(font
, 0, sizeof(WMFont
));
253 font
->screen
= scrPtr
;
256 printf("WMCreateFont: %s\n", fname
);
258 if (fname
[0] == '-') {
259 // Backward compat thing. Remove in a later version
260 font
->font
= XftFontOpenXlfd(display
, scrPtr
->screen
, fname
);
262 font
->font
= XftFontOpenName(display
, scrPtr
->screen
, fname
);
269 font
->height
= font
->font
->ascent
+ font
->font
->descent
;
270 font
->y
= font
->font
->ascent
;
276 assert(WMHashInsert(scrPtr
->fontCache
, font
->name
, font
) == NULL
);
281 WMFont
*WMRetainFont(WMFont
* font
)
283 wassertrv(font
!= NULL
, NULL
);
290 void WMReleaseFont(WMFont
* font
)
292 wassertr(font
!= NULL
);
295 if (font
->refCount
< 1) {
296 XftFontClose(font
->screen
->display
, font
->font
);
298 WMHashRemove(font
->screen
->fontCache
, font
->name
);
305 Bool
WMIsAntialiasingEnabled(WMScreen
* scrPtr
)
307 return scrPtr
->antialiasedText
;
310 unsigned int WMFontHeight(WMFont
* font
)
312 wassertrv(font
!= NULL
, 0);
317 char *WMGetFontName(WMFont
* font
)
319 wassertrv(font
!= NULL
, NULL
);
324 WMFont
*WMDefaultSystemFont(WMScreen
* scrPtr
)
326 return WMRetainFont(scrPtr
->normalFont
);
329 WMFont
*WMDefaultBoldSystemFont(WMScreen
* scrPtr
)
331 return WMRetainFont(scrPtr
->boldFont
);
334 WMFont
*WMSystemFontOfSize(WMScreen
* scrPtr
, int size
)
339 fontSpec
= makeFontOfSize(WINGsConfiguration
.systemFont
, size
, "sans");
341 font
= WMCreateFont(scrPtr
, fontSpec
);
344 wwarning(_("could not load font %s."), fontSpec
);
352 WMFont
*WMBoldSystemFontOfSize(WMScreen
* scrPtr
, int size
)
357 fontSpec
= makeFontOfSize(WINGsConfiguration
.boldSystemFont
, size
, "sans");
359 font
= WMCreateFont(scrPtr
, fontSpec
);
362 wwarning(_("could not load font %s."), fontSpec
);
370 int WMWidthOfString(WMFont
* font
, char *text
, int length
)
374 wassertrv(font
!= NULL
, 0);
375 wassertrv(text
!= NULL
, 0);
377 if (font
->screen
->useWideChar
) {
382 wtext
= (wchar_t *) wmalloc(sizeof(wchar_t) * (length
+ 1));
384 len
= wmbsnrtowcs(wtext
, &mtext
, length
, length
);
386 wtext
[len
] = L
'\0'; /* not really necessary here */
387 XftTextExtents32(font
->screen
->display
, font
->font
, (XftChar32
*) wtext
, len
, &extents
);
390 wwarning(_("Conversion to widechar failed (possible "
391 "invalid multibyte sequence): '%s':(pos %d)\n"),
392 text
, mtext
- text
+ 1);
397 } else if (font
->screen
->useMultiByte
) {
398 XftTextExtentsUtf8(font
->screen
->display
, font
->font
, (XftChar8
*) text
, length
, &extents
);
400 XftTextExtents8(font
->screen
->display
, font
->font
, (XftChar8
*) text
, length
, &extents
);
403 return extents
.xOff
; /* don't ask :P */
406 void WMDrawString(WMScreen
* scr
, Drawable d
, WMColor
* color
, WMFont
* font
, int x
, int y
, char *text
, int length
)
410 wassertr(font
!= NULL
);
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
);
418 XftDrawChange(scr
->xftdraw
, d
);
420 if (font
->screen
->useWideChar
) {
425 wtext
= (wchar_t *) wmalloc(sizeof(wchar_t) * (length
+ 1));
427 len
= wmbsnrtowcs(wtext
, &mtext
, length
, length
);
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); */
440 } else if (font
->screen
->useMultiByte
) {
441 XftDrawStringUtf8(scr
->xftdraw
, &xftcolor
, font
->font
, x
, y
+ font
->y
, (XftChar8
*) text
, length
);
443 XftDrawString8(scr
->xftdraw
, &xftcolor
, font
->font
, x
, y
+ font
->y
, (XftChar8
*) text
, length
);
448 WMDrawImageString(WMScreen
* scr
, Drawable d
, WMColor
* color
, WMColor
* background
,
449 WMFont
* font
, int x
, int y
, char *text
, int length
)
454 wassertr(font
!= NULL
);
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
);
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
);
468 XftDrawChange(scr
->xftdraw
, d
);
470 XftDrawRect(scr
->xftdraw
, &bgColor
, x
, y
, WMWidthOfString(font
, text
, length
), font
->height
);
472 if (font
->screen
->useWideChar
) {
478 wtext
= (wchar_t *) wmalloc(sizeof(wchar_t) * (length
+ 1));
479 len
= wmbsnrtowcs(wtext
, &mtext
, length
, length
);
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); */
492 } else if (font
->screen
->useMultiByte
) {
493 XftDrawStringUtf8(scr
->xftdraw
, &textColor
, font
->font
, x
, y
+ font
->y
, (XftChar8
*) text
, length
);
495 XftDrawString8(scr
->xftdraw
, &textColor
, font
->font
, x
, y
+ font
->y
, (XftChar8
*) text
, length
);
499 WMFont
*WMCopyFontWithStyle(WMScreen
* scrPtr
, WMFont
* font
, WMFontStyle style
)
508 pattern
= FcNameParse(WMGetFontName(font
));
511 FcPatternDel(pattern
, "weight");
512 FcPatternDel(pattern
, "slant");
513 FcPatternAddString(pattern
, "weight", "regular");
514 FcPatternAddString(pattern
, "weight", "medium");
515 FcPatternAddString(pattern
, "slant", "roman");
518 FcPatternDel(pattern
, "weight");
519 FcPatternAddString(pattern
, "weight", "bold");
522 FcPatternDel(pattern
, "slant");
523 FcPatternAddString(pattern
, "slant", "italic");
524 FcPatternAddString(pattern
, "slant", "oblique");
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");
535 name
= FcNameUnparse(pattern
);
536 copy
= WMCreateFont(scrPtr
, name
);
537 FcPatternDestroy(pattern
);