]> Dogcows Code - chaz/openbox/blob - render/font.c
PANGO_VERSION_CHECK is new
[chaz/openbox] / render / font.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
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
7
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.
12
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.
17
18 See the COPYING file for a copy of the GNU General Public License.
19 */
20
21 #include "font.h"
22 #include "color.h"
23 #include "mask.h"
24 #include "theme.h"
25 #include "geom.h"
26 #include "instance.h"
27 #include "gettext.h"
28
29 #include <glib.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <locale.h>
33
34 static void measure_font(const RrInstance *inst, RrFont *f)
35 {
36 PangoFontMetrics *metrics;
37 static PangoLanguage *lang = NULL;
38
39 if (lang == NULL) {
40 #if PANGO_VERSION_MAJOR > 1 || \
41 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
42 lang = pango_language_get_default();
43 #else
44 gchar *locale, *p;
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);
51 g_free(locale);
52 #endif
53 }
54
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);
60
61 }
62
63 RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
64 RrFontWeight weight, RrFontSlant slant)
65 {
66 RrFont *out;
67 PangoWeight pweight;
68 PangoStyle pstyle;
69 PangoAttrList *attrlist;
70
71 out = g_new(RrFont, 1);
72 out->inst = inst;
73 out->ref = 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;
79
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);
86
87 switch (weight) {
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();
94 }
95
96 switch (slant) {
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();
101 }
102
103 /* setup the font */
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);
108
109 /* setup the layout */
110 pango_layout_set_font_description(out->layout, out->font_desc);
111 pango_layout_set_single_paragraph_mode(out->layout, TRUE);
112 pango_layout_set_ellipsize(out->layout, PANGO_ELLIPSIZE_MIDDLE);
113
114 /* get the ascent and descent */
115 measure_font(inst, out);
116
117 return out;
118 }
119
120 RrFont *RrFontOpenDefault(const RrInstance *inst)
121 {
122 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
123 RrDefaultFontWeight, RrDefaultFontSlant);
124 }
125
126 void RrFontRef(RrFont *f)
127 {
128 ++f->ref;
129 }
130
131 void RrFontClose(RrFont *f)
132 {
133 if (f) {
134 if (--f->ref < 1) {
135 g_object_unref(f->layout);
136 pango_font_description_free(f->font_desc);
137 g_free(f);
138 }
139 }
140 }
141
142 static void font_measure_full(const RrFont *f, const gchar *str,
143 gint *x, gint *y, gint shadow_x, gint shadow_y)
144 {
145 PangoRectangle rect;
146
147 pango_layout_set_text(f->layout, str, -1);
148 pango_layout_set_width(f->layout, -1);
149 pango_layout_get_pixel_extents(f->layout, NULL, &rect);
150 *x = rect.width + ABS(shadow_x) + 4 /* we put a 2 px edge on each side */;
151 *y = rect.height + ABS(shadow_y);
152 }
153
154 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
155 gint shadow_x, gint shadow_y)
156 {
157 RrSize *size;
158 size = g_new(RrSize, 1);
159 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y);
160 return size;
161 }
162
163 gint RrFontHeight(const RrFont *f, gint shadow_y)
164 {
165 return (f->ascent + f->descent) / PANGO_SCALE + ABS(shadow_y);
166 }
167
168 static inline int font_calculate_baseline(RrFont *f, gint height)
169 {
170 /* For my own reference:
171 * _________
172 * ^space/2 ^height ^baseline
173 * v_________|_ |
174 * | ^ascent | _ _
175 * | | | | |_ _____ _| |_ _ _
176 * | | | | _/ -_) \ / _| || |
177 * | v_________v \__\___/_\_\\__|\_, |
178 * | ^descent |__/
179 * __________|_v
180 * ^space/2 |
181 * V_________v
182 */
183 return (((height * PANGO_SCALE) /* height of the space in pango units */
184 - (f->ascent + f->descent)) /* minus space taken up by text */
185 / 2 /* divided by two -> half of the empty space (this is the top
186 of the text) */
187 + f->ascent) /* now move down to the baseline */
188 / PANGO_SCALE; /* back to pixels */
189 }
190
191 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
192 {
193 gint x,y,w,h;
194 XftColor c;
195 gint mw;
196 PangoRectangle rect;
197 PangoAttrList *attrlist;
198
199 /* center the text vertically
200 We do this centering based on the 'baseline' since different fonts have
201 different top edges. It looks bad when the whole string is moved when 1
202 character from a non-default language is included in the string */
203 y = area->y +
204 font_calculate_baseline(t->font, area->height);
205
206 /* the +2 and -4 leave a small blank edge on the sides */
207 x = area->x + 2;
208 w = area->width - 4;
209 h = area->height;
210
211 pango_layout_set_text(t->font->layout, t->string, -1);
212 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
213
214 /* * * end of setting up the layout * * */
215
216 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
217 mw = rect.width;
218
219 /* pango_layout_set_alignment doesn't work with
220 pango_xft_render_layout_line */
221 switch (t->justify) {
222 case RR_JUSTIFY_LEFT:
223 break;
224 case RR_JUSTIFY_RIGHT:
225 x += (w - mw);
226 break;
227 case RR_JUSTIFY_CENTER:
228 x += (w - mw) / 2;
229 break;
230 }
231
232 if (t->shadow_offset_x || t->shadow_offset_y) {
233 c.color.red = t->shadow_color->r | t->shadow_color->r << 8;
234 c.color.green = t->shadow_color->g | t->shadow_color->g << 8;
235 c.color.blue = t->shadow_color->b | t->shadow_color->b << 8;
236 c.color.alpha = 0xffff * t->shadow_alpha / 255;
237 c.pixel = t->shadow_color->pixel;
238
239 /* see below... */
240 pango_xft_render_layout_line
241 (d, &c, pango_layout_get_line(t->font->layout, 0),
242 (x + t->shadow_offset_x) * PANGO_SCALE,
243 (y + t->shadow_offset_y) * PANGO_SCALE);
244 }
245
246 c.color.red = t->color->r | t->color->r << 8;
247 c.color.green = t->color->g | t->color->g << 8;
248 c.color.blue = t->color->b | t->color->b << 8;
249 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
250 c.pixel = t->color->pixel;
251
252 if (t->shortcut) {
253 const gchar *c = t->string + t->shortcut_pos;
254
255 t->font->shortcut_underline->start_index = t->shortcut_pos;
256 t->font->shortcut_underline->end_index = t->shortcut_pos +
257 (g_utf8_next_char(c) - c);
258
259 /* the attributes are owned by the layout.
260 re-add the attributes to the layout after changing the
261 start and end index */
262 attrlist = pango_layout_get_attributes(t->font->layout);
263 pango_attr_list_ref(attrlist);
264 pango_layout_set_attributes(t->font->layout, attrlist);
265 pango_attr_list_unref(attrlist);
266 }
267
268 /* layout_line() uses y to specify the baseline
269 The line doesn't need to be freed, it's a part of the layout */
270 pango_xft_render_layout_line
271 (d, &c, pango_layout_get_line(t->font->layout, 0),
272 x * PANGO_SCALE, y * PANGO_SCALE);
273
274 if (t->shortcut) {
275 t->font->shortcut_underline->start_index = 0;
276 t->font->shortcut_underline->end_index = 0;
277 /* the attributes are owned by the layout.
278 re-add the attributes to the layout after changing the
279 start and end index */
280 attrlist = pango_layout_get_attributes(t->font->layout);
281 pango_attr_list_ref(attrlist);
282 pango_layout_set_attributes(t->font->layout, attrlist);
283 pango_attr_list_unref(attrlist);
284 }
285 }
This page took 0.051207 seconds and 5 git commands to generate.