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 Ben 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
;
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 @ */
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
);
55 RrFont
*RrFontOpen(const RrInstance
*inst
, gchar
*name
, gint size
,
56 RrFontWeight weight
, RrFontSlant slant
)
62 out
= g_new(RrFont
, 1);
65 out
->font_desc
= pango_font_description_new();
66 out
->layout
= pango_layout_new(inst
->pango
);
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();
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();
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
);
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
);
95 /* get the ascent and descent */
96 measure_font(inst
, out
);
101 RrFont
*RrFontOpenDefault(const RrInstance
*inst
)
103 return RrFontOpen(inst
, RrDefaultFontFamily
, RrDefaultFontSize
,
104 RrDefaultFontWeight
, RrDefaultFontSlant
);
107 void RrFontRef(RrFont
*f
)
112 void RrFontClose(RrFont
*f
)
116 g_object_unref(f
->layout
);
117 pango_font_description_free(f
->font_desc
);
123 static void font_measure_full(const RrFont
*f
, const gchar
*str
,
124 gint
*x
, gint
*y
, gint shadow_x
, gint shadow_y
)
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
);
135 RrSize
*RrFontMeasureString(const RrFont
*f
, const gchar
*str
,
136 gint shadow_x
, gint shadow_y
)
139 size
= g_new(RrSize
, 1);
140 font_measure_full(f
, str
, &size
->width
, &size
->height
, shadow_x
, shadow_y
);
144 gint
RrFontHeight(const RrFont
*f
, gint shadow_y
)
146 return (f
->ascent
+ f
->descent
) / PANGO_SCALE
+ ABS(shadow_y
);
149 static inline int font_calculate_baseline(RrFont
*f
, gint height
)
151 /* For my own reference:
153 * ^space/2 ^height ^baseline
156 * | | | | |_ _____ _| |_ _ _
157 * | | | | _/ -_) \ / _| || |
158 * | v_________v \__\___/_\_\\__|\_, |
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
168 + f
->ascent
) /* now move down to the baseline */
169 / PANGO_SCALE
; /* back to pixels */
172 void RrFontDraw(XftDraw
*d
, RrTextureText
*t
, RrRect
*area
)
179 /* center the text vertically
180 We do this centering based on the 'baseline' since different fonts have
181 different top edges. It looks bad when the whole string is moved when 1
182 character from a non-default language is included in the string */
184 font_calculate_baseline(t
->font
, area
->height
);
186 /* the +2 and -4 leave a small blank edge on the sides */
191 pango_layout_set_text(t
->font
->layout
, t
->string
, -1);
192 pango_layout_set_width(t
->font
->layout
, w
* PANGO_SCALE
);
194 pango_layout_get_pixel_extents(t
->font
->layout
, NULL
, &rect
);
197 /* pango_layout_set_alignment doesn't work with
198 pango_xft_render_layout_line */
199 switch (t
->justify
) {
200 case RR_JUSTIFY_LEFT
:
202 case RR_JUSTIFY_RIGHT
:
205 case RR_JUSTIFY_CENTER
:
210 if (t
->shadow_offset_x
|| t
->shadow_offset_y
) {
211 c
.color
.red
= t
->shadow_color
->r
| t
->shadow_color
->r
<< 8;
212 c
.color
.green
= t
->shadow_color
->g
| t
->shadow_color
->g
<< 8;
213 c
.color
.blue
= t
->shadow_color
->b
| t
->shadow_color
->b
<< 8;
214 c
.color
.alpha
= 0xffff * t
->shadow_alpha
/ 255;
215 c
.pixel
= t
->shadow_color
->pixel
;
217 pango_xft_render_layout_line
218 (d
, &c
, pango_layout_get_line(t
->font
->layout
, 0),
219 (x
+ t
->shadow_offset_x
) * PANGO_SCALE
,
220 (y
+ t
->shadow_offset_y
) * PANGO_SCALE
);
223 c
.color
.red
= t
->color
->r
| t
->color
->r
<< 8;
224 c
.color
.green
= t
->color
->g
| t
->color
->g
<< 8;
225 c
.color
.blue
= t
->color
->b
| t
->color
->b
<< 8;
226 c
.color
.alpha
= 0xff | 0xff << 8; /* fully opaque text */
227 c
.pixel
= t
->color
->pixel
;
229 /* layout_line() uses y to specify the baseline
230 The line doesn't need to be freed, it's a part of the layout */
231 pango_xft_render_layout_line
232 (d
, &c
, pango_layout_get_line(t
->font
->layout
, 0),
233 x
* PANGO_SCALE
, y
* PANGO_SCALE
);