1 | /* pango-list.c: List all fonts |
2 | * |
3 | * Copyright (C) 2018 Google |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library 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 GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public |
16 | * License along with this library; if not, write to the |
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | * Boston, MA 02111-1307, USA. |
19 | * |
20 | * Google Author(s): Behdad Esfahbod |
21 | */ |
22 | |
23 | #include "config.h" |
24 | #include <pango/pangocairo.h> |
25 | #include <hb-ot.h> |
26 | #include <glib/gstdio.h> |
27 | #include <stdlib.h> |
28 | #include <locale.h> |
29 | |
30 | /* FIXME: This doesn't work if the font has an avar table */ |
31 | static float |
32 | denorm_coord (hb_ot_var_axis_info_t *axis, int coord) |
33 | { |
34 | float r = coord / 16384.0; |
35 | |
36 | if (coord < 0) |
37 | return axis->default_value + r * (axis->default_value - axis->min_value); |
38 | else |
39 | return axis->default_value + r * (axis->max_value - axis->default_value); |
40 | } |
41 | |
42 | int |
43 | main (int argc, |
44 | char **argv) |
45 | { |
46 | gboolean opt_verbose = FALSE; |
47 | gboolean opt_metrics = FALSE; |
48 | gboolean opt_variations = FALSE; |
49 | gboolean opt_version = FALSE; |
50 | GOptionEntry entries[] = { |
51 | { "verbose" , 0, 0, G_OPTION_ARG_NONE, &opt_verbose, "Print verbose information" , NULL }, |
52 | { "metrics" , 0, 0, G_OPTION_ARG_NONE, &opt_metrics, "Print font metrics" , NULL }, |
53 | { "variations" , 0, 0, G_OPTION_ARG_NONE, &opt_variations, "Print font variations" , NULL }, |
54 | { "version" , 0, 0, G_OPTION_ARG_NONE, &opt_version, "Show version" }, |
55 | { NULL, } |
56 | }; |
57 | GOptionContext *context; |
58 | PangoContext *ctx; |
59 | PangoFontMap *fontmap; |
60 | PangoFontFamily **families; |
61 | int n_families; |
62 | int i, j; |
63 | int width; |
64 | GError *error = NULL; |
65 | |
66 | g_set_prgname (prgname: "pango-list" ); |
67 | setlocale (LC_ALL, locale: "" ); |
68 | |
69 | context = g_option_context_new (parameter_string: "" ); |
70 | g_option_context_add_main_entries (context, entries, NULL); |
71 | if (!g_option_context_parse (context, argc: &argc, argv: &argv, error: &error)) |
72 | { |
73 | if (error != NULL) |
74 | g_printerr (format: "%s\n" , error->message); |
75 | else |
76 | g_printerr (format: "Option parse error\n" ); |
77 | exit (status: 1); |
78 | } |
79 | |
80 | g_option_context_free (context); |
81 | |
82 | if (opt_version) |
83 | { |
84 | g_print (format: "%s (%s) %s\n" , g_get_prgname (), PACKAGE_NAME, PACKAGE_VERSION); |
85 | exit (status: 0); |
86 | } |
87 | |
88 | /* Use PangoCairo to get default fontmap so it works on every platform. */ |
89 | fontmap = pango_cairo_font_map_get_default (); |
90 | ctx = pango_font_map_create_context (fontmap); |
91 | |
92 | if (opt_verbose) |
93 | g_print (format: "Using %s\n\n" , G_OBJECT_TYPE_NAME (fontmap)); |
94 | |
95 | pango_font_map_list_families (fontmap, families: &families, n_families: &n_families); |
96 | for (i = 0; i < n_families; i++) |
97 | { |
98 | PangoFontFace **faces; |
99 | int n_faces; |
100 | const char *kind; |
101 | |
102 | const char *family_name = pango_font_family_get_name (family: families[i]); |
103 | if (pango_font_family_is_monospace (family: families[i])) |
104 | { |
105 | if (pango_font_family_is_variable (family: families[i])) |
106 | kind = "(monospace, variable)" ; |
107 | else |
108 | kind = "(monospace)" ; |
109 | } |
110 | else |
111 | { |
112 | if (pango_font_family_is_variable (family: families[i])) |
113 | kind = "(variable)" ; |
114 | else |
115 | kind = "" ; |
116 | } |
117 | |
118 | g_print (format: "%s %s\n" , family_name, kind); |
119 | |
120 | pango_font_family_list_faces (family: families[i], faces: &faces, n_faces: &n_faces); |
121 | |
122 | width = 0; |
123 | for (j = 0; j < n_faces; j++) |
124 | { |
125 | const char *face_name = pango_font_face_get_face_name (face: faces[j]); |
126 | gboolean is_synth = pango_font_face_is_synthesized (face: faces[j]); |
127 | const char *synth_str = is_synth ? "*" : "" ; |
128 | width = MAX (width, strlen (synth_str) + strlen (face_name)); |
129 | } |
130 | |
131 | for (j = 0; j < n_faces; j++) |
132 | { |
133 | const char *face_name = pango_font_face_get_face_name (face: faces[j]); |
134 | gboolean is_synth = pango_font_face_is_synthesized (face: faces[j]); |
135 | const char *synth_str = is_synth ? "*" : "" ; |
136 | PangoFontDescription *desc = pango_font_face_describe (face: faces[j]); |
137 | char *desc_str = pango_font_description_to_string (desc); |
138 | |
139 | g_print (format: " %s%s: %*s%s\n" , synth_str, face_name, |
140 | width - (int)strlen (s: face_name) - (int)strlen (s: synth_str), "" , desc_str); |
141 | |
142 | if (opt_metrics) |
143 | { |
144 | PangoFontMetrics *metrics; |
145 | |
146 | pango_font_description_set_absolute_size (desc, size: 10 * PANGO_SCALE); |
147 | metrics = pango_context_get_metrics (context: ctx, desc, language: pango_language_from_string (language: "en-us" )); |
148 | g_print (format: " (a %d d %d h %d cw %d dw %d u %d %d s %d %d)\n" , |
149 | pango_font_metrics_get_ascent (metrics), |
150 | pango_font_metrics_get_descent (metrics), |
151 | pango_font_metrics_get_height (metrics), |
152 | pango_font_metrics_get_approximate_char_width (metrics), |
153 | pango_font_metrics_get_approximate_digit_width (metrics), |
154 | pango_font_metrics_get_underline_position (metrics), |
155 | pango_font_metrics_get_underline_thickness (metrics), |
156 | pango_font_metrics_get_strikethrough_position (metrics), |
157 | pango_font_metrics_get_strikethrough_thickness (metrics)); |
158 | pango_font_metrics_unref (metrics); |
159 | } |
160 | |
161 | if (opt_variations && |
162 | pango_font_family_is_variable (family: families[i])) |
163 | { |
164 | PangoFont *font; |
165 | hb_font_t *hb_font; |
166 | const int *coords; |
167 | unsigned int length; |
168 | |
169 | pango_font_description_set_absolute_size (desc, size: 10 * PANGO_SCALE); |
170 | |
171 | font = pango_context_load_font (context: ctx, desc); |
172 | hb_font = pango_font_get_hb_font (font); |
173 | coords = hb_font_get_var_coords_normalized (font: hb_font, length: &length); |
174 | if (coords) |
175 | { |
176 | hb_face_t *hb_face = hb_font_get_face (font: hb_font); |
177 | hb_ot_var_axis_info_t *axes; |
178 | unsigned int n_axes; |
179 | int i; |
180 | |
181 | axes = g_new (hb_ot_var_axis_info_t, length); |
182 | n_axes = length; |
183 | |
184 | hb_ot_var_get_axis_infos (face: hb_face, start_offset: 0, axes_count: &n_axes, axes_array: axes); |
185 | |
186 | for (i = 0; i < length; i++) |
187 | { |
188 | char name[20]; |
189 | unsigned int namelen = 20; |
190 | |
191 | hb_ot_name_get_utf8 (face: hb_face, name_id: axes[i].name_id, HB_LANGUAGE_INVALID, text_size: &namelen, text: name); |
192 | |
193 | g_print (format: " %s: %g (%g - %g, %g)\n" , |
194 | name, |
195 | denorm_coord (axis: &axes[i], coord: coords[i]), |
196 | axes[i].min_value, |
197 | axes[i].max_value, |
198 | axes[i].default_value); |
199 | } |
200 | g_free (mem: axes); |
201 | } |
202 | } |
203 | |
204 | g_free (mem: desc_str); |
205 | pango_font_description_free (desc); |
206 | } |
207 | |
208 | g_free (mem: faces); |
209 | } |
210 | g_free (mem: families); |
211 | g_object_unref (object: ctx); |
212 | g_object_unref (object: fontmap); |
213 | |
214 | return 0; |
215 | } |
216 | |