1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 font.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2007 Dana Jansens
6 Copyright (c) 2003 Derek Foreman
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 See the COPYING file for a copy of the GNU General Public License.
34 static void measure_font(const RrInstance *inst, RrFont *f)
36 PangoFontMetrics *metrics;
37 static PangoLanguage *lang = NULL;
40 #if PANGO_VERSION_MAJOR > 1 || \
41 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
42 lang = pango_language_get_default();
45 /* get the default language from the locale
46 (based on gtk_get_default_language in gtkmain.c) */
47 locale = g_strdup(setlocale(LC_CTYPE, NULL));
48 if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
49 if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
50 lang = pango_language_from_string(locale);
55 /* measure the ascent and descent */
56 metrics = pango_context_get_metrics(inst->pango, f->font_desc, lang);
57 f->ascent = pango_font_metrics_get_ascent(metrics);
58 f->descent = pango_font_metrics_get_descent(metrics);
59 pango_font_metrics_unref(metrics);
63 void RrFontDescriptionFromString(RrFont *font, gchar *description)
65 PangoFontDescription *desc;
66 desc = pango_font_description_from_string(description);
67 pango_font_description_merge(font->font_desc, desc, TRUE);
68 pango_font_description_free(desc);
69 pango_layout_set_font_description(font->layout, font->font_desc);
72 RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
73 RrFontWeight weight, RrFontSlant slant)
78 PangoAttrList *attrlist;
80 out = g_new(RrFont, 1);
83 out->font_desc = pango_font_description_new();
84 out->layout = pango_layout_new(inst->pango);
85 out->shortcut_underline = pango_attr_underline_new(PANGO_UNDERLINE_LOW);
86 out->shortcut_underline->start_index = 0;
87 out->shortcut_underline->end_index = 0;
89 attrlist = pango_attr_list_new();
90 /* shortcut_underline is owned by the attrlist */
91 pango_attr_list_insert(attrlist, out->shortcut_underline);
92 /* the attributes are owned by the layout */
93 pango_layout_set_attributes(out->layout, attrlist);
94 pango_attr_list_unref(attrlist);
97 case RR_FONTWEIGHT_LIGHT: pweight = PANGO_WEIGHT_LIGHT; break;
98 case RR_FONTWEIGHT_NORMAL: pweight = PANGO_WEIGHT_NORMAL; break;
99 case RR_FONTWEIGHT_SEMIBOLD: pweight = PANGO_WEIGHT_SEMIBOLD; break;
100 case RR_FONTWEIGHT_BOLD: pweight = PANGO_WEIGHT_BOLD; break;
101 case RR_FONTWEIGHT_ULTRABOLD: pweight = PANGO_WEIGHT_ULTRABOLD; break;
102 default: g_assert_not_reached();
106 case RR_FONTSLANT_NORMAL: pstyle = PANGO_STYLE_NORMAL; break;
107 case RR_FONTSLANT_ITALIC: pstyle = PANGO_STYLE_ITALIC; break;
108 case RR_FONTSLANT_OBLIQUE: pstyle = PANGO_STYLE_OBLIQUE; break;
109 default: g_assert_not_reached();
113 pango_font_description_set_family(out->font_desc, name);
114 pango_font_description_set_weight(out->font_desc, pweight);
115 pango_font_description_set_style(out->font_desc, pstyle);
116 pango_font_description_set_size(out->font_desc, size * PANGO_SCALE);
118 /* setup the layout */
119 pango_layout_set_font_description(out->layout, out->font_desc);
120 pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
122 /* get the ascent and descent */
123 measure_font(inst, out);
128 RrFont *RrFontOpenDefault(const RrInstance *inst)
130 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
131 RrDefaultFontWeight, RrDefaultFontSlant);
134 void RrFontRef(RrFont *f)
139 void RrFontClose(RrFont *f)
143 g_object_unref(f->layout);
144 pango_font_description_free(f->font_desc);
150 static void font_measure_full(const RrFont *f, const gchar *str,
151 gint *x, gint *y, gint shadow_x, gint shadow_y,
152 gboolean flow, gint maxwidth)
156 pango_layout_set_text(f->layout, str, -1);
158 pango_layout_set_single_paragraph_mode(f->layout, FALSE);
159 pango_layout_set_width(f->layout, maxwidth * PANGO_SCALE);
160 pango_layout_set_ellipsize(f->layout, PANGO_ELLIPSIZE_NONE);
163 /* single line mode */
164 pango_layout_set_single_paragraph_mode(f->layout, TRUE);
165 pango_layout_set_width(f->layout, -1);
166 pango_layout_set_ellipsize(f->layout, PANGO_ELLIPSIZE_MIDDLE);
169 /* pango_layout_get_pixel_extents lies! this is the right way to get the
170 size of the text's area */
171 pango_layout_get_extents(f->layout, NULL, &rect);
172 #if PANGO_VERSION_MAJOR > 1 || \
173 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
174 /* pass the logical rect as the ink rect, this is on purpose so we get the
175 full area for the text */
176 pango_extents_to_pixels(&rect, NULL);
178 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
179 rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
181 *x = rect.width + /* ABS(shadow_x) +*/ 4 /* we put a 2 px edge on each side */;
182 *y = rect.height /*+ ABS(shadow_y) */;
185 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
186 gint shadow_x, gint shadow_y,
187 gboolean flow, gint maxwidth)
191 g_assert(!flow || maxwidth > 0);
193 size = g_new(RrSize, 1);
194 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
199 gint RrFontHeight(const RrFont *f, gint shadow_y)
201 return (f->ascent + f->descent) / PANGO_SCALE + 0-1;//ABS(shadow_y);
204 static inline int font_calculate_baseline(RrFont *f, gint height)
206 /* For my own reference:
208 * ^space/2 ^height ^baseline
211 * | | | | |_ _____ _| |_ _ _
212 * | | | | _/ -_) \ / _| || |
213 * | v_________v \__\___/_\_\\__|\_, |
219 return (((height * PANGO_SCALE) /* height of the space in pango units */
220 - (f->ascent + f->descent)) /* minus space taken up by text */
221 / 2 /* divided by two -> half of the empty space (this is the top
223 + f->ascent) /* now move down to the baseline */
224 / PANGO_SCALE; /* back to pixels */
227 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
233 PangoAttrList *attrlist;
234 PangoEllipsizeMode ell;
236 g_assert(!t->flow || t->maxwidth > 0);
240 /* center the text vertically
241 We do this centering based on the 'baseline' since different fonts
242 have different top edges. It looks bad when the whole string is
243 moved when 1 character from a non-default language is included in
245 y += font_calculate_baseline(t->font, area->height);
247 /* the +2 and -4 leave a small blank edge on the sides */
250 if (t->flow) w = MAX(w, t->maxwidth);
255 ell = PANGO_ELLIPSIZE_NONE;
257 switch (t->ellipsize) {
258 case RR_ELLIPSIZE_NONE:
259 ell = PANGO_ELLIPSIZE_NONE;
261 case RR_ELLIPSIZE_START:
262 ell = PANGO_ELLIPSIZE_START;
264 case RR_ELLIPSIZE_MIDDLE:
265 ell = PANGO_ELLIPSIZE_MIDDLE;
267 case RR_ELLIPSIZE_END:
268 ell = PANGO_ELLIPSIZE_END;
273 pango_layout_set_text(t->font->layout, t->string, -1);
274 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
275 pango_layout_set_ellipsize(t->font->layout, ell);
276 pango_layout_set_single_paragraph_mode(t->font->layout, !t->flow);
278 /* * * end of setting up the layout * * */
280 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
283 /* pango_layout_set_alignment doesn't work with
284 pango_xft_render_layout_line */
285 switch (t->justify) {
286 case RR_JUSTIFY_LEFT:
288 case RR_JUSTIFY_RIGHT:
291 case RR_JUSTIFY_CENTER:
296 if (t->shadow_offset_x || t->shadow_offset_y) {
297 /* From nvidia's readme (chapter 23):
299 When rendering to a 32-bit window, keep in mind that the X RENDER
300 extension, used by most composite managers, expects "premultiplied
301 alpha" colors. This means that if your color has components (r,g,b)
302 and alpha value a, then you must render (a*r, a*g, a*b, a) into the
305 c.color.red = (t->shadow_color->r | t->shadow_color->r << 8) *
306 t->shadow_alpha / 255;
307 c.color.green = (t->shadow_color->g | t->shadow_color->g << 8) *
308 t->shadow_alpha / 255;
309 c.color.blue = (t->shadow_color->b | t->shadow_color->b << 8) *
310 t->shadow_alpha / 255;
311 c.color.alpha = 0xffff * t->shadow_alpha / 255;
312 c.pixel = t->shadow_color->pixel;
316 pango_xft_render_layout_line
318 #if PANGO_VERSION_MAJOR > 1 || \
319 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
320 pango_layout_get_line_readonly(t->font->layout, 0),
322 pango_layout_get_line(t->font->layout, 0),
324 (x + t->shadow_offset_x) * PANGO_SCALE,
325 (y + t->shadow_offset_y) * PANGO_SCALE);
328 pango_xft_render_layout(d, &c, t->font->layout,
329 (x + t->shadow_offset_x) * PANGO_SCALE,
330 (y + t->shadow_offset_y) * PANGO_SCALE);
334 c.color.red = t->color->r | t->color->r << 8;
335 c.color.green = t->color->g | t->color->g << 8;
336 c.color.blue = t->color->b | t->color->b << 8;
337 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
338 c.pixel = t->color->pixel;
341 const gchar *s = t->string + t->shortcut_pos;
343 t->font->shortcut_underline->start_index = t->shortcut_pos;
344 t->font->shortcut_underline->end_index = t->shortcut_pos +
345 (g_utf8_next_char(s) - s);
347 /* the attributes are owned by the layout.
348 re-add the attributes to the layout after changing the
349 start and end index */
350 attrlist = pango_layout_get_attributes(t->font->layout);
351 pango_attr_list_ref(attrlist);
352 pango_layout_set_attributes(t->font->layout, attrlist);
353 pango_attr_list_unref(attrlist);
356 /* layout_line() uses y to specify the baseline
357 The line doesn't need to be freed, it's a part of the layout */
359 pango_xft_render_layout_line
361 #if PANGO_VERSION_MAJOR > 1 || \
362 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
363 pango_layout_get_line_readonly(t->font->layout, 0),
365 pango_layout_get_line(t->font->layout, 0),
371 pango_xft_render_layout(d, &c, t->font->layout,
377 t->font->shortcut_underline->start_index = 0;
378 t->font->shortcut_underline->end_index = 0;
379 /* the attributes are owned by the layout.
380 re-add the attributes to the layout after changing the
381 start and end index */
382 attrlist = pango_layout_get_attributes(t->font->layout);
383 pango_attr_list_ref(attrlist);
384 pango_layout_set_attributes(t->font->layout, attrlist);
385 pango_attr_list_unref(attrlist);