1 /* dzl-pango.c
2 *
3 * Copyright (C) 2014-2017 Christian Hergert <christian@hergert.me>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define G_LOG_DOMAIN "dzl-pango"
20
21 #include "config.h"
22
23 #include <gdk/gdk.h>
24 #include <glib/gstdio.h>
25 #define _USE_MATH_DEFINES
26 #include <math.h>
27
28 #include "util/dzl-pango.h"
29
30 #define FONT_FAMILY "font-family"
31 #define FONT_STYLE "font-style"
32 #define FONT_VARIANT "font-variant"
33 #define FONT_STRETCH "font-stretch"
34 #define FONT_WEIGHT "font-weight"
35 #define FONT_SIZE "font-size"
36
37 /**
38 * SECTION:dzl-pango
39 * @title: Pango Utilities
40 * @short_description: Utilities to use with the Pango text layout library
41 */
42
43 /**
44 * dzl_pango_font_description_to_css:
45 *
46 * This function will generate CSS suitable for Gtk's CSS engine
47 * based on the properties of the #PangoFontDescription.
48 *
49 * Returns: (transfer full): A newly allocated string containing the
50 * CSS describing the font description.
51 */
52 gchar *
dzl_pango_font_description_to_css(const PangoFontDescription * font_desc)53 dzl_pango_font_description_to_css (const PangoFontDescription *font_desc)
54 {
55 PangoFontMask mask;
56 GString *str;
57
58 #define ADD_KEYVAL(key,fmt) \
59 g_string_append(str,key":"fmt";")
60 #define ADD_KEYVAL_PRINTF(key,fmt,...) \
61 g_string_append_printf(str,key":"fmt";", __VA_ARGS__)
62
63 g_return_val_if_fail (font_desc, NULL);
64
65 str = g_string_new (NULL);
66
67 mask = pango_font_description_get_set_fields (font_desc);
68
69 if ((mask & PANGO_FONT_MASK_FAMILY) != 0)
70 {
71 const gchar *family;
72
73 family = pango_font_description_get_family (font_desc);
74 ADD_KEYVAL_PRINTF (FONT_FAMILY, "\"%s\"", family);
75 }
76
77 if ((mask & PANGO_FONT_MASK_STYLE) != 0)
78 {
79 PangoStyle style;
80
81 style = pango_font_description_get_style (font_desc);
82
83 switch (style)
84 {
85 case PANGO_STYLE_NORMAL:
86 ADD_KEYVAL (FONT_STYLE, "normal");
87 break;
88
89 case PANGO_STYLE_OBLIQUE:
90 ADD_KEYVAL (FONT_STYLE, "oblique");
91 break;
92
93 case PANGO_STYLE_ITALIC:
94 ADD_KEYVAL (FONT_STYLE, "italic");
95 break;
96
97 default:
98 break;
99 }
100 }
101
102 if ((mask & PANGO_FONT_MASK_VARIANT) != 0)
103 {
104 PangoVariant variant;
105
106 variant = pango_font_description_get_variant (font_desc);
107
108 switch (variant)
109 {
110 case PANGO_VARIANT_NORMAL:
111 ADD_KEYVAL (FONT_VARIANT, "normal");
112 break;
113
114 case PANGO_VARIANT_SMALL_CAPS:
115 ADD_KEYVAL (FONT_VARIANT, "small-caps");
116 break;
117
118 default:
119 break;
120 }
121 }
122
123 if ((mask & PANGO_FONT_MASK_WEIGHT))
124 {
125 gint weight;
126
127 weight = pango_font_description_get_weight (font_desc);
128
129 /*
130 * WORKAROUND:
131 *
132 * font-weight with numbers does not appear to be working as expected
133 * right now. So for the common (bold/normal), let's just use the string
134 * and let gtk warn for the other values, which shouldn't really be
135 * used for this.
136 */
137
138 switch (weight)
139 {
140 case PANGO_WEIGHT_SEMILIGHT:
141 /*
142 * 350 is not actually a valid css font-weight, so we will just round
143 * up to 400.
144 */
145 case PANGO_WEIGHT_NORMAL:
146 ADD_KEYVAL (FONT_WEIGHT, "normal");
147 break;
148
149 case PANGO_WEIGHT_BOLD:
150 ADD_KEYVAL (FONT_WEIGHT, "bold");
151 break;
152
153 case PANGO_WEIGHT_THIN:
154 case PANGO_WEIGHT_ULTRALIGHT:
155 case PANGO_WEIGHT_LIGHT:
156 case PANGO_WEIGHT_BOOK:
157 case PANGO_WEIGHT_MEDIUM:
158 case PANGO_WEIGHT_SEMIBOLD:
159 case PANGO_WEIGHT_ULTRABOLD:
160 case PANGO_WEIGHT_HEAVY:
161 case PANGO_WEIGHT_ULTRAHEAVY:
162 default:
163 /* round to nearest hundred */
164 weight = round (weight / 100.0) * 100;
165 ADD_KEYVAL_PRINTF ("font-weight", "%d", weight);
166 break;
167 }
168 }
169
170 #ifndef GDK_WINDOWING_QUARTZ
171 /*
172 * We seem to get "Condensed" for fonts on the Quartz backend,
173 * which is rather annoying as it results in us always hitting
174 * fallback (stretch) paths. So let's cheat and just disable
175 * stretch support for now on Quartz.
176 */
177 if ((mask & PANGO_FONT_MASK_STRETCH))
178 {
179 switch (pango_font_description_get_stretch (font_desc))
180 {
181 case PANGO_STRETCH_ULTRA_CONDENSED:
182 ADD_KEYVAL (FONT_STRETCH, "ultra-condensed");
183 break;
184
185 case PANGO_STRETCH_EXTRA_CONDENSED:
186 ADD_KEYVAL (FONT_STRETCH, "extra-condensed");
187 break;
188
189 case PANGO_STRETCH_CONDENSED:
190 ADD_KEYVAL (FONT_STRETCH, "condensed");
191 break;
192
193 case PANGO_STRETCH_SEMI_CONDENSED:
194 ADD_KEYVAL (FONT_STRETCH, "semi-condensed");
195 break;
196
197 case PANGO_STRETCH_NORMAL:
198 ADD_KEYVAL (FONT_STRETCH, "normal");
199 break;
200
201 case PANGO_STRETCH_SEMI_EXPANDED:
202 ADD_KEYVAL (FONT_STRETCH, "semi-expanded");
203 break;
204
205 case PANGO_STRETCH_EXPANDED:
206 ADD_KEYVAL (FONT_STRETCH, "expanded");
207 break;
208
209 case PANGO_STRETCH_EXTRA_EXPANDED:
210 ADD_KEYVAL (FONT_STRETCH, "extra-expanded");
211 break;
212
213 case PANGO_STRETCH_ULTRA_EXPANDED:
214 ADD_KEYVAL (FONT_STRETCH, "ultra-expanded");
215 break;
216
217 default:
218 break;
219 }
220 }
221 #endif
222
223 if ((mask & PANGO_FONT_MASK_SIZE))
224 {
225 gint font_size;
226
227 font_size = pango_font_description_get_size (font_desc) / PANGO_SCALE;
228 ADD_KEYVAL_PRINTF ("font-size", "%dpt", font_size);
229 }
230
231 return g_string_free (str, FALSE);
232
233 #undef ADD_KEYVAL
234 #undef ADD_KEYVAL_PRINTF
235 }
236