wmaker: remove useless null pointer check (Coverity #109612)
[wmaker-crm.git] / WINGs / wfont.c
blobb3d399cf655bc604631c52fce723d1dbe89e555c
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 WMFont *WMDefaultSystemFont(WMScreen * scrPtr)
242 return WMRetainFont(scrPtr->normalFont);
245 WMFont *WMDefaultBoldSystemFont(WMScreen * scrPtr)
247 return WMRetainFont(scrPtr->boldFont);
250 WMFont *WMSystemFontOfSize(WMScreen * scrPtr, int size)
252 WMFont *font;
253 char *fontSpec;
255 fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, NULL);
257 font = WMCreateFont(scrPtr, fontSpec);
259 if (!font) {
260 wwarning(_("could not load font: %s."), fontSpec);
263 wfree(fontSpec);
265 return font;
268 WMFont *WMBoldSystemFontOfSize(WMScreen * scrPtr, int size)
270 WMFont *font;
271 char *fontSpec;
273 fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, NULL);
275 font = WMCreateFont(scrPtr, fontSpec);
277 if (!font) {
278 wwarning(_("could not load font: %s."), fontSpec);
281 wfree(fontSpec);
283 return font;
286 int WMWidthOfString(WMFont * font, const char *text, int length)
288 #ifdef USE_PANGO
289 const char *previous_text;
290 int width;
291 #else
292 XGlyphInfo extents;
293 #endif
295 wassertrv(font != NULL && text != NULL, 0);
296 #ifdef USE_PANGO
297 previous_text = pango_layout_get_text(font->layout);
298 if ((previous_text == NULL) || (strncmp(text, previous_text, length) != 0) || previous_text[length] != '\0')
299 pango_layout_set_text(font->layout, text, length);
300 pango_layout_get_pixel_size(font->layout, &width, NULL);
302 return width;
303 #else
304 XftTextExtentsUtf8(font->screen->display, font->font, (XftChar8 *) text, length, &extents);
306 return extents.xOff; /* don't ask :P */
307 #endif
310 void WMDrawString(WMScreen * scr, Drawable d, WMColor * color, WMFont * font, int x, int y, const char *text, int length)
312 XftColor xftcolor;
313 #ifdef USE_PANGO
314 const char *previous_text;
315 #endif
317 wassertr(font != NULL);
319 xftcolor.color.red = color->color.red;
320 xftcolor.color.green = color->color.green;
321 xftcolor.color.blue = color->color.blue;
322 xftcolor.color.alpha = color->alpha;;
323 xftcolor.pixel = W_PIXEL(color);
325 XftDrawChange(scr->xftdraw, d);
327 #ifdef USE_PANGO
328 previous_text = pango_layout_get_text(font->layout);
329 if ((previous_text == NULL) || (strcmp(text, previous_text) != 0))
330 pango_layout_set_text(font->layout, text, length);
331 pango_xft_render_layout(scr->xftdraw, &xftcolor, font->layout, x * PANGO_SCALE, y * PANGO_SCALE);
332 #else
333 XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, x, y + font->y, (XftChar8 *) text, length);
334 #endif
337 void
338 WMDrawImageString(WMScreen * scr, Drawable d, WMColor * color, WMColor * background,
339 WMFont * font, int x, int y, const char *text, int length)
341 XftColor textColor;
342 XftColor bgColor;
343 #ifdef USE_PANGO
344 const char *previous_text;
345 #endif
347 wassertr(font != NULL);
349 textColor.color.red = color->color.red;
350 textColor.color.green = color->color.green;
351 textColor.color.blue = color->color.blue;
352 textColor.color.alpha = color->alpha;;
353 textColor.pixel = W_PIXEL(color);
355 bgColor.color.red = background->color.red;
356 bgColor.color.green = background->color.green;
357 bgColor.color.blue = background->color.blue;
358 bgColor.color.alpha = background->alpha;;
359 bgColor.pixel = W_PIXEL(background);
361 XftDrawChange(scr->xftdraw, d);
363 XftDrawRect(scr->xftdraw, &bgColor, x, y, WMWidthOfString(font, text, length), font->height);
365 #ifdef USE_PANGO
366 previous_text = pango_layout_get_text(font->layout);
367 if ((previous_text == NULL) || (strcmp(text, previous_text) != 0))
368 pango_layout_set_text(font->layout, text, length);
369 pango_xft_render_layout(scr->xftdraw, &textColor, font->layout, x * PANGO_SCALE, y * PANGO_SCALE);
370 #else
371 XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, x, y + font->y, (XftChar8 *) text, length);
372 #endif
375 WMFont *WMCopyFontWithStyle(WMScreen * scrPtr, WMFont * font, WMFontStyle style)
377 FcPattern *pattern;
378 WMFont *copy;
379 char *name;
381 if (!font)
382 return NULL;
384 /* It's enough to add italic to slant, even if the font has no italic
385 * variant, but only oblique. This is because fontconfig will actually
386 * return the closest match font to what we requested which is the
387 * oblique font. Same goes for using bold for weight.
389 pattern = FcNameParse((FcChar8 *) WMGetFontName(font));
390 switch (style) {
391 case WFSNormal:
392 FcPatternDel(pattern, FC_WEIGHT);
393 FcPatternDel(pattern, FC_SLANT);
394 break;
395 case WFSBold:
396 FcPatternDel(pattern, FC_WEIGHT);
397 FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
398 break;
399 case WFSItalic:
400 FcPatternDel(pattern, FC_SLANT);
401 FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
402 break;
403 case WFSBoldItalic:
404 FcPatternDel(pattern, FC_WEIGHT);
405 FcPatternDel(pattern, FC_SLANT);
406 FcPatternAddString(pattern, FC_WEIGHT, (FcChar8 *) "bold");
407 FcPatternAddString(pattern, FC_SLANT, (FcChar8 *) "italic");
408 break;
411 name = (char *)FcNameUnparse(pattern);
412 copy = WMCreateFont(scrPtr, name);
413 FcPatternDestroy(pattern);
414 wfree(name);
416 return copy;