debian: Update with version 0.95.9-2 packaging.
[wmaker-crm.git] / WINGs / wfont.c
blob999aaa44111941fe7eba9af748db8c8aae255539
2 #include <stdlib.h>
4 #include "wconfig.h"
6 #include "WINGsP.h"
8 #include <wraster.h>
9 #include <assert.h>
10 #include <X11/Xlocale.h>
12 #include <X11/Xft/Xft.h>
13 #include <fontconfig/fontconfig.h>
15 #ifdef USE_PANGO
16 #include <pango/pango.h>
17 #include <pango/pangofc-fontmap.h>
18 #include <pango/pangoxft.h>
19 #endif
21 #define DEFAULT_FONT "sans serif:pixelsize=12"
23 #define DEFAULT_SIZE WINGsConfiguration.defaultFontSize
25 static FcPattern *xlfdToFcPattern(const char *xlfd)
27 FcPattern *pattern;
28 char *fname, *ptr;
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, ','))) {
37 *ptr = 0;
39 pattern = XftXlfdParse(fname, False, False);
40 wfree(fname);
42 if (!pattern) {
43 wwarning(_("invalid font: %s. Trying '%s'"), xlfd, DEFAULT_FONT);
44 pattern = FcNameParse((FcChar8 *) DEFAULT_FONT);
47 return pattern;
50 static char *xlfdToFcName(const char *xlfd)
52 FcPattern *pattern;
53 char *fname;
55 pattern = xlfdToFcPattern(xlfd);
56 fname = (char *)FcNameUnparse(pattern);
57 FcPatternDestroy(pattern);
59 return fname;
62 static Bool hasProperty(FcPattern * pattern, const char *property)
64 FcValue val;
66 if (FcPatternGet(pattern, property, 0, &val) == FcResultMatch) {
67 return True;
70 return False;
73 static Bool hasPropertyWithStringValue(FcPattern * pattern, const char *object, const char *value)
75 FcChar8 *str;
76 int id;
78 if (!value || value[0] == 0)
79 return True;
81 id = 0;
82 while (FcPatternGetString(pattern, object, id, &str) == FcResultMatch) {
83 if (strcasecmp(value, (char *)str) == 0) {
84 return True;
86 id++;
89 return False;
92 static char *makeFontOfSize(const char *font, int size, const char *fallback)
94 FcPattern *pattern;
95 char *result;
97 if (font[0] == '-') {
98 pattern = xlfdToFcPattern(font);
99 } else {
100 pattern = FcNameParse((const FcChar8 *) font);
103 /*FcPatternPrint(pattern); */
105 if (size > 0) {
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);
121 return result;
124 WMFont *WMCreateFont(WMScreen * scrPtr, const char *fontName)
126 Display *display = scrPtr->display;
127 WMFont *font;
128 char *fname;
129 #ifdef USE_PANGO
130 PangoFontMap *fontmap;
131 PangoContext *context;
132 PangoLayout *layout;
133 FcPattern *pattern;
134 PangoFontDescription *description;
135 double size;
136 #endif
138 if (fontName[0] == '-') {
139 fname = xlfdToFcName(fontName);
140 } else {
141 fname = wstrdup(fontName);
144 if (!WINGsConfiguration.antialiasedText && !strstr(fname, ":antialias=")) {
145 fname = wstrappend(fname, ":antialias=false");
148 font = WMHashGet(scrPtr->fontCache, fname);
149 if (font) {
150 WMRetainFont(font);
151 wfree(fname);
152 return font;
155 font = wmalloc(sizeof(WMFont));
157 font->screen = scrPtr;
159 font->font = XftFontOpenName(display, scrPtr->screen, fname);
160 if (!font->font) {
161 wfree(font);
162 wfree(fname);
163 return NULL;
166 font->height = font->font->ascent + font->font->descent;
167 font->y = font->font->ascent;
169 font->refCount = 1;
171 font->name = fname;
173 #ifdef USE_PANGO
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;
190 #endif
192 assert(WMHashInsert(scrPtr->fontCache, font->name, font) == NULL);
194 return font;
197 WMFont *WMRetainFont(WMFont * font)
199 wassertrv(font != NULL, NULL);
201 font->refCount++;
203 return font;
206 void WMReleaseFont(WMFont * font)
208 wassertr(font != NULL);
210 font->refCount--;
211 if (font->refCount < 1) {
212 XftFontClose(font->screen->display, font->font);
213 if (font->name) {
214 WMHashRemove(font->screen->fontCache, font->name);
215 wfree(font->name);
217 wfree(font);
221 Bool WMIsAntialiasingEnabled(WMScreen * scrPtr)
223 return scrPtr->antialiasedText;
226 unsigned int WMFontHeight(WMFont * font)
228 wassertrv(font != NULL, 0);
230 return font->height;
233 char *WMGetFontName(WMFont * font)
235 wassertrv(font != NULL, NULL);
237 return font->name;
240 void WMGetScaleBaseFromSystemFont(WMScreen *scrPtr, int *alphabetWidth, int *fontHeight)
242 WMFont *font;
244 font = WMDefaultSystemFont(scrPtr);
245 *alphabetWidth = WMWidthOfString(font, "abcdefghijklmnopqrstuvwxyz", 26);
246 *fontHeight = WMFontHeight(font);
247 WMReleaseFont(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)
262 WMFont *font;
263 char *fontSpec;
265 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL);
267 font = WMCreateFont(scrPtr, fontSpec);
269 if (!font) {
270 wwarning(_("could not load font: %s."), fontSpec);
273 wfree(fontSpec);
275 return font;
278 WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
280 WMFont *font;
281 char *fontSpec;
283 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL);
285 font = WMCreateFont(scrPtr, fontSpec);
287 if (!font) {
288 wwarning(_("could not load font: %s."), fontSpec);
291 wfree(fontSpec);
293 return font;
296 int WMWidthOfString(WMFont * font, const char *text, int length)
298 #ifdef USE_PANGO
299 const char *previous_text;
300 int width;
301 #else
302 XGlyphInfo extents;
303 #endif
305 wassertrv(font != NULL && text != NULL, 0);
306 #ifdef USE_PANGO
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);
312 return width;
313 #else
314 XftTextExtentsUtf8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
316 return extents.xOff; /* don't ask :P */
317 #endif
320 void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, int x, int y, const char *text, int length)
322 XftColor xftcolor;
323 #ifdef USE_PANGO
324 const char *previous_text;
325 #endif
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);
337 #ifdef USE_PANGO
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);
342 #else
343 XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
344 #endif
347 void
348 WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * background,
349 WMFont * font, int x, int y, const char *text, int length)
351 XftColor textColor;
352 XftColor bgColor;
353 #ifdef USE_PANGO
354 const char *previous_text;
355 #endif
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);
375 #ifdef USE_PANGO
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);
380 #else
381 XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
382 #endif
385 WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style)
387 FcPattern *pattern;
388 WMFont *copy;
389 char *name;
391 if (!font)
392 return NULL;
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));
400 switch (style) {
401 case WFSNormal:
402 FcPatternDel(pattern, FC_WEIGHT);
403 FcPatternDel(pattern, FC_SLANT);
404 break;
405 case WFSBold:
406 FcPatternDel(pattern, FC_WEIGHT);
407 FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
408 break;
409 case WFSItalic:
410 FcPatternDel(pattern, FC_SLANT);
411 FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
412 break;
413 case WFSBoldItalic:
414 FcPatternDel(pattern, FC_WEIGHT);
415 FcPatternDel(pattern, FC_SLANT);
416 FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
417 FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
418 break;
421 name = (char *)FcNameUnparse(pattern);
422 copy = WMCreateFont(scrPtr, name);
423 FcPatternDestroy(pattern);
424 wfree(name);
426 return copy;