1 /*
2 * Copyright © 2023 Behdad Esfahbod
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
27 #include "batch.hh"
28 #include "font-options.hh"
29
30 #ifdef HB_HAS_GOBJECT
31 #include <hb-gobject.h>
32 #endif
33
34 #ifdef HAVE_CHAFA
35 # include <chafa.h>
36 #endif
37
38 const unsigned DEFAULT_FONT_SIZE = FONT_SIZE_UPEM;
39 const unsigned SUBPIXEL_BITS = 0;
40
41 static void
_hb_ot_name_get_utf8(hb_face_t * face,hb_ot_name_id_t name_id,hb_language_t language,unsigned int * text_size,char * text)42 _hb_ot_name_get_utf8 (hb_face_t *face,
43 hb_ot_name_id_t name_id,
44 hb_language_t language,
45 unsigned int *text_size /* IN/OUT */,
46 char *text /* OUT */)
47 {
48 static hb_language_t en = hb_language_from_string ("en", -1);
49
50 unsigned len = *text_size;
51 if (!hb_ot_name_get_utf8 (face, name_id,
52 language,
53 &len, text))
54 {
55 len = *text_size;
56 hb_ot_name_get_utf8 (face, name_id,
57 en,
58 &len, text);
59 }
60 *text_size = len;
61 }
62
63 struct info_t :
64 option_parser_t,
65 font_options_t
66 {
add_optionsinfo_t67 void add_options ()
68 {
69 font_options_t::add_options (this);
70
71 GOptionEntry misc_entries[] =
72 {
73 {"direction", 0, 0, G_OPTION_ARG_STRING, &this->direction_str, "Set direction (default: ltr)", "ltr/rtl/ttb/btt"},
74 {"script", 0, 0, G_OPTION_ARG_STRING, &this->script_str, "Set script (default: none)", "ISO-15924 tag; eg. 'Latn'"},
75 {"language", 0, 0, G_OPTION_ARG_STRING, &this->language_str, "Set language (default: $LANG)", "BCP 47 tag; eg. 'en'"},
76 {"ot-script", 0, 0, G_OPTION_ARG_STRING, &this->ot_script_str, "Set OpenType script tag (default: none)","tag; eg. 'latn'"},
77 {"ot-language", 0, 0, G_OPTION_ARG_STRING, &this->ot_language_str, "Set OpenType language tag (default: none)", "tag; eg. 'ENG'"},
78
79 {nullptr}
80 };
81 add_group (misc_entries,
82 "misc",
83 "Miscellaneous options:",
84 "Miscellaneous options affecting queries",
85 this,
86 false /* We add below. */);
87
88 GOptionEntry query_entries[] =
89 {
90 {"all", 'a', 0, G_OPTION_ARG_NONE, &this->all, "Show everything", nullptr},
91
92 {"show-all", 0, 0, G_OPTION_ARG_NONE, &this->show_all, "Show all short information (default)", nullptr},
93 {"show-face-count",0, 0, G_OPTION_ARG_NONE, &this->show_face_count, "Show face count", nullptr},
94 {"show-family", 0, 0, G_OPTION_ARG_NONE, &this->show_family, "Show family name", nullptr},
95 {"show-subfamily",0, 0, G_OPTION_ARG_NONE, &this->show_subfamily, "Show subfamily name", nullptr},
96 {"show-unique-name",0, 0, G_OPTION_ARG_NONE, &this->show_unique_name, "Show unique name", nullptr},
97 {"show-full-name",0, 0, G_OPTION_ARG_NONE, &this->show_full_name, "Show full name", nullptr},
98 {"show-postscript-name",0, 0, G_OPTION_ARG_NONE, &this->show_postscript_name, "Show Postscript name", nullptr},
99 {"show-version", 0, 0, G_OPTION_ARG_NONE, &this->show_version, "Show version", nullptr},
100 {"show-technology",0, 0, G_OPTION_ARG_NONE, &this->show_technology, "Show technology", nullptr},
101 {"show-unicode-count",0, 0, G_OPTION_ARG_NONE, &this->show_unicode_count, "Show Unicode count", nullptr},
102 {"show-glyph-count",0, 0, G_OPTION_ARG_NONE, &this->show_glyph_count, "Show glyph count", nullptr},
103 {"show-upem", 0, 0, G_OPTION_ARG_NONE, &this->show_upem, "Show Units-Per-EM", nullptr},
104 {"show-extents", 0, 0, G_OPTION_ARG_NONE, &this->show_extents, "Show extents", nullptr},
105
106 {"get-name", 0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_name, "Get name", "name id; eg. '13'"},
107 {"get-style", 0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_style, "Get style", "style tag; eg. 'wght'"},
108 {"get-metric", 0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_metric, "Get metric", "metric tag; eg. 'hasc'"},
109 {"get-baseline", 0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_baseline, "Get baseline", "baseline tag; eg. 'hang'"},
110 {"get-meta", 0, 0, G_OPTION_ARG_STRING_ARRAY,&this->get_meta, "Get meta information", "tag tag; eg. 'dlng'"},
111 {"get-table", 0, 0, G_OPTION_ARG_STRING, &this->get_table, "Get font table", "table tag; eg. 'cmap'"},
112
113 {"list-all", 0, 0, G_OPTION_ARG_NONE, &this->list_all, "List all long information", nullptr},
114 {"list-names", 0, 0, G_OPTION_ARG_NONE, &this->list_names, "List names", nullptr},
115 #ifdef HB_HAS_GOBJECT
116 {"list-style", 0, 0, G_OPTION_ARG_NONE, &this->list_style, "List style", nullptr},
117 {"list-metrics", 0, 0, G_OPTION_ARG_NONE, &this->list_metrics, "List metrics", nullptr},
118 {"list-baselines",0, 0, G_OPTION_ARG_NONE, &this->list_baselines, "List baselines", nullptr},
119 #endif
120 {"list-tables", 'l', 0, G_OPTION_ARG_NONE, &this->list_tables, "List tables", nullptr},
121 {"list-unicodes", 0, 0, G_OPTION_ARG_NONE, &this->list_unicodes, "List characters", nullptr},
122 {"list-glyphs", 0, 0, G_OPTION_ARG_NONE, &this->list_glyphs, "List glyphs", nullptr},
123 {"list-scripts", 0, 0, G_OPTION_ARG_NONE, &this->list_scripts, "List layout scripts", nullptr},
124 {"list-features", 0, 0, G_OPTION_ARG_NONE, &this->list_features, "List layout features", nullptr},
125 #ifndef HB_NO_VAR
126 {"list-variations",0, 0, G_OPTION_ARG_NONE, &this->list_variations, "List variations", nullptr},
127 #endif
128 {"list-palettes", 0, 0, G_OPTION_ARG_NONE, &this->list_palettes, "List color palettes", nullptr},
129 {"list-meta", 0, 0, G_OPTION_ARG_NONE, &this->list_meta, "List meta information", nullptr},
130
131 {nullptr}
132 };
133 add_group (query_entries,
134 "query",
135 "Query options:",
136 "Options to query the font instance",
137 this,
138 true);
139
140 GOptionEntry entries[] =
141 {
142 {"quiet", 'q', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &this->verbose, "Generate machine-readable output", nullptr},
143 {G_OPTION_REMAINING, 0, G_OPTION_FLAG_IN_MAIN,
144 G_OPTION_ARG_CALLBACK, (gpointer) &collect_rest, nullptr, "[FONT-FILE]"},
145 {nullptr}
146 };
147 add_main_group (entries, this);
148
149 option_parser_t::add_options ();
150 }
151
152 static gboolean
collect_restinfo_t153 collect_rest (const char *name G_GNUC_UNUSED,
154 const char *arg,
155 gpointer data,
156 GError **error)
157 {
158 info_t *thiz = (info_t *) data;
159
160 if (!thiz->font_file)
161 {
162 thiz->font_file = g_strdup (arg);
163 return true;
164 }
165
166 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
167 "Too many arguments on the command line");
168 return false;
169 }
170
171
172 protected:
173
174 hb_bool_t verbose = true;
175 hb_bool_t first_item = true;
176
177 char *direction_str = nullptr;
178 char *script_str = nullptr;
179 char *language_str = nullptr;
180 hb_direction_t direction = HB_DIRECTION_LTR;
181 hb_script_t script = HB_SCRIPT_INVALID;
182 hb_language_t language = HB_LANGUAGE_INVALID;
183 char *ot_script_str = nullptr;
184 char *ot_language_str = nullptr;
185
186 hb_bool_t all = false;
187
188 hb_bool_t show_all = false;
189 hb_bool_t show_face_count = false;
190 hb_bool_t show_family = false;
191 hb_bool_t show_subfamily = false;
192 hb_bool_t show_unique_name = false;
193 hb_bool_t show_full_name = false;
194 hb_bool_t show_postscript_name = false;
195 hb_bool_t show_version = false;
196 hb_bool_t show_technology = false;
197 hb_bool_t show_unicode_count = false;
198 hb_bool_t show_glyph_count = false;
199 hb_bool_t show_upem = false;
200 hb_bool_t show_extents = false;
201
202 char **get_name = nullptr;
203 char **get_style = nullptr;
204 char **get_metric = nullptr;
205 char **get_baseline = nullptr;
206 char **get_meta = nullptr;
207 char *get_table = nullptr;
208
209 hb_bool_t list_all = false;
210 hb_bool_t list_names = false;
211 #ifdef HB_HAS_GOBJECT
212 hb_bool_t list_style = false;
213 hb_bool_t list_metrics = false;
214 hb_bool_t list_baselines = false;
215 #endif
216 hb_bool_t list_tables = false;
217 hb_bool_t list_unicodes = false;
218 hb_bool_t list_glyphs = false;
219 hb_bool_t list_scripts = false;
220 hb_bool_t list_features = false;
221 #ifndef HB_NO_VAR
222 hb_bool_t list_variations = false;
223 #endif
224 hb_bool_t list_palettes = false;
225 hb_bool_t list_meta = false;
226
227 public:
228
229 void
post_parseinfo_t230 post_parse (GError **error)
231 {
232 if (direction_str)
233 direction = hb_direction_from_string (direction_str, -1);
234 if (script_str)
235 script = hb_script_from_string (script_str, -1);
236 language = hb_language_get_default ();
237 if (language_str)
238 language = hb_language_from_string (language_str, -1);
239 }
240
241 int
operator ()info_t242 operator () (int argc, char **argv)
243 {
244 add_options ();
245
246 if (argc == 2)
247 show_all = true;
248
249 parse (&argc, &argv);
250
251 if (all)
252 {
253 show_all =
254 list_all =
255 true;
256 }
257
258 if (show_all)
259 {
260 show_face_count =
261 show_family =
262 show_subfamily =
263 show_unique_name =
264 show_full_name =
265 show_postscript_name =
266 show_version =
267 show_technology =
268 show_unicode_count =
269 show_glyph_count =
270 show_upem =
271 show_extents =
272 true;
273 first_item = false;
274 }
275
276 if (list_all)
277 {
278 list_names =
279 #ifdef HB_HAS_GOBJECT
280 list_style =
281 list_metrics =
282 list_baselines =
283 #endif
284 list_tables =
285 list_unicodes =
286 list_glyphs =
287 list_scripts =
288 list_features =
289 #ifndef HB_NO_VAR
290 list_variations =
291 #endif
292 list_palettes =
293 list_meta =
294 true;
295 }
296
297 if (show_face_count) _show_face_count ();
298 if (show_family) _show_family ();
299 if (show_subfamily) _show_subfamily ();
300 if (show_unique_name) _show_unique_name ();
301 if (show_full_name) _show_full_name ();
302 if (show_postscript_name)_show_postscript_name ();
303 if (show_version) _show_version ();
304 if (show_technology) _show_technology ();
305 if (show_unicode_count)_show_unicode_count ();
306 if (show_glyph_count) _show_glyph_count ();
307 if (show_upem) _show_upem ();
308 if (show_extents) _show_extents ();
309
310 if (get_name) _get_name ();
311 if (get_style) _get_style ();
312 if (get_metric) _get_metric ();
313 if (get_baseline) _get_baseline ();
314 if (get_meta) _get_meta ();
315 if (get_table) _get_table ();
316
317 if (list_names) _list_names ();
318 #ifdef HB_HAS_GOBJECT
319 if (list_style) _list_style ();
320 if (list_metrics) _list_metrics ();
321 if (list_baselines) _list_baselines ();
322 #endif
323 if (list_tables) _list_tables ();
324 if (list_unicodes) _list_unicodes ();
325 if (list_glyphs) _list_glyphs ();
326 if (list_scripts) _list_scripts ();
327 if (list_features) _list_features ();
328 #ifndef HB_NO_VAR
329 if (list_variations) _list_variations ();
330 #endif
331 if (list_palettes) _list_palettes ();
332 if (list_meta) _list_meta ();
333
334 return 0;
335 }
336
337 protected:
338
separatorinfo_t339 void separator ()
340 {
341 if (first_item)
342 {
343 first_item = false;
344 return;
345 }
346 printf ("\n===\n\n");
347 }
348
349 void
_show_face_countinfo_t350 _show_face_count ()
351 {
352 hb_blob_t *blob = hb_blob_create_from_file (font_file);
353 printf ("Face count: %u\n", hb_face_count (blob));
354 hb_blob_destroy (blob);
355 }
356
357 void
_show_nameinfo_t358 _show_name (const char *label, hb_ot_name_id_t name_id)
359 {
360 if (verbose)
361 {
362 printf ("%s: ", label);
363 }
364
365 char name[16384];
366 unsigned name_len = sizeof name;
367 _hb_ot_name_get_utf8 (face, name_id,
368 language,
369 &name_len, name);
370
371 printf ("%s\n", name);
372 }
_show_familyinfo_t373 void _show_family () { _show_name ("Family", 1); }
_show_subfamilyinfo_t374 void _show_subfamily ()
375 {
376 hb_ot_name_id_t name_id = 2;
377
378 unsigned named_instance = hb_font_get_var_named_instance (font);
379 if (named_instance != HB_FONT_NO_VAR_NAMED_INSTANCE)
380 name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, named_instance);
381
382 _show_name ("Subfamily", name_id);
383 }
_show_unique_nameinfo_t384 void _show_unique_name () { _show_name ("Unique name", 3); }
_show_full_nameinfo_t385 void _show_full_name () { _show_name ("Full name", 4); }
_show_postscript_nameinfo_t386 void _show_postscript_name ()
387 {
388 hb_ot_name_id_t name_id = 6;
389
390 unsigned named_instance = hb_font_get_var_named_instance (font);
391 if (named_instance != HB_FONT_NO_VAR_NAMED_INSTANCE)
392 name_id = hb_ot_var_named_instance_get_postscript_name_id (face, named_instance);
393
394
395 _show_name ("Postscript name", name_id);
396 }
_show_versioninfo_t397 void _show_version () { _show_name ("Version", 5); }
398
_has_blobinfo_t399 bool _has_blob (hb_tag_t tag)
400 {
401 hb_blob_t *blob = hb_face_reference_table (face, tag);
402 bool ret = hb_blob_get_length (blob);
403 hb_blob_destroy (blob);
404 return ret;
405 }
406
_show_technologyinfo_t407 void _show_technology ()
408 {
409 if (_has_blob (HB_TAG('g','l','y','f')))
410 printf ("Has TrueType outlines\n");
411 if (_has_blob (HB_TAG('C','F','F',' ')) || _has_blob (HB_TAG('C','F','F','2')))
412 printf ("Has Postscript outlines\n");
413
414 if (_has_blob (HB_TAG('f','p','g','m')) || _has_blob (HB_TAG('p','r','e','p')) || _has_blob (HB_TAG('c','v','t',' ')))
415 printf ("Has TrueType hinting\n");
416
417 if (_has_blob (HB_TAG('G','S','U','B')) || _has_blob (HB_TAG('G','P','O','S')))
418 printf ("Has OpenType layout\n");
419 if (_has_blob (HB_TAG('m','o','r','x')) || _has_blob (HB_TAG('k','e','r','x')))
420 printf ("Has AAT layout\n");
421 if (_has_blob (HB_TAG('S','i','l','f')))
422 printf ("Has Graphite layout\n");
423 if (_has_blob (HB_TAG('k','e','r','n')))
424 printf ("Has legacy kerning\n");
425
426 if (_has_blob (HB_TAG('E','B','D','T')))
427 printf ("Has monochrome bitmaps\n");
428
429 if (_has_blob (HB_TAG('C','B','D','T')) || _has_blob (HB_TAG('s','b','i','x')))
430 printf ("Has color bitmaps\n");
431 if (_has_blob (HB_TAG('S','V','G',' ')))
432 printf ("Has color SVGs\n");
433 if (_has_blob (HB_TAG('C','O','L','R')))
434 printf ("Has color paintings\n");
435
436 if (_has_blob (HB_TAG('f','v','a','r'))) printf ("Has variations\n");
437 }
438
_show_unicode_countinfo_t439 void _show_unicode_count ()
440 {
441 if (verbose)
442 {
443 printf ("Unicode count: ");
444 }
445
446 hb_set_t *unicodes = hb_set_create ();
447 hb_face_collect_unicodes (face, unicodes);
448
449 printf ("%u\n", hb_set_get_population (unicodes));
450
451 hb_set_destroy (unicodes);
452 }
453
_show_glyph_countinfo_t454 void _show_glyph_count ()
455 {
456 if (verbose)
457 {
458 printf ("Glyph count: ");
459 }
460
461 printf ("%u\n", hb_face_get_glyph_count (face));
462 }
463
_show_upeminfo_t464 void _show_upem ()
465 {
466 if (verbose)
467 {
468 printf ("Units-Per-EM: ");
469 }
470
471 printf ("%u\n", hb_face_get_upem (face));
472 }
473
_show_extentsinfo_t474 void _show_extents ()
475 {
476 hb_font_extents_t extents;
477 hb_font_get_extents_for_direction (font, direction, &extents);
478
479 if (verbose) printf ("Ascender: ");
480 printf ("%d\n", extents.ascender);
481
482 if (verbose) printf ("Descender: ");
483 printf ("%d\n", extents.descender);
484
485 if (verbose) printf ("Line gap: ");
486 printf ("%d\n", extents.line_gap);
487 }
488
_get_nameinfo_t489 void _get_name ()
490 {
491 for (char **p = get_name; *p; p++)
492 {
493 hb_ot_name_id_t name_id = (hb_ot_name_id_t) atoi (*p);
494 _show_name (*p, name_id);
495 }
496 }
497
_get_styleinfo_t498 void _get_style ()
499 {
500 for (char **p = get_style; *p; p++)
501 {
502 hb_style_tag_t tag = (hb_style_tag_t) hb_tag_from_string (*p, -1);
503
504 if (verbose)
505 printf ("Style %c%c%c%c: ", HB_UNTAG (tag));
506
507 float v = hb_style_get_value (font, tag);
508 printf ("%g\n", (double) v);
509 }
510 }
511
_get_metricinfo_t512 void _get_metric ()
513 {
514 bool fallback = false;
515 for (char **p = get_metric; *p; p++)
516 {
517 hb_ot_metrics_tag_t tag = (hb_ot_metrics_tag_t) hb_tag_from_string (*p, -1);
518 hb_position_t position;
519
520 if (verbose)
521 printf ("Metric %c%c%c%c: ", HB_UNTAG (tag));
522
523 if (hb_ot_metrics_get_position (font, tag, &position))
524 printf ("%d \n", position);
525 else
526 {
527 hb_ot_metrics_get_position_with_fallback (font, tag, &position);
528 printf ("%d *\n", position);
529 fallback = true;
530 }
531 }
532
533 if (verbose && fallback)
534 {
535 printf ("\n[*] Fallback value\n");
536 }
537 }
538
_get_baselineinfo_t539 void _get_baseline ()
540 {
541 hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
542 hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
543 unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
544 unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
545
546 hb_ot_tags_from_script_and_language (script, language,
547 &script_count, script_tags,
548 &language_count, language_tags);
549
550 hb_tag_t script_tag = script_count ? script_tags[script_count - 1] : HB_TAG_NONE;
551 hb_tag_t language_tag = language_count ? language_tags[0] : HB_TAG_NONE;
552
553 if (ot_script_str)
554 script_tag = hb_tag_from_string (ot_script_str, -1);
555 if (ot_language_str)
556 language_tag = hb_tag_from_string (ot_language_str, -1);
557
558
559 bool fallback = false;
560 for (char **p = get_baseline; *p; p++)
561 {
562 hb_ot_layout_baseline_tag_t tag = (hb_ot_layout_baseline_tag_t) hb_tag_from_string (*p, -1);
563 hb_position_t position;
564
565 if (verbose)
566 printf ("Baseline %c%c%c%c: ", HB_UNTAG (tag));
567
568 if (hb_ot_layout_get_baseline (font, tag, direction, script_tag, language_tag, &position))
569 printf ("%d \n", position);
570 else
571 {
572 hb_ot_layout_get_baseline_with_fallback (font, tag, direction, script_tag, language_tag, &position);
573 printf ("%d *\n", position);
574 fallback = true;
575 }
576 }
577
578 if (verbose && fallback)
579 {
580 printf ("\n[*] Fallback value\n");
581 }
582 }
583
_get_metainfo_t584 void _get_meta ()
585 {
586 for (char **p = get_meta; *p; p++)
587 {
588 hb_ot_meta_tag_t tag = (hb_ot_meta_tag_t) hb_tag_from_string (*p, -1);
589
590 hb_blob_t *blob = hb_ot_meta_reference_entry (face, tag);
591
592 if (verbose)
593 printf ("Meta %c%c%c%c: ", HB_UNTAG (tag));
594
595 printf ("%.*s\n",
596 (int) hb_blob_get_length (blob),
597 hb_blob_get_data (blob, nullptr));
598
599 hb_blob_destroy (blob);
600 }
601 }
602
603 void
_get_tableinfo_t604 _get_table ()
605 {
606 hb_blob_t *blob = hb_face_reference_table (face, hb_tag_from_string (get_table, -1));
607 unsigned count = 0;
608 const char *data = hb_blob_get_data (blob, &count);
609 fwrite (data, 1, count, stdout);
610 hb_blob_destroy (blob);
611 }
612
_list_namesinfo_t613 void _list_names ()
614 {
615 if (verbose)
616 {
617 separator ();
618 printf ("Name information:\n\n");
619 printf ("Id: Name Text\n------------------------------------\n");
620 }
621
622 #ifdef HB_HAS_GOBJECT
623 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_NAME_ID_PREDEFINED);
624 #endif
625
626 unsigned count;
627 const auto *entries = hb_ot_name_list_names (face, &count);
628 for (unsigned i = 0; i < count; i++)
629 {
630 char name[16384];
631 unsigned name_len = sizeof name;
632 _hb_ot_name_get_utf8 (face, entries[i].name_id,
633 language,
634 &name_len, name);
635
636 #ifdef HB_HAS_GOBJECT
637 if (verbose)
638 {
639 GEnumValue *enum_value = g_enum_get_value (enum_class, entries[i].name_id);
640 printf ("%u: %-27s %s\n", entries[i].name_id, enum_value ? enum_value->value_nick : "", name);
641 }
642 else
643 #endif
644 printf ("%u %s\n", entries[i].name_id, name);
645 }
646 }
647
648 #ifdef HB_HAS_GOBJECT
_list_styleinfo_t649 void _list_style ()
650 {
651 if (verbose)
652 {
653 separator ();
654 printf ("Style information:\n\n");
655 printf ("Tag: Name Value\n---------------------------------------------\n");
656 }
657
658 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_STYLE_TAG);
659
660 unsigned count = enum_class->n_values;
661 const auto *entries = enum_class->values;
662 for (unsigned i = 0; i < count; i++)
663 {
664 float v = hb_style_get_value (font, (hb_style_tag_t) entries[i].value);
665 printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
666 if (verbose)
667 printf (": %-33s", entries[i].value_nick);
668 printf (" %g\n", (double) v);
669 }
670 }
671
_list_metricsinfo_t672 void _list_metrics ()
673 {
674 if (verbose)
675 {
676 separator ();
677 printf ("Metrics information:\n\n");
678 printf ("Tag: Name Value\n---------------------------------------------\n");
679 }
680
681 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_METRICS_TAG);
682
683 bool any_fallback = false;
684
685 unsigned count = enum_class->n_values;
686 const auto *entries = enum_class->values;
687 for (unsigned i = 0; i < count; i++)
688 {
689 bool fallback = false;
690 hb_position_t v;
691 if (!hb_ot_metrics_get_position (font,
692 (hb_ot_metrics_tag_t) entries[i].value,
693 &v))
694 {
695 hb_ot_metrics_get_position_with_fallback (font,
696 (hb_ot_metrics_tag_t) entries[i].value,
697 &v);
698 any_fallback = fallback = true;
699 }
700 printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
701 if (verbose)
702 printf (": %-33s", entries[i].value_nick);
703 printf (" %d ", v);
704
705 if (fallback)
706 printf ("*");
707 printf ("\n");
708 }
709
710 if (verbose && any_fallback)
711 {
712 printf ("\n[*] Fallback value\n");
713 }
714 }
715
_list_baselinesinfo_t716 void _list_baselines ()
717 {
718 hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
719 hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
720 unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
721 unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
722
723 hb_ot_tags_from_script_and_language (script, language,
724 &script_count, script_tags,
725 &language_count, language_tags);
726
727 hb_tag_t script_tag = script_count ? script_tags[script_count - 1] : HB_TAG_NONE;
728 hb_tag_t language_tag = language_count ? language_tags[0] : HB_TAG_NONE;
729
730 if (ot_script_str)
731 script_tag = hb_tag_from_string (ot_script_str, -1);
732 if (ot_language_str)
733 language_tag = hb_tag_from_string (ot_language_str, -1);
734
735
736 if (verbose)
737 {
738 separator ();
739 printf ("Baselines information:\n\n");
740 printf ("Tag: Name Value\n---------------------------------------------\n");
741 }
742
743 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_LAYOUT_BASELINE_TAG);
744
745 bool any_fallback = false;
746
747 unsigned count = enum_class->n_values;
748 const auto *entries = enum_class->values;
749 for (unsigned i = 0; i < count; i++)
750 {
751 bool fallback = false;
752 hb_position_t v;
753 if (!hb_ot_layout_get_baseline (font, (hb_ot_layout_baseline_tag_t) entries[i].value,
754 direction, script_tag, language_tag,
755 &v))
756 {
757 hb_ot_layout_get_baseline_with_fallback (font, (hb_ot_layout_baseline_tag_t) entries[i].value,
758 direction, script_tag, language_tag,
759 &v);
760 any_fallback = fallback = true;
761 }
762 printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
763 if (verbose)
764 printf (": %-33s", entries[i].value_nick);
765 printf (" %d ", v);
766
767 if (fallback)
768 printf ("*");
769 printf ("\n");
770 }
771
772 if (verbose && any_fallback)
773 {
774 printf ("\n[*] Fallback value\n");
775 }
776 }
777 #endif
778
_list_tablesinfo_t779 void _list_tables ()
780 {
781 if (verbose)
782 {
783 separator ();
784 printf ("Table information:\n\n");
785 printf ("Tag Size\n------------\n");
786 }
787
788 unsigned count = hb_face_get_table_tags (face, 0, nullptr, nullptr);
789 hb_tag_t *tags = (hb_tag_t *) calloc (count, sizeof (hb_tag_t));
790 hb_face_get_table_tags (face, 0, &count, tags);
791
792 for (unsigned i = 0; i < count; i++)
793 {
794 hb_tag_t tag = tags[i];
795
796 hb_blob_t *blob = hb_face_reference_table (face, tag);
797
798 printf ("%c%c%c%c %8u bytes\n", HB_UNTAG (tag), hb_blob_get_length (blob));
799
800 hb_blob_destroy (blob);
801 }
802
803 free (tags);
804 }
805
806 void
_list_unicodesinfo_t807 _list_unicodes ()
808 {
809 if (verbose)
810 {
811 separator ();
812 printf ("Character-set information:\n\n");
813 printf ("Unicode Glyph name\n------------------\n");
814 }
815
816 hb_set_t *unicodes = hb_set_create ();
817 hb_map_t *cmap = hb_map_create ();
818
819 hb_face_collect_nominal_glyph_mapping (face, cmap, unicodes);
820
821 for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
822 hb_set_next (unicodes, &u);)
823 {
824 hb_codepoint_t gid = hb_map_get (cmap, u);
825
826 char glyphname[128];
827 hb_font_glyph_to_string (font, gid,
828 glyphname, sizeof glyphname);
829
830 printf ("U+%04X %s\n", u, glyphname);
831 }
832
833 hb_map_destroy (cmap);
834
835
836 /* List variation-selector sequences. */
837 hb_set_t *vars = hb_set_create ();
838
839 hb_face_collect_variation_selectors (face, vars);
840
841 for (hb_codepoint_t vs = HB_SET_VALUE_INVALID;
842 hb_set_next (vars, &vs);)
843 {
844 hb_set_clear (unicodes);
845 hb_face_collect_variation_unicodes (face, vs, unicodes);
846
847 for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
848 hb_set_next (unicodes, &u);)
849 {
850 hb_codepoint_t gid = 0;
851 HB_UNUSED bool b = hb_font_get_variation_glyph (font, u, vs, &gid);
852 assert (b);
853
854 char glyphname[128];
855 hb_font_glyph_to_string (font, gid,
856 glyphname, sizeof glyphname);
857
858 printf ("U+%04X,U+%04X %s\n", vs, u, glyphname);
859 }
860 }
861
862 hb_set_destroy (vars);
863 hb_set_destroy (unicodes);
864 }
865
866 void
_list_glyphsinfo_t867 _list_glyphs ()
868 {
869 if (verbose)
870 {
871 separator ();
872 printf ("Glyph-set information:\n\n");
873 printf ("GlyphID Glyph name\n------------------\n");
874 }
875
876 unsigned num_glyphs = hb_face_get_glyph_count (face);
877
878 for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
879 {
880 char glyphname[128];
881 hb_font_glyph_to_string (font, gid,
882 glyphname, sizeof glyphname);
883
884 printf ("%u %s\n", gid, glyphname);
885 }
886 }
887
888 void
_list_scriptsinfo_t889 _list_scripts ()
890 {
891 if (verbose)
892 {
893 separator ();
894 printf ("Layout script information:\n\n");
895 }
896
897 hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
898
899 for (unsigned int i = 0; table_tags[i]; i++)
900 {
901 if (verbose) printf ("Table: ");
902 printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
903
904 hb_tag_t script_array[32];
905 unsigned script_count = sizeof script_array / sizeof script_array[0];
906 unsigned script_offset = 0;
907 do
908 {
909 hb_ot_layout_table_get_script_tags (face, table_tags[i],
910 script_offset,
911 &script_count,
912 script_array);
913
914 for (unsigned script_index = 0; script_index < script_count; script_index++)
915 {
916 printf (" ");
917 if (verbose) printf ("Script: ");
918
919 hb_tag_t hb_sc = hb_script_to_iso15924_tag (hb_ot_tag_to_script (script_array[script_index]));
920 if (script_array[script_index] == HB_TAG ('D','F','L','T'))
921 hb_sc = HB_SCRIPT_COMMON;
922
923 printf ("%c%c%c%c (%c%c%c%c)\n",
924 HB_UNTAG (hb_sc),
925 HB_UNTAG (script_array[script_index]));
926
927 hb_tag_t language_array[32];
928 unsigned language_count = sizeof language_array / sizeof language_array[0];
929 unsigned language_offset = 0;
930 do
931 {
932 hb_ot_layout_script_get_language_tags (face, table_tags[i],
933 script_offset + script_index,
934 language_offset,
935 &language_count,
936 language_array);
937
938 for (unsigned language_index = 0; language_index < language_count; language_index++)
939 {
940 printf (" ");
941 if (verbose) printf ("Language: ");
942 printf ("%s (%c%c%c%c)\n",
943 hb_language_to_string (hb_ot_tag_to_language (language_array[language_index])),
944 HB_UNTAG (language_array[language_index]));
945 }
946
947 language_offset += language_count;
948 }
949 while (language_count == sizeof language_array / sizeof language_array[0]);
950 }
951
952 script_offset += script_count;
953 }
954 while (script_count == sizeof script_array / sizeof script_array[0]);
955
956 }
957
958 }
959
960 void
_list_features_no_scriptinfo_t961 _list_features_no_script ()
962 {
963 if (verbose)
964 {
965 printf ("Showing all font features with duplicates removed.\n\n");
966 }
967
968 hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
969
970 hb_set_t *features = hb_set_create ();
971
972 for (unsigned int i = 0; table_tags[i]; i++)
973 {
974 if (verbose) printf ("Table: ");
975 printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
976
977 hb_set_clear (features);
978 hb_tag_t feature_array[32];
979 unsigned feature_count = sizeof feature_array / sizeof feature_array[0];
980 unsigned feature_offset = 0;
981 do
982 {
983 hb_ot_layout_table_get_feature_tags (face, table_tags[i],
984 feature_offset,
985 &feature_count,
986 feature_array);
987
988 for (unsigned feature_index = 0; feature_index < feature_count; feature_index++)
989 {
990 if (hb_set_has (features, feature_array[feature_index]))
991 continue;
992 hb_set_add (features, feature_array[feature_index]);
993
994 hb_ot_name_id_t label_id;
995
996 hb_ot_layout_feature_get_name_ids (face,
997 table_tags[i],
998 feature_offset + feature_index,
999 &label_id,
1000 nullptr,
1001 nullptr,
1002 nullptr,
1003 nullptr);
1004
1005 char name[128];
1006 unsigned name_len = sizeof name;
1007
1008 _hb_ot_name_get_utf8 (face, label_id,
1009 language,
1010 &name_len, name);
1011
1012 printf (" ");
1013 if (verbose) printf ("Feature: ");
1014 printf ("%c%c%c%c", HB_UNTAG (feature_array[feature_index]));
1015
1016 if (*name)
1017 printf (" %s", name);
1018
1019 printf ("\n");
1020 }
1021
1022 feature_offset += feature_count;
1023 }
1024 while (feature_count == sizeof feature_array / sizeof feature_array[0]);
1025 }
1026
1027 hb_set_destroy (features);
1028 }
1029
1030 void
_list_featuresinfo_t1031 _list_features ()
1032 {
1033 if (verbose)
1034 {
1035 separator ();
1036 printf ("Layout features information:\n\n");
1037 }
1038
1039 hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
1040
1041 if (script == HB_SCRIPT_INVALID && !ot_script_str)
1042 {
1043 _list_features_no_script ();
1044 return;
1045 }
1046
1047 for (unsigned int i = 0; table_tags[i]; i++)
1048 {
1049 if (verbose) printf ("Table: ");
1050 printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
1051
1052 auto table_tag = table_tags[i];
1053
1054 hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
1055 hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
1056 unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
1057 unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
1058
1059 hb_ot_tags_from_script_and_language (script, language,
1060 &script_count, script_tags,
1061 &language_count, language_tags);
1062
1063 if (ot_script_str)
1064 {
1065 script_tags[0] = hb_tag_from_string (ot_script_str, -1);
1066 script_count = 1;
1067 }
1068 if (ot_language_str)
1069 {
1070 language_tags[0] = hb_tag_from_string (ot_language_str, -1);
1071 language_count = 1;
1072 }
1073
1074 unsigned script_index;
1075 hb_tag_t chosen_script;
1076 hb_ot_layout_table_select_script (face, table_tag,
1077 script_count, script_tags,
1078 &script_index, &chosen_script);
1079
1080 unsigned language_index;
1081 hb_tag_t chosen_language;
1082 hb_ot_layout_script_select_language2 (face, table_tag,
1083 script_index,
1084 language_count, language_tags,
1085 &language_index, &chosen_language);
1086
1087 if (verbose)
1088 {
1089 if (chosen_script)
1090 {
1091 printf (" Script: %c%c%c%c\n", HB_UNTAG (chosen_script));
1092 if (chosen_language)
1093 printf (" Language: %c%c%c%c\n", HB_UNTAG (chosen_language));
1094 else
1095 printf (" Language: Default\n");
1096 }
1097 }
1098
1099 unsigned feature_array[32];
1100 unsigned feature_count = sizeof feature_array / sizeof feature_array[0];
1101 unsigned feature_offset = 0;
1102 do
1103 {
1104 hb_ot_layout_language_get_feature_indexes (face, table_tag,
1105 script_index, language_index,
1106 feature_offset,
1107 &feature_count,
1108 feature_array);
1109
1110 for (unsigned feature_index = 0; feature_index < feature_count; feature_index++)
1111 {
1112 hb_ot_name_id_t label_id;
1113
1114 hb_ot_layout_feature_get_name_ids (face,
1115 table_tags[i],
1116 feature_array[feature_index],
1117 &label_id,
1118 nullptr,
1119 nullptr,
1120 nullptr,
1121 nullptr);
1122
1123 char name[128];
1124 unsigned name_len = sizeof name;
1125
1126 _hb_ot_name_get_utf8 (face, label_id,
1127 language,
1128 &name_len, name);
1129
1130 printf (" ");
1131 if (verbose) printf ("Feature: ");
1132 hb_tag_t feature_tag;
1133 unsigned f_count = 1;
1134 hb_ot_layout_table_get_feature_tags (face, table_tag,
1135 feature_array[feature_index],
1136 &f_count, &feature_tag);
1137 printf ("%c%c%c%c", HB_UNTAG (feature_tag));
1138
1139 if (*name)
1140 printf (" %s", name);
1141
1142 printf ("\n");
1143 }
1144
1145 feature_offset += feature_count;
1146 }
1147 while (feature_count == sizeof feature_array / sizeof feature_array[0]);
1148 }
1149 }
1150
1151 #ifndef HB_NO_VAR
1152 void
_list_variationsinfo_t1153 _list_variations ()
1154 {
1155 if (verbose)
1156 {
1157 separator ();
1158 printf ("Variations information:\n\n");
1159 }
1160
1161 hb_ot_var_axis_info_t *axes;
1162
1163 unsigned count = hb_ot_var_get_axis_infos (face, 0, nullptr, nullptr);
1164 axes = (hb_ot_var_axis_info_t *) calloc (count, sizeof (hb_ot_var_axis_info_t));
1165 hb_ot_var_get_axis_infos (face, 0, &count, axes);
1166
1167 bool has_hidden = false;
1168
1169 if (verbose && count)
1170 {
1171 printf ("Varitation axes:\n\n");
1172 printf ("Tag Minimum Default Maximum Name\n------------------------------------\n");
1173 }
1174 for (unsigned i = 0; i < count; i++)
1175 {
1176 const auto &axis = axes[i];
1177 if (axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN)
1178 has_hidden = true;
1179
1180 char name[128];
1181 unsigned name_len = sizeof name;
1182
1183 _hb_ot_name_get_utf8 (face, axis.name_id,
1184 language,
1185 &name_len, name);
1186
1187 printf ("%c%c%c%c%s %g %g %g %s\n",
1188 HB_UNTAG (axis.tag),
1189 axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN ? "*" : "",
1190 (double) axis.min_value,
1191 (double) axis.default_value,
1192 (double) axis.max_value,
1193 name);
1194 }
1195 if (verbose && has_hidden)
1196 printf ("\n[*] Hidden axis\n");
1197
1198 free (axes);
1199 axes = nullptr;
1200
1201 count = hb_ot_var_get_named_instance_count (face);
1202 if (count)
1203 {
1204 if (verbose)
1205 {
1206 printf ("\n\nNamed instances:\n\n");
1207 printf ("Index Name Position\n------------------------------------------------\n");
1208 }
1209
1210 for (unsigned i = 0; i < count; i++)
1211 {
1212 char name[128];
1213 unsigned name_len = sizeof name;
1214
1215 hb_ot_name_id_t name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
1216 _hb_ot_name_get_utf8 (face, name_id,
1217 language,
1218 &name_len, name);
1219
1220 unsigned coords_count = hb_ot_var_named_instance_get_design_coords (face, i, nullptr, nullptr);
1221 float* coords;
1222 coords = (float *) calloc (coords_count, sizeof (float));
1223 hb_ot_var_named_instance_get_design_coords (face, i, &coords_count, coords);
1224
1225 printf ("%u %-32s", i, name);
1226 for (unsigned j = 0; j < coords_count; j++)
1227 printf ("%g, ", (double) coords[j]);
1228 printf ("\n");
1229
1230 free (coords);
1231 }
1232 }
1233 }
1234 #endif
1235
1236 #ifdef HAVE_CHAFA
1237 GString *
_palette_chafa_strinfo_t1238 _palette_chafa_str (unsigned palette_index)
1239 {
1240 unsigned count = hb_ot_color_palette_get_colors (face, palette_index, 0,
1241 nullptr, nullptr);
1242
1243 hb_color_t *palette = (hb_color_t *) malloc (count * sizeof (hb_color_t));
1244 hb_ot_color_palette_get_colors (face, palette_index, 0,
1245 &count, palette);
1246
1247 #define REPEAT 16
1248 hb_color_t *data = (hb_color_t *) malloc (count * REPEAT * sizeof (hb_color_t));
1249 for (unsigned i = 0; i < count; i++)
1250 for (unsigned j = 0; j < REPEAT; j++)
1251 data[i * REPEAT + j] = palette[i];
1252 free (palette);
1253 palette = nullptr;
1254
1255 chafa_set_n_threads (1); // https://github.com/hpjansson/chafa/issues/125#issuecomment-1397475217
1256 //
1257 gchar **environ = g_get_environ ();
1258 ChafaTermInfo *term_info = chafa_term_db_detect (chafa_term_db_get_default (),
1259 environ);
1260
1261 ChafaCanvasMode mode;
1262 ChafaPixelMode pixel_mode = CHAFA_PIXEL_MODE_SYMBOLS;
1263 if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
1264 mode = CHAFA_CANVAS_MODE_TRUECOLOR;
1265 else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_256))
1266 mode = CHAFA_CANVAS_MODE_INDEXED_240;
1267 else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_16))
1268 mode = CHAFA_CANVAS_MODE_INDEXED_16;
1269 else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_INVERT_COLORS))
1270 mode = CHAFA_CANVAS_MODE_FGBG_BGFG;
1271 else
1272 mode = CHAFA_CANVAS_MODE_FGBG;
1273
1274 ChafaSymbolMap *symbol_map = chafa_symbol_map_new ();
1275 chafa_symbol_map_add_by_tags (symbol_map,
1276 (ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK));
1277
1278 ChafaCanvasConfig *config = chafa_canvas_config_new ();
1279 chafa_canvas_config_set_canvas_mode (config, mode);
1280 chafa_canvas_config_set_pixel_mode (config, pixel_mode);
1281 chafa_canvas_config_set_cell_geometry (config, REPEAT, 1);
1282 chafa_canvas_config_set_geometry (config, 2 * count, 1);
1283 chafa_canvas_config_set_symbol_map (config, symbol_map);
1284 chafa_canvas_config_set_color_extractor (config, CHAFA_COLOR_EXTRACTOR_MEDIAN);
1285 chafa_canvas_config_set_work_factor (config, 1.0f);
1286
1287 ChafaCanvas *canvas = chafa_canvas_new (config);
1288 chafa_canvas_draw_all_pixels (canvas,
1289 G_BYTE_ORDER == G_BIG_ENDIAN
1290 ? CHAFA_PIXEL_BGRA8_UNASSOCIATED
1291 : CHAFA_PIXEL_ARGB8_UNASSOCIATED,
1292 (const guint8 *) data,
1293 count * REPEAT,
1294 1,
1295 sizeof (hb_color_t));
1296
1297 free (data);
1298
1299 auto gs = chafa_canvas_print (canvas, term_info);
1300
1301 chafa_canvas_unref (canvas);
1302 chafa_canvas_config_unref (config);
1303 chafa_symbol_map_unref (symbol_map);
1304 chafa_term_info_unref (term_info);
1305 g_strfreev (environ);
1306
1307 return gs;
1308 }
1309 #endif
1310
1311 void
_list_palettesinfo_t1312 _list_palettes ()
1313 {
1314 if (verbose)
1315 {
1316 separator ();
1317 printf ("Color palettes information:\n");
1318 }
1319
1320 {
1321 if (verbose)
1322 {
1323 printf ("\nPalettes:\n\n");
1324 printf ("Index Flags Name\n--------------------\n");
1325 }
1326 unsigned count = hb_ot_color_palette_get_count (face);
1327 for (unsigned i = 0; i < count; i++)
1328 {
1329 hb_ot_name_id_t name_id = hb_ot_color_palette_get_name_id (face, i);
1330 hb_ot_color_palette_flags_t flags = hb_ot_color_palette_get_flags (face, i);
1331
1332 char name[128];
1333 unsigned name_len = sizeof name;
1334
1335 _hb_ot_name_get_utf8 (face, name_id,
1336 language,
1337 &name_len, name);
1338 const char *type = "";
1339 if (flags)
1340 {
1341 if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND)
1342 {
1343 if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND)
1344 type = "Both";
1345 else
1346 type = "Light";
1347 }
1348 else {
1349 type = "Dark";
1350 }
1351 }
1352
1353 #ifdef HAVE_CHAFA
1354 char *chafa_env = getenv ("HB_CHAFA");
1355 bool use_chafa = !chafa_env || atoi (chafa_env);
1356 if (verbose && use_chafa && isatty (fileno (stdout)))
1357 {
1358 GString *chafa_str = _palette_chafa_str (i);
1359 printf ("%u %s %-23s %*s\n", i, type, name,
1360 (int) chafa_str->len, chafa_str->str);
1361 g_string_free (chafa_str, TRUE);
1362 }
1363 else
1364 #endif
1365 printf ("%u %s %s\n", i, type, name);
1366 }
1367 }
1368
1369 {
1370 if (verbose)
1371 {
1372 printf ("\nColors:\n\n");
1373 printf ("Index Name\n------------\n");
1374 }
1375 unsigned count = hb_ot_color_palette_get_colors (face, 0, 0, nullptr, nullptr);
1376 for (unsigned i = 0; i < count; i++)
1377 {
1378 hb_ot_name_id_t name_id = hb_ot_color_palette_color_get_name_id (face, i);
1379
1380 char name[128];
1381 unsigned name_len = sizeof name;
1382 _hb_ot_name_get_utf8 (face, name_id,
1383 language,
1384 &name_len, name);
1385
1386 printf ("%u %s\n", i, name);
1387 }
1388 }
1389 }
1390
1391 void
_list_metainfo_t1392 _list_meta ()
1393 {
1394 if (verbose)
1395 {
1396 separator ();
1397 printf ("Meta information:\n");
1398 }
1399
1400 {
1401 if (verbose)
1402 {
1403 printf ("\nTag Data\n------------\n");
1404 }
1405 unsigned count = hb_ot_meta_get_entry_tags (face, 0, nullptr, nullptr);
1406 for (unsigned i = 0; i < count; i++)
1407 {
1408 hb_ot_meta_tag_t tag;
1409 unsigned len = 1;
1410 hb_ot_meta_get_entry_tags (face, i, &len, &tag);
1411
1412 hb_blob_t *blob = hb_ot_meta_reference_entry (face, tag);
1413
1414 printf ("%c%c%c%c %.*s\n", HB_UNTAG (tag),
1415 (int) hb_blob_get_length (blob),
1416 hb_blob_get_data (blob, nullptr));
1417
1418 hb_blob_destroy (blob);
1419 }
1420 }
1421 }
1422
1423 };
1424
1425
1426 template <typename consumer_t,
1427 typename font_options_type>
1428 struct main_font_t :
1429 option_parser_t,
1430 font_options_type,
1431 consumer_t
1432 {
operator ()main_font_t1433 int operator () (int argc, char **argv)
1434 {
1435 add_options ();
1436
1437 if (argc == 2)
1438 consumer_t::show_all = true;
1439
1440 parse (&argc, &argv);
1441
1442 consumer_t::operator () (this);
1443
1444 return 0;
1445 }
1446 };
1447
1448 int
main(int argc,char ** argv)1449 main (int argc, char **argv)
1450 {
1451 return batch_main<info_t> (argc, argv);
1452 }
1453