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_single_paragraph_mode(out
->layout
, TRUE
);
112 pango_layout_set_ellipsize(out
->layout
, PANGO_ELLIPSIZE_MIDDLE
);
114 /* get the ascent and descent */
115 measure_font(inst
, out
);
120 RrFont
*RrFontOpenDefault(const RrInstance
*inst
)
122 return RrFontOpen(inst
, RrDefaultFontFamily
, RrDefaultFontSize
,
123 RrDefaultFontWeight
, RrDefaultFontSlant
);
126 void RrFontRef(RrFont
*f
)
131 void RrFontClose(RrFont
*f
)
135 g_object_unref(f
->layout
);
136 pango_font_description_free(f
->font_desc
);
142 static void font_measure_full(const RrFont
*f
, const gchar
*str
,
143 gint
*x
, gint
*y
, gint shadow_x
, gint shadow_y
)
147 pango_layout_set_text(f
->layout
, str
, -1);
148 pango_layout_set_width(f
->layout
, -1);
149 pango_layout_get_extents(f
->layout
, NULL
, &rect
);
150 /* DONT use pango_layout_get_pixel_extents. they say it's guaranteed to
151 fit the text but they lie. figure it out ourselves */
152 *x
= (rect
.width
+ PANGO_SCALE
- 1) / PANGO_SCALE
153 + ABS(shadow_x
) + 4 /* we put a 2 px edge on each side */;
154 *y
= (rect
.height
+ PANGO_SCALE
- 1) / PANGO_SCALE
+ ABS(shadow_y
);
157 RrSize
*RrFontMeasureString(const RrFont
*f
, const gchar
*str
,
158 gint shadow_x
, gint shadow_y
)
161 size
= g_new(RrSize
, 1);
162 font_measure_full(f
, str
, &size
->width
, &size
->height
, shadow_x
, shadow_y
);
166 gint
RrFontHeight(const RrFont
*f
, gint shadow_y
)
168 return (f
->ascent
+ f
->descent
) / PANGO_SCALE
+ ABS(shadow_y
);
171 static inline int font_calculate_baseline(RrFont
*f
, gint height
)
173 /* For my own reference:
175 * ^space/2 ^height ^baseline
178 * | | | | |_ _____ _| |_ _ _
179 * | | | | _/ -_) \ / _| || |
180 * | v_________v \__\___/_\_\\__|\_, |
186 return (((height
* PANGO_SCALE
) /* height of the space in pango units */
187 - (f
->ascent
+ f
->descent
)) /* minus space taken up by text */
188 / 2 /* divided by two -> half of the empty space (this is the top
190 + f
->ascent
) /* now move down to the baseline */
191 / PANGO_SCALE
; /* back to pixels */
194 void RrFontDraw(XftDraw
*d
, RrTextureText
*t
, RrRect
*area
)
200 PangoAttrList
*attrlist
;
202 /* center the text vertically
203 We do this centering based on the 'baseline' since different fonts have
204 different top edges. It looks bad when the whole string is moved when 1
205 character from a non-default language is included in the string */
207 font_calculate_baseline(t
->font
, area
->height
);
209 /* the +2 and -4 leave a small blank edge on the sides */
214 pango_layout_set_text(t
->font
->layout
, t
->string
, -1);
215 pango_layout_set_width(t
->font
->layout
, w
* PANGO_SCALE
);
217 /* * * end of setting up the layout * * */
219 pango_layout_get_pixel_extents(t
->font
->layout
, NULL
, &rect
);
222 /* pango_layout_set_alignment doesn't work with
223 pango_xft_render_layout_line */
224 switch (t
->justify
) {
225 case RR_JUSTIFY_LEFT
:
227 case RR_JUSTIFY_RIGHT
:
230 case RR_JUSTIFY_CENTER
:
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
;
243 pango_xft_render_layout_line
244 (d
, &c
, pango_layout_get_line(t
->font
->layout
, 0),
245 (x
+ t
->shadow_offset_x
) * PANGO_SCALE
,
246 (y
+ t
->shadow_offset_y
) * PANGO_SCALE
);
249 c
.color
.red
= t
->color
->r
| t
->color
->r
<< 8;
250 c
.color
.green
= t
->color
->g
| t
->color
->g
<< 8;
251 c
.color
.blue
= t
->color
->b
| t
->color
->b
<< 8;
252 c
.color
.alpha
= 0xff | 0xff << 8; /* fully opaque text */
253 c
.pixel
= t
->color
->pixel
;
256 const gchar
*c
= t
->string
+ t
->shortcut_pos
;
258 t
->font
->shortcut_underline
->start_index
= t
->shortcut_pos
;
259 t
->font
->shortcut_underline
->end_index
= t
->shortcut_pos
+
260 (g_utf8_next_char(c
) - c
);
262 /* the attributes are owned by the layout.
263 re-add the attributes to the layout after changing the
264 start and end index */
265 attrlist
= pango_layout_get_attributes(t
->font
->layout
);
266 pango_attr_list_ref(attrlist
);
267 pango_layout_set_attributes(t
->font
->layout
, attrlist
);
268 pango_attr_list_unref(attrlist
);
271 /* layout_line() uses y to specify the baseline
272 The line doesn't need to be freed, it's a part of the layout */
273 pango_xft_render_layout_line
274 (d
, &c
, pango_layout_get_line(t
->font
->layout
, 0),
275 x
* PANGO_SCALE
, y
* PANGO_SCALE
);
278 t
->font
->shortcut_underline
->start_index
= 0;
279 t
->font
->shortcut_underline
->end_index
= 0;
280 /* the attributes are owned by the layout.
281 re-add the attributes to the layout after changing the
282 start and end index */
283 attrlist
= pango_layout_get_attributes(t
->font
->layout
);
284 pango_attr_list_ref(attrlist
);
285 pango_layout_set_attributes(t
->font
->layout
, attrlist
);
286 pango_attr_list_unref(attrlist
);