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 RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
64 RrFontWeight weight, RrFontSlant slant)
69 PangoAttrList *attrlist;
71 out = g_new(RrFont, 1);
74 out->font_desc = pango_font_description_new();
75 out->layout = pango_layout_new(inst->pango);
76 out->shortcut_underline = pango_attr_underline_new(PANGO_UNDERLINE_LOW);
77 out->shortcut_underline->start_index = 0;
78 out->shortcut_underline->end_index = 0;
80 attrlist = pango_attr_list_new();
81 /* shortcut_underline is owned by the attrlist */
82 pango_attr_list_insert(attrlist, out->shortcut_underline);
83 /* the attributes are owned by the layout */
84 pango_layout_set_attributes(out->layout, attrlist);
85 pango_attr_list_unref(attrlist);
88 case RR_FONTWEIGHT_LIGHT: pweight = PANGO_WEIGHT_LIGHT; break;
89 case RR_FONTWEIGHT_NORMAL: pweight = PANGO_WEIGHT_NORMAL; break;
90 case RR_FONTWEIGHT_SEMIBOLD: pweight = PANGO_WEIGHT_SEMIBOLD; break;
91 case RR_FONTWEIGHT_BOLD: pweight = PANGO_WEIGHT_BOLD; break;
92 case RR_FONTWEIGHT_ULTRABOLD: pweight = PANGO_WEIGHT_ULTRABOLD; break;
93 default: g_assert_not_reached();
97 case RR_FONTSLANT_NORMAL: pstyle = PANGO_STYLE_NORMAL; break;
98 case RR_FONTSLANT_ITALIC: pstyle = PANGO_STYLE_ITALIC; break;
99 case RR_FONTSLANT_OBLIQUE: pstyle = PANGO_STYLE_OBLIQUE; break;
100 default: g_assert_not_reached();
104 pango_font_description_set_family(out->font_desc, name);
105 pango_font_description_set_weight(out->font_desc, pweight);
106 pango_font_description_set_style(out->font_desc, pstyle);
107 pango_font_description_set_size(out->font_desc, size * PANGO_SCALE);
109 /* setup the layout */
110 pango_layout_set_font_description(out->layout, out->font_desc);
111 pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
113 /* get the ascent and descent */
114 measure_font(inst, out);
119 RrFont *RrFontOpenDefault(const RrInstance *inst)
121 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
122 RrDefaultFontWeight, RrDefaultFontSlant);
125 void RrFontRef(RrFont *f)
130 void RrFontClose(RrFont *f)
134 g_object_unref(f->layout);
135 pango_font_description_free(f->font_desc);
141 static void font_measure_full(const RrFont *f, const gchar *str,
142 gint *x, gint *y, gint shadow_x, gint shadow_y,
143 gboolean flow, gint maxwidth)
147 pango_layout_set_text(f->layout, str, -1);
149 pango_layout_set_single_paragraph_mode(f->layout, FALSE);
150 pango_layout_set_width(f->layout, maxwidth * PANGO_SCALE);
151 pango_layout_set_ellipsize(f->layout, PANGO_ELLIPSIZE_NONE);
154 /* single line mode */
155 pango_layout_set_single_paragraph_mode(f->layout, TRUE);
156 pango_layout_set_width(f->layout, -1);
157 pango_layout_set_ellipsize(f->layout, PANGO_ELLIPSIZE_MIDDLE);
160 /* pango_layout_get_pixel_extents lies! this is the right way to get the
161 size of the text's area */
162 pango_layout_get_extents(f->layout, NULL, &rect);
163 #if PANGO_VERSION_MAJOR > 1 || \
164 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
165 /* pass the logical rect as the ink rect, this is on purpose so we get the
166 full area for the text */
167 pango_extents_to_pixels(&rect, NULL);
169 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
170 rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
172 *x = rect.width + ABS(shadow_x) + 4 /* we put a 2 px edge on each side */;
173 *y = rect.height + ABS(shadow_y);
176 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
177 gint shadow_x, gint shadow_y,
178 gboolean flow, gint maxwidth)
182 g_assert(!flow || maxwidth > 0);
184 size = g_new(RrSize, 1);
185 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
190 gint RrFontHeight(const RrFont *f, gint shadow_y)
192 return (f->ascent + f->descent) / PANGO_SCALE + ABS(shadow_y);
195 static inline int font_calculate_baseline(RrFont *f, gint height)
197 /* For my own reference:
199 * ^space/2 ^height ^baseline
202 * | | | | |_ _____ _| |_ _ _
203 * | | | | _/ -_) \ / _| || |
204 * | v_________v \__\___/_\_\\__|\_, |
210 return (((height * PANGO_SCALE) /* height of the space in pango units */
211 - (f->ascent + f->descent)) /* minus space taken up by text */
212 / 2 /* divided by two -> half of the empty space (this is the top
214 + f->ascent) /* now move down to the baseline */
215 / PANGO_SCALE; /* back to pixels */
218 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
224 PangoAttrList *attrlist;
225 PangoEllipsizeMode ell;
227 g_assert(!t->flow || t->maxwidth > 0);
231 /* center the text vertically
232 We do this centering based on the 'baseline' since different fonts
233 have different top edges. It looks bad when the whole string is
234 moved when 1 character from a non-default language is included in
236 y += font_calculate_baseline(t->font, area->height);
238 /* the +2 and -4 leave a small blank edge on the sides */
241 if (t->flow) w = MAX(w, t->maxwidth);
243 /* h = area->height; */
246 ell = PANGO_ELLIPSIZE_NONE;
248 switch (t->ellipsize) {
249 case RR_ELLIPSIZE_NONE:
250 ell = PANGO_ELLIPSIZE_NONE;
252 case RR_ELLIPSIZE_START:
253 ell = PANGO_ELLIPSIZE_START;
255 case RR_ELLIPSIZE_MIDDLE:
256 ell = PANGO_ELLIPSIZE_MIDDLE;
258 case RR_ELLIPSIZE_END:
259 ell = PANGO_ELLIPSIZE_END;
262 g_assert_not_reached();
266 pango_layout_set_text(t->font->layout, t->string, -1);
267 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
268 pango_layout_set_ellipsize(t->font->layout, ell);
269 pango_layout_set_single_paragraph_mode(t->font->layout, !t->flow);
271 /* * * end of setting up the layout * * */
273 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
276 /* pango_layout_set_alignment doesn't work with
277 pango_xft_render_layout_line */
278 switch (t->justify) {
279 case RR_JUSTIFY_LEFT:
281 case RR_JUSTIFY_RIGHT:
284 case RR_JUSTIFY_CENTER:
289 if (t->shadow_offset_x || t->shadow_offset_y) {
290 /* From nvidia's readme (chapter 23):
292 When rendering to a 32-bit window, keep in mind that the X RENDER
293 extension, used by most composite managers, expects "premultiplied
294 alpha" colors. This means that if your color has components (r,g,b)
295 and alpha value a, then you must render (a*r, a*g, a*b, a) into the
298 c.color.red = (t->shadow_color->r | t->shadow_color->r << 8) *
299 t->shadow_alpha / 255;
300 c.color.green = (t->shadow_color->g | t->shadow_color->g << 8) *
301 t->shadow_alpha / 255;
302 c.color.blue = (t->shadow_color->b | t->shadow_color->b << 8) *
303 t->shadow_alpha / 255;
304 c.color.alpha = 0xffff * t->shadow_alpha / 255;
305 c.pixel = t->shadow_color->pixel;
309 pango_xft_render_layout_line
311 #if PANGO_VERSION_MAJOR > 1 || \
312 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
313 pango_layout_get_line_readonly(t->font->layout, 0),
315 pango_layout_get_line(t->font->layout, 0),
317 (x + t->shadow_offset_x) * PANGO_SCALE,
318 (y + t->shadow_offset_y) * PANGO_SCALE);
321 pango_xft_render_layout(d, &c, t->font->layout,
322 (x + t->shadow_offset_x) * PANGO_SCALE,
323 (y + t->shadow_offset_y) * PANGO_SCALE);
327 c.color.red = t->color->r | t->color->r << 8;
328 c.color.green = t->color->g | t->color->g << 8;
329 c.color.blue = t->color->b | t->color->b << 8;
330 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
331 c.pixel = t->color->pixel;
334 const gchar *s = t->string + t->shortcut_pos;
336 t->font->shortcut_underline->start_index = t->shortcut_pos;
337 t->font->shortcut_underline->end_index = t->shortcut_pos +
338 (g_utf8_next_char(s) - s);
340 /* the attributes are owned by the layout.
341 re-add the attributes to the layout after changing the
342 start and end index */
343 attrlist = pango_layout_get_attributes(t->font->layout);
344 pango_attr_list_ref(attrlist);
345 pango_layout_set_attributes(t->font->layout, attrlist);
346 pango_attr_list_unref(attrlist);
349 /* layout_line() uses y to specify the baseline
350 The line doesn't need to be freed, it's a part of the layout */
352 pango_xft_render_layout_line
354 #if PANGO_VERSION_MAJOR > 1 || \
355 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
356 pango_layout_get_line_readonly(t->font->layout, 0),
358 pango_layout_get_line(t->font->layout, 0),
364 pango_xft_render_layout(d, &c, t->font->layout,
370 t->font->shortcut_underline->start_index = 0;
371 t->font->shortcut_underline->end_index = 0;
372 /* the attributes are owned by the layout.
373 re-add the attributes to the layout after changing the
374 start and end index */
375 attrlist = pango_layout_get_attributes(t->font->layout);
376 pango_attr_list_ref(attrlist);
377 pango_layout_set_attributes(t->font->layout, attrlist);
378 pango_attr_list_unref(attrlist);