]> Dogcows Code - chaz/openbox/blob - render/font.c
bd4dcfc23c39074d7ccb3c6d6ca35d14a0ed158a
[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 gchar *locale, *p;
38
39 /* get the default language from the locale
40 (based on gtk_get_default_language in gtkmain.c) */
41 locale = g_strdup(setlocale(LC_CTYPE, NULL));
42 if ((p = strchr(locale, '.'))) *p = '\0'; /* strip off the . */
43 if ((p = strchr(locale, '@'))) *p = '\0'; /* strip off the @ */
44
45 /* measure the ascent and descent */
46 metrics = pango_context_get_metrics(inst->pango, f->font_desc,
47 pango_language_from_string(locale));
48 f->ascent = pango_font_metrics_get_ascent(metrics);
49 f->descent = pango_font_metrics_get_descent(metrics);
50 pango_font_metrics_unref(metrics);
51
52 g_free(locale);
53 }
54
55 RrFont *RrFontOpen(const RrInstance *inst, const gchar *name, gint size,
56 RrFontWeight weight, RrFontSlant slant)
57 {
58 RrFont *out;
59 PangoWeight pweight;
60 PangoStyle pstyle;
61
62 out = g_new(RrFont, 1);
63 out->inst = inst;
64 out->ref = 1;
65 out->font_desc = pango_font_description_new();
66 out->layout = pango_layout_new(inst->pango);
67
68 switch (weight) {
69 case RR_FONTWEIGHT_LIGHT: pweight = PANGO_WEIGHT_LIGHT; break;
70 case RR_FONTWEIGHT_NORMAL: pweight = PANGO_WEIGHT_NORMAL; break;
71 case RR_FONTWEIGHT_SEMIBOLD: pweight = PANGO_WEIGHT_SEMIBOLD; break;
72 case RR_FONTWEIGHT_BOLD: pweight = PANGO_WEIGHT_BOLD; break;
73 case RR_FONTWEIGHT_ULTRABOLD: pweight = PANGO_WEIGHT_ULTRABOLD; break;
74 default: g_assert_not_reached();
75 }
76
77 switch (slant) {
78 case RR_FONTSLANT_NORMAL: pstyle = PANGO_STYLE_NORMAL; break;
79 case RR_FONTSLANT_ITALIC: pstyle = PANGO_STYLE_ITALIC; break;
80 case RR_FONTSLANT_OBLIQUE: pstyle = PANGO_STYLE_OBLIQUE; break;
81 default: g_assert_not_reached();
82 }
83
84 /* setup the font */
85 pango_font_description_set_family(out->font_desc, name);
86 pango_font_description_set_weight(out->font_desc, pweight);
87 pango_font_description_set_style(out->font_desc, pstyle);
88 pango_font_description_set_size(out->font_desc, size * PANGO_SCALE);
89
90 /* setup the layout */
91 pango_layout_set_font_description(out->layout, out->font_desc);
92 pango_layout_set_single_paragraph_mode(out->layout, TRUE);
93 pango_layout_set_ellipsize(out->layout, PANGO_ELLIPSIZE_MIDDLE);
94
95 /* get the ascent and descent */
96 measure_font(inst, out);
97
98 return out;
99 }
100
101 RrFont *RrFontOpenDefault(const RrInstance *inst)
102 {
103 return RrFontOpen(inst, RrDefaultFontFamily, RrDefaultFontSize,
104 RrDefaultFontWeight, RrDefaultFontSlant);
105 }
106
107 void RrFontRef(RrFont *f)
108 {
109 ++f->ref;
110 }
111
112 void RrFontClose(RrFont *f)
113 {
114 if (f) {
115 if (--f->ref < 1) {
116 g_object_unref(f->layout);
117 pango_font_description_free(f->font_desc);
118 g_free(f);
119 }
120 }
121 }
122
123 static void font_measure_full(const RrFont *f, const gchar *str,
124 gint *x, gint *y, gint shadow_x, gint shadow_y)
125 {
126 PangoRectangle rect;
127
128 pango_layout_set_text(f->layout, str, -1);
129 pango_layout_set_width(f->layout, -1);
130 pango_layout_get_pixel_extents(f->layout, NULL, &rect);
131 *x = rect.width + ABS(shadow_x);
132 *y = rect.height + ABS(shadow_y);
133 }
134
135 RrSize *RrFontMeasureString(const RrFont *f, const gchar *str,
136 gint shadow_x, gint shadow_y)
137 {
138 RrSize *size;
139 size = g_new(RrSize, 1);
140 font_measure_full(f, str, &size->width, &size->height, shadow_x, shadow_y);
141 return size;
142 }
143
144 gint RrFontHeight(const RrFont *f, gint shadow_y)
145 {
146 return (f->ascent + f->descent) / PANGO_SCALE + ABS(shadow_y);
147 }
148
149 static inline int font_calculate_baseline(RrFont *f, gint height)
150 {
151 /* For my own reference:
152 * _________
153 * ^space/2 ^height ^baseline
154 * v_________|_ |
155 * | ^ascent | _ _
156 * | | | | |_ _____ _| |_ _ _
157 * | | | | _/ -_) \ / _| || |
158 * | v_________v \__\___/_\_\\__|\_, |
159 * | ^descent |__/
160 * __________|_v
161 * ^space/2 |
162 * V_________v
163 */
164 return (((height * PANGO_SCALE) /* height of the space in pango units */
165 - (f->ascent + f->descent)) /* minus space taken up by text */
166 / 2 /* divided by two -> half of the empty space (this is the top
167 of the text) */
168 + f->ascent) /* now move down to the baseline */
169 / PANGO_SCALE; /* back to pixels */
170 }
171
172 void RrFontDraw(XftDraw *d, RrTextureText *t, RrRect *area)
173 {
174 gint x,y,w,h;
175 XftColor c;
176 gint mw;
177 PangoRectangle rect;
178 PangoAttrList* attrs = NULL;
179
180 /* center the text vertically
181 We do this centering based on the 'baseline' since different fonts have
182 different top edges. It looks bad when the whole string is moved when 1
183 character from a non-default language is included in the string */
184 y = area->y +
185 font_calculate_baseline(t->font, area->height);
186
187 /* the +2 and -4 leave a small blank edge on the sides */
188 x = area->x + 2;
189 w = area->width - 4;
190 h = area->height;
191
192 /* * * set up the layout * * */
193
194 if (t->shortcut) {
195 gchar *i;
196 gchar *lowertext;
197
198 lowertext = g_utf8_strdown(t->string, -1);
199 i = g_utf8_strchr(lowertext, -1, t->shortcut);
200 if (i != NULL) {
201 PangoAttribute *a;
202
203 a = pango_attr_underline_new(PANGO_UNDERLINE_LOW);
204 a->start_index = i - lowertext;
205 a->end_index = i - lowertext +
206 g_unichar_to_utf8(t->shortcut, NULL);
207
208 attrs = pango_attr_list_new();
209 pango_attr_list_insert(attrs, a);
210 }
211 g_free(lowertext);
212 }
213
214 pango_layout_set_text(t->font->layout, t->string, -1);
215 pango_layout_set_width(t->font->layout, w * PANGO_SCALE);
216
217 /* * * end of setting up the layout * * */
218
219 pango_layout_get_pixel_extents(t->font->layout, NULL, &rect);
220 mw = rect.width;
221
222 /* pango_layout_set_alignment doesn't work with
223 pango_xft_render_layout_line */
224 switch (t->justify) {
225 case RR_JUSTIFY_LEFT:
226 break;
227 case RR_JUSTIFY_RIGHT:
228 x += (w - mw);
229 break;
230 case RR_JUSTIFY_CENTER:
231 x += (w - mw) / 2;
232 break;
233 }
234
235 if (t->shadow_offset_x || t->shadow_offset_y) {
236 c.color.red = t->shadow_color->r | t->shadow_color->r << 8;
237 c.color.green = t->shadow_color->g | t->shadow_color->g << 8;
238 c.color.blue = t->shadow_color->b | t->shadow_color->b << 8;
239 c.color.alpha = 0xffff * t->shadow_alpha / 255;
240 c.pixel = t->shadow_color->pixel;
241
242 pango_layout_set_attributes(t->font->layout, NULL);
243
244 /* see below... */
245 pango_xft_render_layout_line
246 (d, &c, pango_layout_get_line(t->font->layout, 0),
247 (x + t->shadow_offset_x) * PANGO_SCALE,
248 (y + t->shadow_offset_y) * PANGO_SCALE);
249 }
250
251 c.color.red = t->color->r | t->color->r << 8;
252 c.color.green = t->color->g | t->color->g << 8;
253 c.color.blue = t->color->b | t->color->b << 8;
254 c.color.alpha = 0xff | 0xff << 8; /* fully opaque text */
255 c.pixel = t->color->pixel;
256
257 pango_layout_set_attributes(t->font->layout, attrs);
258 if (attrs != NULL) pango_attr_list_unref(attrs);
259
260 /* layout_line() uses y to specify the baseline
261 The line doesn't need to be freed, it's a part of the layout */
262 pango_xft_render_layout_line
263 (d, &c, pango_layout_get_line(t->font->layout, 0),
264 x * PANGO_SCALE, y * PANGO_SCALE);
265 }
This page took 0.049066 seconds and 3 git commands to generate.