]> Dogcows Code - chaz/openbox/blob - render/font.c
make white font shadows (negative shadowtint) work right.. this has been busted a...
[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
113 /* get the ascent and descent */
114 measure_font(inst, out);
115
116 return out;
117 }
118
119 RrFont *RrFontOpenDefault(const RrInstance *inst)
120 {
121 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
122 RrDefaultFontWeight, RrDefaultFontSlant);
123 }
124
125 void RrFontRef(RrFont *f)
126 {
127 ++f->ref;
128 }
129
130 void RrFontClose(RrFont *f)
131 {
132 if (f) {
133 if (--f->ref < 1) {
134 g_object_unref(f->layout);
135 pango_font_description_free(f->font_desc);
136 g_free(f);
137 }
138 }
139 }
140
141 static void font_measure_full(const RrFont *f, const gchar *str,
142 gint *x, gint *y, gint shadow_x, gint shadow_y)
143 {
144 PangoRectangle rect;
145
146 pango_layout_set_text(f->layout, str, -1);
147 pango_layout_set_width(f->layout, -1);
148
149 /* pango_layout_get_pixel_extents lies! this is the right way to get the
150 size of the text's area */
151 pango_layout_get_extents(f->layout, NULL, &rect);
152 #if PANGO_VERSION_MAJOR > 1 || \
153 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
154 /* pass the logical rect as the ink rect, this is on purpose so we get the
155 full area for the text */
156 pango_extents_to_pixels(&rect, NULL);
157 #else
158 rect.width = (rect.width + PANGO_SCALE - 1) / PANGO_SCALE;
159 rect.height = (rect.height + PANGO_SCALE - 1) / PANGO_SCALE;
160 #endif
161 *x = rect.width + ABS(shadow_x) + 4 /* we put a 2 px edge on each side */;
162 *y = rect.height + ABS(shadow_y);
163 }
164
165 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
166 gint shadow_x, gint shadow_y)
167 {
168 RrSize *size;
169 size = g_new(RrSize, 1);
170 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y);
171 return size;
172 }
173
174 gint RrFontHeight(const RrFont *f, gint shadow_y)
175 {
176 return (f->ascent + f->descent) / PANGO_SCALE + ABS(shadow_y);
177 }
178
179 static inline int font_calculate_baseline(RrFont *f, gint height)
180 {
181 /* For my own reference:
182 * _________
183 * ^space/2 ^height ^baseline
184 * v_________|_ |
185 * | ^ascent | _ _
186 * | | | | |_ _____ _| |_ _ _
187 * | | | | _/ -_) \ / _| || |
188 * | v_________v \__\___/_\_\\__|\_, |
189 * | ^descent |__/
190 * __________|_v
191 * ^space/2 |
192 * V_________v
193 */
194 return (((height * PANGO_SCALE) /* height of the space in pango units */
195 - (f->ascent + f->descent)) /* minus space taken up by text */
196 / 2 /* divided by two -> half of the empty space (this is the top
197 of the text) */
198 + f->ascent) /* now move down to the baseline */
199 / PANGO_SCALE; /* back to pixels */
200 }
201
202 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
203 {
204 gint x,y,w,h;
205 XftColor c;
206 gint mw;
207 PangoRectangle rect;
208 PangoAttrList *attrlist;
209 PangoEllipsizeMode ell;
210
211 /* center the text vertically
212 We do this centering based on the 'baseline' since different fonts have
213 different top edges. It looks bad when the whole string is moved when 1
214 character from a non-default language is included in the string */
215 y = area->y +
216 font_calculate_baseline(t->font, area->height);
217
218 /* the +2 and -4 leave a small blank edge on the sides */
219 x = area->x + 2;
220 w = area->width - 4;
221 h = area->height;
222
223 switch (t->ellipsize) {
224 case RR_ELLIPSIZE_NONE:
225 ell = PANGO_ELLIPSIZE_NONE;
226 break;
227 case RR_ELLIPSIZE_START:
228 ell = PANGO_ELLIPSIZE_START;
229 break;
230 case RR_ELLIPSIZE_MIDDLE:
231 ell = PANGO_ELLIPSIZE_MIDDLE;
232 break;
233 case RR_ELLIPSIZE_END:
234 ell = PANGO_ELLIPSIZE_END;
235 break;
236 }
237
238 pango_layout_set_text(t->font->layout, t->string, -1);
239 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
240 pango_layout_set_ellipsize(t->font->layout, ell);
241
242 /* * * end of setting up the layout * * */
243
244 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
245 mw = rect.width;
246
247 /* pango_layout_set_alignment doesn't work with
248 pango_xft_render_layout_line */
249 switch (t->justify) {
250 case RR_JUSTIFY_LEFT:
251 break;
252 case RR_JUSTIFY_RIGHT:
253 x += (w - mw);
254 break;
255 case RR_JUSTIFY_CENTER:
256 x += (w - mw) / 2;
257 break;
258 }
259
260 if (t->shadow_offset_x || t->shadow_offset_y) {
261 /* From nvidia's readme (chapter 23):
262
263 When rendering to a 32-bit window, keep in mind that the X RENDER
264 extension, used by most composite managers, expects "premultiplied
265 alpha" colors. This means that if your color has components (r,g,b)
266 and alpha value a, then you must render (a*r, a*g, a*b, a) into the
267 target window.
268 */
269 c.color.red = (t->shadow_color->r | t->shadow_color->r << 8) *
270 t->shadow_alpha / 255;
271 c.color.green = (t->shadow_color->g | t->shadow_color->g << 8) *
272 t->shadow_alpha / 255;
273 c.color.blue = (t->shadow_color->b | t->shadow_color->b << 8) *
274 t->shadow_alpha / 255;
275 c.color.alpha = 0xffff * t->shadow_alpha / 255;
276 c.pixel = t->shadow_color->pixel;
277
278 /* see below... */
279 pango_xft_render_layout_line
280 (d, &c, pango_layout_get_line(t->font->layout, 0),
281 (x + t->shadow_offset_x) * PANGO_SCALE,
282 (y + t->shadow_offset_y) * PANGO_SCALE);
283 }
284
285 c.color.red = t->color->r | t->color->r << 8;
286 c.color.green = t->color->g | t->color->g << 8;
287 c.color.blue = t->color->b | t->color->b << 8;
288 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
289 c.pixel = t->color->pixel;
290
291 if (t->shortcut) {
292 const gchar *s = t->string + t->shortcut_pos;
293
294 t->font->shortcut_underline->start_index = t->shortcut_pos;
295 t->font->shortcut_underline->end_index = t->shortcut_pos +
296 (g_utf8_next_char(s) - s);
297
298 /* the attributes are owned by the layout.
299 re-add the attributes to the layout after changing the
300 start and end index */
301 attrlist = pango_layout_get_attributes(t->font->layout);
302 pango_attr_list_ref(attrlist);
303 pango_layout_set_attributes(t->font->layout, attrlist);
304 pango_attr_list_unref(attrlist);
305 }
306
307 /* layout_line() uses y to specify the baseline
308 The line doesn't need to be freed, it's a part of the layout */
309 pango_xft_render_layout_line
310 (d, &c, pango_layout_get_line(t->font->layout, 0),
311 x * PANGO_SCALE, y * PANGO_SCALE);
312
313 if (t->shortcut) {
314 t->font->shortcut_underline->start_index = 0;
315 t->font->shortcut_underline->end_index = 0;
316 /* the attributes are owned by the layout.
317 re-add the attributes to the layout after changing the
318 start and end index */
319 attrlist = pango_layout_get_attributes(t->font->layout);
320 pango_attr_list_ref(attrlist);
321 pango_layout_set_attributes(t->font->layout, attrlist);
322 pango_attr_list_unref(attrlist);
323 }
324 }
This page took 0.048225 seconds and 5 git commands to generate.