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_slice_new(RrFont
);
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_wrap(out
->layout
, PANGO_WRAP_WORD_CHAR
);
113 /* get the ascent and descent */
114 measure_font(inst
, out
);
119 RrFont
*RrFontOpenDefault(const RrInstance
*inst
)
121 return RrFontOpen(inst
, RrDefaultFontFamily
, RrDefaultFontSize
,
122 RrDefaultFontWeight
, RrDefaultFontSlant
);
125 void RrFontRef(RrFont
*f
)
130 void RrFontClose(RrFont
*f
)
134 g_object_unref(f
->layout
);
135 pango_font_description_free(f
->font_desc
);
136 g_slice_free(RrFont
, f
);
141 static void font_measure_full(const RrFont
*f
, const gchar
*str
,
142 gint
*x
, gint
*y
, gint shadow_x
, gint shadow_y
,
143 gboolean flow
, gint maxwidth
)
147 pango_layout_set_text(f
->layout
, str
, -1);
149 pango_layout_set_single_paragraph_mode(f
->layout
, FALSE
);
150 pango_layout_set_width(f
->layout
, maxwidth
* PANGO_SCALE
);
151 pango_layout_set_ellipsize(f
->layout
, PANGO_ELLIPSIZE_NONE
);
154 /* single line mode */
155 pango_layout_set_single_paragraph_mode(f
->layout
, TRUE
);
156 pango_layout_set_width(f
->layout
, -1);
157 pango_layout_set_ellipsize(f
->layout
, PANGO_ELLIPSIZE_MIDDLE
);
160 /* pango_layout_get_pixel_extents lies! this is the right way to get the
161 size of the text's area */
162 pango_layout_get_extents(f
->layout
, NULL
, &rect
);
163 #if PANGO_VERSION_MAJOR > 1 || \
164 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
165 /* pass the logical rect as the ink rect, this is on purpose so we get the
166 full area for the text */
167 pango_extents_to_pixels(&rect
, NULL
);
169 rect
.width
= (rect
.width
+ PANGO_SCALE
- 1) / PANGO_SCALE
;
170 rect
.height
= (rect
.height
+ PANGO_SCALE
- 1) / PANGO_SCALE
;
172 *x
= rect
.width
+ ABS(shadow_x
) + 4 /* we put a 2 px edge on each side */;
173 *y
= rect
.height
+ ABS(shadow_y
);
176 RrSize
*RrFontMeasureString(const RrFont
*f
, const gchar
*str
,
177 gint shadow_x
, gint shadow_y
,
178 gboolean flow
, gint maxwidth
)
182 g_assert(!flow
|| maxwidth
> 0);
184 size
= g_slice_new(RrSize
);
185 font_measure_full(f
, str
, &size
->width
, &size
->height
, shadow_x
, shadow_y
,
190 gint
RrFontHeight(const RrFont
*f
, gint shadow_y
)
192 return (f
->ascent
+ f
->descent
) / PANGO_SCALE
+ ABS(shadow_y
);
195 static inline int font_calculate_baseline(RrFont
*f
, gint height
)
197 /* For my own reference:
199 * ^space/2 ^height ^baseline
202 * | | | | |_ _____ _| |_ _ _
203 * | | | | _/ -_) \ / _| || |
204 * | v_________v \__\___/_\_\\__|\_, |
210 return (((height
* PANGO_SCALE
) /* height of the space in pango units */
211 - (f
->ascent
+ f
->descent
)) /* minus space taken up by text */
212 / 2 /* divided by two -> half of the empty space (this is the top
214 + f
->ascent
) /* now move down to the baseline */
215 / PANGO_SCALE
; /* back to pixels */
218 void RrFontDraw(XftDraw
*d
, RrTextureText
*t
, RrRect
*area
)
224 PangoAttrList
*attrlist
;
225 PangoEllipsizeMode ell
;
227 g_assert(!t
->flow
|| t
->maxwidth
> 0);
231 /* center the text vertically
232 We do this centering based on the 'baseline' since different fonts
233 have different top edges. It looks bad when the whole string is
234 moved when 1 character from a non-default language is included in
236 y
+= font_calculate_baseline(t
->font
, area
->height
);
238 /* the +2 and -4 leave a small blank edge on the sides */
241 if (t
->flow
) w
= MAX(w
, t
->maxwidth
);
243 /* h = area->height; */
246 ell
= PANGO_ELLIPSIZE_NONE
;
248 switch (t
->ellipsize
) {
249 case RR_ELLIPSIZE_NONE
:
250 ell
= PANGO_ELLIPSIZE_NONE
;
252 case RR_ELLIPSIZE_START
:
253 ell
= PANGO_ELLIPSIZE_START
;
255 case RR_ELLIPSIZE_MIDDLE
:
256 ell
= PANGO_ELLIPSIZE_MIDDLE
;
258 case RR_ELLIPSIZE_END
:
259 ell
= PANGO_ELLIPSIZE_END
;
262 g_assert_not_reached();
266 pango_layout_set_text(t
->font
->layout
, t
->string
, -1);
267 pango_layout_set_width(t
->font
->layout
, w
* PANGO_SCALE
);
268 pango_layout_set_ellipsize(t
->font
->layout
, ell
);
269 pango_layout_set_single_paragraph_mode(t
->font
->layout
, !t
->flow
);
271 /* * * end of setting up the layout * * */
273 pango_layout_get_pixel_extents(t
->font
->layout
, NULL
, &rect
);
276 /* pango_layout_set_alignment doesn't work with
277 pango_xft_render_layout_line */
278 switch (t
->justify
) {
279 case RR_JUSTIFY_LEFT
:
281 case RR_JUSTIFY_RIGHT
:
284 case RR_JUSTIFY_CENTER
:
287 case RR_JUSTIFY_NUM_TYPES
:
288 g_assert_not_reached();
291 if (t
->shadow_offset_x
|| t
->shadow_offset_y
) {
292 /* From nvidia's readme (chapter 23):
294 When rendering to a 32-bit window, keep in mind that the X RENDER
295 extension, used by most composite managers, expects "premultiplied
296 alpha" colors. This means that if your color has components (r,g,b)
297 and alpha value a, then you must render (a*r, a*g, a*b, a) into the
300 c
.color
.red
= (t
->shadow_color
->r
| t
->shadow_color
->r
<< 8) *
301 t
->shadow_alpha
/ 255;
302 c
.color
.green
= (t
->shadow_color
->g
| t
->shadow_color
->g
<< 8) *
303 t
->shadow_alpha
/ 255;
304 c
.color
.blue
= (t
->shadow_color
->b
| t
->shadow_color
->b
<< 8) *
305 t
->shadow_alpha
/ 255;
306 c
.color
.alpha
= 0xffff * t
->shadow_alpha
/ 255;
307 c
.pixel
= t
->shadow_color
->pixel
;
311 pango_xft_render_layout_line
313 #if PANGO_VERSION_MAJOR > 1 || \
314 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
315 pango_layout_get_line_readonly(t
->font
->layout
, 0),
317 pango_layout_get_line(t
->font
->layout
, 0),
319 (x
+ t
->shadow_offset_x
) * PANGO_SCALE
,
320 (y
+ t
->shadow_offset_y
) * PANGO_SCALE
);
323 pango_xft_render_layout(d
, &c
, t
->font
->layout
,
324 (x
+ t
->shadow_offset_x
) * PANGO_SCALE
,
325 (y
+ t
->shadow_offset_y
) * PANGO_SCALE
);
329 c
.color
.red
= t
->color
->r
| t
->color
->r
<< 8;
330 c
.color
.green
= t
->color
->g
| t
->color
->g
<< 8;
331 c
.color
.blue
= t
->color
->b
| t
->color
->b
<< 8;
332 c
.color
.alpha
= 0xff | 0xff << 8; /* fully opaque text */
333 c
.pixel
= t
->color
->pixel
;
336 const gchar
*s
= t
->string
+ t
->shortcut_pos
;
338 t
->font
->shortcut_underline
->start_index
= t
->shortcut_pos
;
339 t
->font
->shortcut_underline
->end_index
= t
->shortcut_pos
+
340 (g_utf8_next_char(s
) - s
);
342 /* the attributes are owned by the layout.
343 re-add the attributes to the layout after changing the
344 start and end index */
345 attrlist
= pango_layout_get_attributes(t
->font
->layout
);
346 pango_attr_list_ref(attrlist
);
347 pango_layout_set_attributes(t
->font
->layout
, attrlist
);
348 pango_attr_list_unref(attrlist
);
351 /* layout_line() uses y to specify the baseline
352 The line doesn't need to be freed, it's a part of the layout */
354 pango_xft_render_layout_line
356 #if PANGO_VERSION_MAJOR > 1 || \
357 (PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR >= 16)
358 pango_layout_get_line_readonly(t
->font
->layout
, 0),
360 pango_layout_get_line(t
->font
->layout
, 0),
366 pango_xft_render_layout(d
, &c
, t
->font
->layout
,
372 t
->font
->shortcut_underline
->start_index
= 0;
373 t
->font
->shortcut_underline
->end_index
= 0;
374 /* the attributes are owned by the layout.
375 re-add the attributes to the layout after changing the
376 start and end index */
377 attrlist
= pango_layout_get_attributes(t
->font
->layout
);
378 pango_attr_list_ref(attrlist
);
379 pango_layout_set_attributes(t
->font
->layout
, attrlist
);
380 pango_attr_list_unref(attrlist
);