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_slice_new(RrFont);
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_SINGLE);
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);
117 pango_font_description_set_absolute_size(out->font_desc, -size * PANGO_SCALE);
119 pango_font_description_set_size(out->font_desc, size * PANGO_SCALE);
121 /* setup the layout */
122 pango_layout_set_font_description(out->layout, out->font_desc);
123 pango_layout_set_wrap(out->layout, PANGO_WRAP_WORD_CHAR);
125 /* get the ascent and descent */
126 measure_font(inst, out);
131 RrFont *RrFontOpenDefault(const RrInstance *inst)
133 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
134 RrDefaultFontWeight, RrDefaultFontSlant);
137 void RrFontRef(RrFont *f)
142 void RrFontClose(RrFont *f)
146 g_object_unref(f->layout);
147 pango_font_description_free(f->font_desc);
148 g_slice_free(RrFont, f);
153 static void font_measure_full(const RrFont *f, const gchar *str,
154 gint *x, gint *y, gint shadow_x, gint shadow_y,
155 gboolean flow, gint maxwidth)
159 pango_layout_set_text(f->layout, str, -1);
161 pango_layout_set_single_paragraph_mode(f->layout, FALSE);
162 pango_layout_set_width(f->layout, maxwidth * PANGO_SCALE);
163 pango_layout_set_ellipsize(f->layout, PANGO_ELLIPSIZE_NONE);
166 /* single line mode */
167 pango_layout_set_single_paragraph_mode(f->layout, TRUE);
168 pango_layout_set_width(f->layout, -1);
169 pango_layout_set_ellipsize(f->layout, PANGO_ELLIPSIZE_MIDDLE);
172 /* pango_layout_get_pixel_extents lies! this is the right way to get the
173 size of the text's area */
174 pango_layout_get_extents(f->layout, NULL, &rect);
175 #if PANGO_VERSION_MAJOR > 1 || \
176 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
177 /* pass the logical rect as the ink rect, this is on purpose so we get the
178 full area for the text */
179 pango_extents_to_pixels(&rect, NULL);
181 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
182 rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
184 *x = rect.width + ABS(shadow_x) + 4 /* we put a 2 px edge on each side */;
185 *y = rect.height + ABS(shadow_y);
188 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
189 gint shadow_x, gint shadow_y,
190 gboolean flow, gint maxwidth)
194 g_assert(!flow || maxwidth > 0);
196 size = g_slice_new(RrSize);
197 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y,
202 gint RrFontHeight(const RrFont *f, gint shadow_y)
204 return (f->ascent + f->descent) / PANGO_SCALE + ABS(shadow_y);
207 static inline int font_calculate_baseline(RrFont *f, gint height)
209 /* For my own reference:
211 * ^space/2 ^height ^baseline
214 * | | | | |_ _____ _| |_ _ _
215 * | | | | _/ -_) \ / _| || |
216 * | v_________v \__\___/_\_\\__|\_, |
222 return (((height * PANGO_SCALE) /* height of the space in pango units */
223 - (f->ascent + f->descent)) /* minus space taken up by text */
224 / 2 /* divided by two -> half of the empty space (this is the top
226 + f->ascent) /* now move down to the baseline */
227 / PANGO_SCALE; /* back to pixels */
230 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
236 PangoAttrList *attrlist;
237 PangoEllipsizeMode ell;
239 g_assert(!t->flow || t->maxwidth > 0);
243 /* center the text vertically
244 We do this centering based on the 'baseline' since different fonts
245 have different top edges. It looks bad when the whole string is
246 moved when 1 character from a non-default language is included in
248 y += font_calculate_baseline(t->font, area->height);
250 /* the +2 and -4 leave a small blank edge on the sides */
253 if (t->flow) w = MAX(w, t->maxwidth);
255 /* h = area->height; */
258 ell = PANGO_ELLIPSIZE_NONE;
260 switch (t->ellipsize) {
261 case RR_ELLIPSIZE_NONE:
262 ell = PANGO_ELLIPSIZE_NONE;
264 case RR_ELLIPSIZE_START:
265 ell = PANGO_ELLIPSIZE_START;
267 case RR_ELLIPSIZE_MIDDLE:
268 ell = PANGO_ELLIPSIZE_MIDDLE;
270 case RR_ELLIPSIZE_END:
271 ell = PANGO_ELLIPSIZE_END;
274 g_assert_not_reached();
278 pango_layout_set_text(t->font->layout, t->string, -1);
279 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
280 pango_layout_set_ellipsize(t->font->layout, ell);
281 pango_layout_set_single_paragraph_mode(t->font->layout, !t->flow);
283 /* * * end of setting up the layout * * */
285 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
288 /* pango_layout_set_alignment doesn't work with
289 pango_xft_render_layout_line */
290 switch (t->justify) {
291 case RR_JUSTIFY_LEFT:
293 case RR_JUSTIFY_RIGHT:
296 case RR_JUSTIFY_CENTER:
299 case RR_JUSTIFY_NUM_TYPES:
300 g_assert_not_reached();
303 if (t->shadow_offset_x || t->shadow_offset_y) {
304 /* From nvidia's readme (chapter 23):
306 When rendering to a 32-bit window, keep in mind that the X RENDER
307 extension, used by most composite managers, expects "premultiplied
308 alpha" colors. This means that if your color has components (r,g,b)
309 and alpha value a, then you must render (a*r, a*g, a*b, a) into the
312 c.color.red = (t->shadow_color->r | t->shadow_color->r << 8) *
313 t->shadow_alpha / 255;
314 c.color.green = (t->shadow_color->g | t->shadow_color->g << 8) *
315 t->shadow_alpha / 255;
316 c.color.blue = (t->shadow_color->b | t->shadow_color->b << 8) *
317 t->shadow_alpha / 255;
318 c.color.alpha = 0xffff * t->shadow_alpha / 255;
319 c.pixel = t->shadow_color->pixel;
323 pango_xft_render_layout_line
325 #if PANGO_VERSION_MAJOR > 1 || \
326 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
327 pango_layout_get_line_readonly(t->font->layout, 0),
329 pango_layout_get_line(t->font->layout, 0),
331 (x + t->shadow_offset_x) * PANGO_SCALE,
332 (y + t->shadow_offset_y) * PANGO_SCALE);
335 pango_xft_render_layout(d, &c, t->font->layout,
336 (x + t->shadow_offset_x) * PANGO_SCALE,
337 (y + t->shadow_offset_y) * PANGO_SCALE);
341 c.color.red = t->color->r | t->color->r << 8;
342 c.color.green = t->color->g | t->color->g << 8;
343 c.color.blue = t->color->b | t->color->b << 8;
344 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
345 c.pixel = t->color->pixel;
348 const gchar *s = t->string + t->shortcut_pos;
350 t->font->shortcut_underline->start_index = t->shortcut_pos;
351 t->font->shortcut_underline->end_index = t->shortcut_pos +
352 (g_utf8_next_char(s) - s);
354 /* the attributes are owned by the layout.
355 re-add the attributes to the layout after changing the
356 start and end index */
357 attrlist = pango_layout_get_attributes(t->font->layout);
358 pango_attr_list_ref(attrlist);
359 pango_layout_set_attributes(t->font->layout, attrlist);
360 pango_attr_list_unref(attrlist);
363 /* layout_line() uses y to specify the baseline
364 The line doesn't need to be freed, it's a part of the layout */
366 pango_xft_render_layout_line
368 #if PANGO_VERSION_MAJOR > 1 || \
369 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
370 pango_layout_get_line_readonly(t->font->layout, 0),
372 pango_layout_get_line(t->font->layout, 0),
378 pango_xft_render_layout(d, &c, t->font->layout,
384 t->font->shortcut_underline->start_index = 0;
385 t->font->shortcut_underline->end_index = 0;
386 /* the attributes are owned by the layout.
387 re-add the attributes to the layout after changing the
388 start and end index */
389 attrlist = pango_layout_get_attributes(t->font->layout);
390 pango_attr_list_ref(attrlist);
391 pango_layout_set_attributes(t->font->layout, attrlist);
392 pango_attr_list_unref(attrlist);