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
;
38 /* measure the ascent and descent */
39 metrics
= pango_context_get_metrics(inst
->pango
, f
->font_desc
,
40 pango_language_get_default());
41 f
->ascent
= pango_font_metrics_get_ascent(metrics
);
42 f
->descent
= pango_font_metrics_get_descent(metrics
);
43 pango_font_metrics_unref(metrics
);
46 RrFont
*RrFontOpen(const RrInstance
*inst
, const gchar
*name
, gint size
,
47 RrFontWeight weight
, RrFontSlant slant
)
52 PangoAttrList
*attrlist
;
54 out
= g_new(RrFont
, 1);
57 out
->font_desc
= pango_font_description_new();
58 out
->layout
= pango_layout_new(inst
->pango
);
59 out
->shortcut_underline
= pango_attr_underline_new(PANGO_UNDERLINE_LOW
);
60 out
->shortcut_underline
->start_index
= 0;
61 out
->shortcut_underline
->end_index
= 0;
63 attrlist
= pango_attr_list_new();
64 /* shortcut_underline is owned by the attrlist */
65 pango_attr_list_insert(attrlist
, out
->shortcut_underline
);
66 /* the attributes are owned by the layout */
67 pango_layout_set_attributes(out
->layout
, attrlist
);
68 pango_attr_list_unref(attrlist
);
71 case RR_FONTWEIGHT_LIGHT
: pweight
= PANGO_WEIGHT_LIGHT
; break;
72 case RR_FONTWEIGHT_NORMAL
: pweight
= PANGO_WEIGHT_NORMAL
; break;
73 case RR_FONTWEIGHT_SEMIBOLD
: pweight
= PANGO_WEIGHT_SEMIBOLD
; break;
74 case RR_FONTWEIGHT_BOLD
: pweight
= PANGO_WEIGHT_BOLD
; break;
75 case RR_FONTWEIGHT_ULTRABOLD
: pweight
= PANGO_WEIGHT_ULTRABOLD
; break;
76 default: g_assert_not_reached();
80 case RR_FONTSLANT_NORMAL
: pstyle
= PANGO_STYLE_NORMAL
; break;
81 case RR_FONTSLANT_ITALIC
: pstyle
= PANGO_STYLE_ITALIC
; break;
82 case RR_FONTSLANT_OBLIQUE
: pstyle
= PANGO_STYLE_OBLIQUE
; break;
83 default: g_assert_not_reached();
87 pango_font_description_set_family(out
->font_desc
, name
);
88 pango_font_description_set_weight(out
->font_desc
, pweight
);
89 pango_font_description_set_style(out
->font_desc
, pstyle
);
90 pango_font_description_set_size(out
->font_desc
, size
* PANGO_SCALE
);
92 /* setup the layout */
93 pango_layout_set_font_description(out
->layout
, out
->font_desc
);
94 pango_layout_set_single_paragraph_mode(out
->layout
, TRUE
);
95 pango_layout_set_ellipsize(out
->layout
, PANGO_ELLIPSIZE_MIDDLE
);
97 /* get the ascent and descent */
98 measure_font(inst
, out
);
103 RrFont
*RrFontOpenDefault(const RrInstance
*inst
)
105 return RrFontOpen(inst
, RrDefaultFontFamily
, RrDefaultFontSize
,
106 RrDefaultFontWeight
, RrDefaultFontSlant
);
109 void RrFontRef(RrFont
*f
)
114 void RrFontClose(RrFont
*f
)
118 g_object_unref(f
->layout
);
119 pango_font_description_free(f
->font_desc
);
125 static void font_measure_full(const RrFont
*f
, const gchar
*str
,
126 gint
*x
, gint
*y
, gint shadow_x
, gint shadow_y
)
130 pango_layout_set_text(f
->layout
, str
, -1);
131 pango_layout_set_width(f
->layout
, -1);
132 pango_layout_get_pixel_extents(f
->layout
, NULL
, &rect
);
133 *x
= rect
.width
+ ABS(shadow_x
) + 4 /* we put a 2 px edge on each side */;
134 *y
= rect
.height
+ ABS(shadow_y
);
137 RrSize
*RrFontMeasureString(const RrFont
*f
, const gchar
*str
,
138 gint shadow_x
, gint shadow_y
)
141 size
= g_new(RrSize
, 1);
142 font_measure_full(f
, str
, &size
->width
, &size
->height
, shadow_x
, shadow_y
);
146 gint
RrFontHeight(const RrFont
*f
, gint shadow_y
)
148 return (f
->ascent
+ f
->descent
) / PANGO_SCALE
+ ABS(shadow_y
);
151 static inline int font_calculate_baseline(RrFont
*f
, gint height
)
153 /* For my own reference:
155 * ^space/2 ^height ^baseline
158 * | | | | |_ _____ _| |_ _ _
159 * | | | | _/ -_) \ / _| || |
160 * | v_________v \__\___/_\_\\__|\_, |
166 return (((height
* PANGO_SCALE
) /* height of the space in pango units */
167 - (f
->ascent
+ f
->descent
)) /* minus space taken up by text */
168 / 2 /* divided by two -> half of the empty space (this is the top
170 + f
->ascent
) /* now move down to the baseline */
171 / PANGO_SCALE
; /* back to pixels */
174 void RrFontDraw(XftDraw
*d
, RrTextureText
*t
, RrRect
*area
)
180 PangoAttrList
*attrlist
;
182 /* center the text vertically
183 We do this centering based on the 'baseline' since different fonts have
184 different top edges. It looks bad when the whole string is moved when 1
185 character from a non-default language is included in the string */
187 font_calculate_baseline(t
->font
, area
->height
);
189 /* the +2 and -4 leave a small blank edge on the sides */
194 pango_layout_set_text(t
->font
->layout
, t
->string
, -1);
195 pango_layout_set_width(t
->font
->layout
, w
* PANGO_SCALE
);
197 /* * * end of setting up the layout * * */
199 pango_layout_get_pixel_extents(t
->font
->layout
, NULL
, &rect
);
202 /* pango_layout_set_alignment doesn't work with
203 pango_xft_render_layout_line */
204 switch (t
->justify
) {
205 case RR_JUSTIFY_LEFT
:
207 case RR_JUSTIFY_RIGHT
:
210 case RR_JUSTIFY_CENTER
:
215 if (t
->shadow_offset_x
|| t
->shadow_offset_y
) {
216 c
.color
.red
= t
->shadow_color
->r
| t
->shadow_color
->r
<< 8;
217 c
.color
.green
= t
->shadow_color
->g
| t
->shadow_color
->g
<< 8;
218 c
.color
.blue
= t
->shadow_color
->b
| t
->shadow_color
->b
<< 8;
219 c
.color
.alpha
= 0xffff * t
->shadow_alpha
/ 255;
220 c
.pixel
= t
->shadow_color
->pixel
;
223 pango_xft_render_layout_line
224 (d
, &c
, pango_layout_get_line(t
->font
->layout
, 0),
225 (x
+ t
->shadow_offset_x
) * PANGO_SCALE
,
226 (y
+ t
->shadow_offset_y
) * PANGO_SCALE
);
229 c
.color
.red
= t
->color
->r
| t
->color
->r
<< 8;
230 c
.color
.green
= t
->color
->g
| t
->color
->g
<< 8;
231 c
.color
.blue
= t
->color
->b
| t
->color
->b
<< 8;
232 c
.color
.alpha
= 0xff | 0xff << 8; /* fully opaque text */
233 c
.pixel
= t
->color
->pixel
;
236 const gchar
*c
= t
->string
+ t
->shortcut_pos
;
238 t
->font
->shortcut_underline
->start_index
= t
->shortcut_pos
;
239 t
->font
->shortcut_underline
->end_index
= t
->shortcut_pos
+
240 (g_utf8_next_char(c
) - c
);
242 /* the attributes are owned by the layout.
243 re-add the attributes to the layout after changing the
244 start and end index */
245 attrlist
= pango_layout_get_attributes(t
->font
->layout
);
246 pango_attr_list_ref(attrlist
);
247 pango_layout_set_attributes(t
->font
->layout
, attrlist
);
248 pango_attr_list_unref(attrlist
);
251 /* layout_line() uses y to specify the baseline
252 The line doesn't need to be freed, it's a part of the layout */
253 pango_xft_render_layout_line
254 (d
, &c
, pango_layout_get_line(t
->font
->layout
, 0),
255 x
* PANGO_SCALE
, y
* PANGO_SCALE
);
258 t
->font
->shortcut_underline
->start_index
= 0;
259 t
->font
->shortcut_underline
->end_index
= 0;
260 /* the attributes are owned by the layout.
261 re-add the attributes to the layout after changing the
262 start and end index */
263 attrlist
= pango_layout_get_attributes(t
->font
->layout
);
264 pango_attr_list_ref(attrlist
);
265 pango_layout_set_attributes(t
->font
->layout
, attrlist
);
266 pango_attr_list_unref(attrlist
);