10 #include <X11/Xlocale.h>
12 #include <X11/Xft/Xft.h>
13 #include <fontconfig/fontconfig.h>
16 #include <pango/pango.h>
17 #include <pango/pangofc-fontmap.h>
18 #include <pango/pangoxft.h>
21 #define DEFAULT_FONT "sans serif:pixelsize=12"
23 #define DEFAULT_SIZE WINGsConfiguration.defaultFontSize
25 static FcPattern
*xlfdToFcPattern(const char *xlfd
)
30 /* Just skip old font names that contain %d in them.
31 * We don't support that anymore. */
32 if (strchr(xlfd
, '%') != NULL
)
33 return FcNameParse((FcChar8
*) DEFAULT_FONT
);
35 fname
= wstrdup(xlfd
);
36 if ((ptr
= strchr(fname
, ','))) {
39 pattern
= XftXlfdParse(fname
, False
, False
);
43 wwarning(_("invalid font: %s. Trying '%s'"), xlfd
, DEFAULT_FONT
);
44 pattern
= FcNameParse((FcChar8
*) DEFAULT_FONT
);
50 static char *xlfdToFcName(const char *xlfd
)
55 pattern
= xlfdToFcPattern(xlfd
);
56 fname
= (char *)FcNameUnparse(pattern
);
57 FcPatternDestroy(pattern
);
62 static Bool
hasProperty(FcPattern
* pattern
, const char *property
)
66 if (FcPatternGet(pattern
, property
, 0, &val
) == FcResultMatch
) {
73 static Bool
hasPropertyWithStringValue(FcPattern
* pattern
, const char *object
, const char *value
)
78 if (!value
|| value
[0] == 0)
82 while (FcPatternGetString(pattern
, object
, id
, &str
) == FcResultMatch
) {
83 if (strcasecmp(value
, (char *)str
) == 0) {
92 static char *makeFontOfSize(const char *font
, int size
, const char *fallback
)
98 pattern
= xlfdToFcPattern(font
);
100 pattern
= FcNameParse((const FcChar8
*) font
);
103 /*FcPatternPrint(pattern); */
106 FcPatternDel(pattern
, FC_PIXEL_SIZE
);
107 FcPatternAddDouble(pattern
, FC_PIXEL_SIZE
, (double)size
);
108 } else if (size
== 0 && !hasProperty(pattern
, "size") && !hasProperty(pattern
, FC_PIXEL_SIZE
)) {
109 FcPatternAddDouble(pattern
, FC_PIXEL_SIZE
, (double)DEFAULT_SIZE
);
112 if (fallback
&& !hasPropertyWithStringValue(pattern
, FC_FAMILY
, fallback
)) {
113 FcPatternAddString(pattern
, FC_FAMILY
, (const FcChar8
*) fallback
);
116 /*FcPatternPrint(pattern); */
118 result
= (char *)FcNameUnparse(pattern
);
119 FcPatternDestroy(pattern
);
124 WMFont
*WMCreateFont(WMScreen
* scrPtr
, const char *fontName
)
126 Display
*display
= scrPtr
->display
;
130 PangoFontMap
*fontmap
;
131 PangoContext
*context
;
134 PangoFontDescription
*description
;
138 if (fontName
[0] == '-') {
139 fname
= xlfdToFcName(fontName
);
141 fname
= wstrdup(fontName
);
144 if (!WINGsConfiguration
.antialiasedText
&& !strstr(fname
, ":antialias=")) {
145 fname
= wstrappend(fname
, ":antialias=false");
148 font
= WMHashGet(scrPtr
->fontCache
, fname
);
155 font
= wmalloc(sizeof(WMFont
));
157 font
->screen
= scrPtr
;
159 font
->font
= XftFontOpenName(display
, scrPtr
->screen
, fname
);
166 font
->height
= font
->font
->ascent
+ font
->font
->descent
;
167 font
->y
= font
->font
->ascent
;
174 fontmap
= pango_xft_get_font_map(scrPtr
->display
, scrPtr
->screen
);
175 context
= pango_font_map_create_context(fontmap
);
176 layout
= pango_layout_new(context
);
178 pattern
= FcNameParse((FcChar8
*) font
->name
);
179 description
= pango_fc_font_description_from_pattern(pattern
, FALSE
);
181 /* Pango examines FC_SIZE but not FC_PIXEL_SIZE of the patten, but
182 * font-name has only "pixelsize", so set the size manually here.
184 if (FcPatternGetDouble(pattern
, FC_PIXEL_SIZE
, 0, &size
) == FcResultMatch
)
185 pango_font_description_set_absolute_size(description
, size
* PANGO_SCALE
);
187 pango_layout_set_font_description(layout
, description
);
189 font
->layout
= layout
;
192 assert(WMHashInsert(scrPtr
->fontCache
, font
->name
, font
) == NULL
);
197 WMFont
*WMRetainFont(WMFont
* font
)
199 wassertrv(font
!= NULL
, NULL
);
206 void WMReleaseFont(WMFont
* font
)
208 wassertr(font
!= NULL
);
211 if (font
->refCount
< 1) {
212 XftFontClose(font
->screen
->display
, font
->font
);
214 WMHashRemove(font
->screen
->fontCache
, font
->name
);
221 Bool
WMIsAntialiasingEnabled(WMScreen
* scrPtr
)
223 return scrPtr
->antialiasedText
;
226 unsigned int WMFontHeight(WMFont
* font
)
228 wassertrv(font
!= NULL
, 0);
233 char *WMGetFontName(WMFont
* font
)
235 wassertrv(font
!= NULL
, NULL
);
240 void WMGetScaleBaseFromSystemFont(WMScreen
*scrPtr
, int *alphabetWidth
, int *fontHeight
)
244 font
= WMDefaultSystemFont(scrPtr
);
245 *alphabetWidth
= WMWidthOfString(font
, "abcdefghijklmnopqrstuvwxyz", 26);
246 *fontHeight
= WMFontHeight(font
);
250 WMFont
*WMDefaultSystemFont(WMScreen
* scrPtr
)
252 return WMRetainFont(scrPtr
->normalFont
);
255 WMFont
*WMDefaultBoldSystemFont(WMScreen
* scrPtr
)
257 return WMRetainFont(scrPtr
->boldFont
);
260 WMFont
*WMSystemFontOfSize(WMScreen
* scrPtr
, int size
)
265 fontSpec
= makeFontOfSize(WINGsConfiguration
.systemFont
, size
, NULL
);
267 font
= WMCreateFont(scrPtr
, fontSpec
);
270 wwarning(_("could not load font: %s."), fontSpec
);
278 WMFont
*WMBoldSystemFontOfSize(WMScreen
* scrPtr
, int size
)
283 fontSpec
= makeFontOfSize(WINGsConfiguration
.boldSystemFont
, size
, NULL
);
285 font
= WMCreateFont(scrPtr
, fontSpec
);
288 wwarning(_("could not load font: %s."), fontSpec
);
296 int WMWidthOfString(WMFont
* font
, const char *text
, int length
)
299 const char *previous_text
;
305 wassertrv(font
!= NULL
&& text
!= NULL
, 0);
307 previous_text
= pango_layout_get_text(font
->layout
);
308 if ((previous_text
== NULL
) || (strncmp(text
, previous_text
, length
) != 0) || previous_text
[length
] != '\0')
309 pango_layout_set_text(font
->layout
, text
, length
);
310 pango_layout_get_pixel_size(font
->layout
, &width
, NULL
);
314 XftTextExtentsUtf8(font
->screen
->display
, font
->font
, (XftChar8
*) text
, length
, &extents
);
316 return extents
.xOff
; /* don't ask :P */
320 void WMDrawString(WMScreen
* scr
, Drawable d
, WMColor
* color
, WMFont
* font
, int x
, int y
, const char *text
, int length
)
324 const char *previous_text
;
327 wassertr(font
!= NULL
);
329 xftcolor
.color
.red
= color
->color
.red
;
330 xftcolor
.color
.green
= color
->color
.green
;
331 xftcolor
.color
.blue
= color
->color
.blue
;
332 xftcolor
.color
.alpha
= color
->alpha
;;
333 xftcolor
.pixel
= W_PIXEL(color
);
335 XftDrawChange(scr
->xftdraw
, d
);
338 previous_text
= pango_layout_get_text(font
->layout
);
339 if ((previous_text
== NULL
) || (strcmp(text
, previous_text
) != 0))
340 pango_layout_set_text(font
->layout
, text
, length
);
341 pango_xft_render_layout(scr
->xftdraw
, &xftcolor
, font
->layout
, x
* PANGO_SCALE
, y
* PANGO_SCALE
);
343 XftDrawStringUtf8(scr
->xftdraw
, &xftcolor
, font
->font
, x
, y
+ font
->y
, (XftChar8
*) text
, length
);
348 WMDrawImageString(WMScreen
* scr
, Drawable d
, WMColor
* color
, WMColor
* background
,
349 WMFont
* font
, int x
, int y
, const char *text
, int length
)
354 const char *previous_text
;
357 wassertr(font
!= NULL
);
359 textColor
.color
.red
= color
->color
.red
;
360 textColor
.color
.green
= color
->color
.green
;
361 textColor
.color
.blue
= color
->color
.blue
;
362 textColor
.color
.alpha
= color
->alpha
;;
363 textColor
.pixel
= W_PIXEL(color
);
365 bgColor
.color
.red
= background
->color
.red
;
366 bgColor
.color
.green
= background
->color
.green
;
367 bgColor
.color
.blue
= background
->color
.blue
;
368 bgColor
.color
.alpha
= background
->alpha
;;
369 bgColor
.pixel
= W_PIXEL(background
);
371 XftDrawChange(scr
->xftdraw
, d
);
373 XftDrawRect(scr
->xftdraw
, &bgColor
, x
, y
, WMWidthOfString(font
, text
, length
), font
->height
);
376 previous_text
= pango_layout_get_text(font
->layout
);
377 if ((previous_text
== NULL
) || (strcmp(text
, previous_text
) != 0))
378 pango_layout_set_text(font
->layout
, text
, length
);
379 pango_xft_render_layout(scr
->xftdraw
, &textColor
, font
->layout
, x
* PANGO_SCALE
, y
* PANGO_SCALE
);
381 XftDrawStringUtf8(scr
->xftdraw
, &textColor
, font
->font
, x
, y
+ font
->y
, (XftChar8
*) text
, length
);
385 WMFont
*WMCopyFontWithStyle(WMScreen
* scrPtr
, WMFont
* font
, WMFontStyle style
)
394 /* It's enough to add italic to slant, even if the font has no italic
395 * variant, but only oblique. This is because fontconfig will actually
396 * return the closest match font to what we requested which is the
397 * oblique font. Same goes for using bold for weight.
399 pattern
= FcNameParse((FcChar8
*) WMGetFontName(font
));
402 FcPatternDel(pattern
, FC_WEIGHT
);
403 FcPatternDel(pattern
, FC_SLANT
);
406 FcPatternDel(pattern
, FC_WEIGHT
);
407 FcPatternAddString(pattern
, FC_WEIGHT
, (FcChar8
*) "bold");
410 FcPatternDel(pattern
, FC_SLANT
);
411 FcPatternAddString(pattern
, FC_SLANT
, (FcChar8
*) "italic");
414 FcPatternDel(pattern
, FC_WEIGHT
);
415 FcPatternDel(pattern
, FC_SLANT
);
416 FcPatternAddString(pattern
, FC_WEIGHT
, (FcChar8
*) "bold");
417 FcPatternAddString(pattern
, FC_SLANT
, (FcChar8
*) "italic");
421 name
= (char *)FcNameUnparse(pattern
);
422 copy
= WMCreateFont(scrPtr
, name
);
423 FcPatternDestroy(pattern
);