/* pango-list.c: List all fonts * * Copyright (C) 2018 Google * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Google Author(s): Behdad Esfahbod */ #include "config.h" #include #include #include #include #include #include #include #if HB_VERSION_ATLEAST (3, 3, 0) static void get_axes_and_values (hb_font_t *font, unsigned int n_axes, hb_ot_var_axis_info_t *axes, float *coords) { const float *dcoords; unsigned int length = n_axes; hb_ot_var_get_axis_infos (hb_font_get_face (font), 0, &length, axes); dcoords = hb_font_get_var_coords_design (font, &length); if (dcoords) memcpy (coords, dcoords, sizeof (float) * length); else { for (int i = 0; i < n_axes; i++) { hb_ot_var_axis_info_t *axis = &axes[i]; coords[axis->axis_index] = axis->default_value; } } } #else /* FIXME: This doesn't work if the font has an avar table */ static float denorm_coord (hb_ot_var_axis_info_t *axis, int coord) { float r = coord / 16384.0; if (coord < 0) return axis->default_value + r * (axis->default_value - axis->min_value); else return axis->default_value + r * (axis->max_value - axis->default_value); } static void get_axes_and_values (hb_font_t *font, unsigned int n_axes, hb_ot_var_axis_info_t *axes, float *coords) { const int *ncoords; unsigned int length = n_axes; hb_ot_var_get_axis_infos (hb_font_get_face (font), 0, &length, axes); ncoords = hb_font_get_var_coords_normalized (font, &length); for (int i = 0; i < n_axes; i++) { hb_ot_var_axis_info_t *axis = &axes[i]; int idx = axis->axis_index; if (ncoords) coords[idx] = denorm_coord (axis, ncoords[idx]); else coords[idx] = axis->default_value; } } #endif int main (int argc, char **argv) { gboolean opt_verbose = FALSE; gboolean opt_metrics = FALSE; gboolean opt_variations = FALSE; gboolean opt_version = FALSE; gboolean opt_only_families = FALSE; GOptionEntry entries[] = { { "verbose", 0, 0, G_OPTION_ARG_NONE, &opt_verbose, "Print verbose information", NULL }, { "families", 0, 0, G_OPTION_ARG_NONE, &opt_only_families, "List only families", NULL }, { "metrics", 0, 0, G_OPTION_ARG_NONE, &opt_metrics, "Print font metrics", NULL }, { "variations", 0, 0, G_OPTION_ARG_NONE, &opt_variations, "Print font variations", NULL }, { "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, "Show version" }, { NULL, } }; GOptionContext *context; Pango2Context *ctx; Pango2FontMap *fontmap; int i, j; int width; GError *error = NULL; hb_ot_var_axis_info_t axes[100]; float coords[100]; unsigned int n_axes; g_set_prgname ("pango-list"); setlocale (LC_ALL, ""); context = g_option_context_new (""); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { if (error != NULL) g_printerr ("%s\n", error->message); else g_printerr ("Option parse error\n"); exit (1); } g_option_context_free (context); if (opt_version) { g_print ("%s (%s) %s\n", g_get_prgname (), PACKAGE_NAME, PACKAGE_VERSION); exit (0); } fontmap = pango2_font_map_get_default (); ctx = pango2_context_new (); if (opt_verbose) g_print ("Using %s\n\n", G_OBJECT_TYPE_NAME (fontmap)); for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (fontmap)); i++) { Pango2FontFamily *family = g_list_model_get_item (G_LIST_MODEL (fontmap), i); const char *family_name = pango2_font_family_get_name (family); g_object_unref (family); g_print ("%s", family_name); if (opt_verbose) { if (PANGO2_IS_GENERIC_FAMILY (family)) g_print ("(generic)"); g_print (" (%d faces)", g_list_model_get_n_items (G_LIST_MODEL (family))); } g_print ("\n"); if (opt_only_families) continue; width = 0; for (j = 0; j < g_list_model_get_n_items (G_LIST_MODEL (family)); j++) { Pango2FontFace *face = g_list_model_get_item (G_LIST_MODEL (family), j); const char *face_name = pango2_font_face_get_name (face); gboolean is_synth = pango2_font_face_is_synthesized (face); const char *synth_str = is_synth ? "*" : ""; const char *variable_str = ""; width = MAX (width, strlen (synth_str) + strlen (variable_str) + strlen (face_name)); g_object_unref (face); } for (j = 0; j < g_list_model_get_n_items (G_LIST_MODEL (family)); j++) { Pango2FontFace *face = g_list_model_get_item (G_LIST_MODEL (family), j); const char *face_name = pango2_font_face_get_name (face); gboolean is_synth = pango2_font_face_is_synthesized (face); const char *synth_str = is_synth ? "*" : ""; gboolean is_variable = pango2_font_face_is_variable (face); const char *variable_str = is_variable ? "@" : ""; Pango2FontDescription *desc; char *desc_str; desc = pango2_font_face_describe (face); desc_str = pango2_font_description_to_string (desc); g_print (" %s%s%s: %*s%s\n", synth_str, variable_str, face_name, width - (int)strlen (face_name) - (int)strlen (synth_str) - (int)strlen (variable_str), "", desc_str); pango2_font_description_set_absolute_size (desc, 10 * PANGO2_SCALE); if (opt_metrics) { Pango2FontMetrics *metrics; metrics = pango2_context_get_metrics (ctx, desc, pango2_language_from_string ("en-us")); g_print (" (a %d d %d h %d cw %d dw %d u %d %d s %d %d)\n", pango2_font_metrics_get_ascent (metrics), pango2_font_metrics_get_descent (metrics), pango2_font_metrics_get_height (metrics), pango2_font_metrics_get_approximate_char_width (metrics), pango2_font_metrics_get_approximate_digit_width (metrics), pango2_font_metrics_get_underline_position (metrics), pango2_font_metrics_get_underline_thickness (metrics), pango2_font_metrics_get_strikethrough_position (metrics), pango2_font_metrics_get_strikethrough_thickness (metrics)); pango2_font_metrics_free (metrics); } if (opt_variations) { Pango2Font *font; hb_font_t *hb_font; int instance_id = -1; /* set variations here, to make the fontmap prefer the variable family * over a non-variable one. */ pango2_font_description_set_variations (desc, "@"); font = pango2_context_load_font (ctx, desc); hb_font = pango2_font_get_hb_font (font); if (PANGO2_IS_HB_FONT (font)) { Pango2HbFace *hbface = (Pango2HbFace *)face; instance_id = hbface->instance_id; } if (pango2_font_face_is_variable (face)) { if (instance_id >= 0) g_print (" Instance %d\n", instance_id); else if (instance_id == -1) g_print (" Default Instance\n"); } n_axes = hb_ot_var_get_axis_count (hb_font_get_face (hb_font)); get_axes_and_values (hb_font, n_axes, axes, coords); for (int i = 0; i < n_axes; i++) { char name[20]; unsigned int namelen = 20; hb_ot_name_get_utf8 (hb_font_get_face (hb_font), axes[i].name_id, HB_LANGUAGE_INVALID, &namelen, name); g_print (" %s: %g (%g - %g, %g)\n", name, coords[axes[i].axis_index], axes[i].min_value, axes[i].max_value, axes[i].default_value); } g_object_unref (font); } if (opt_verbose) { if (PANGO2_IS_HB_FACE (face)) { Pango2HbFace *hbface = (Pango2HbFace *)face; if (hbface->file) g_print (" %d %s\n", hbface->index, hbface->file); } } g_free (desc_str); pango2_font_description_free (desc); g_object_unref (face); } } g_object_unref (ctx); g_object_unref (fontmap); return 0; }