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 printf ("Face count: %u\n", hb_face_count (blob));
353 }
354
355 void
_show_nameinfo_t356 _show_name (const char *label, hb_ot_name_id_t name_id)
357 {
358 if (verbose)
359 {
360 printf ("%s: ", label);
361 }
362
363 char name[16384];
364 unsigned name_len = sizeof name;
365 _hb_ot_name_get_utf8 (face, name_id,
366 language,
367 &name_len, name);
368
369 printf ("%s\n", name);
370 }
_show_familyinfo_t371 void _show_family () { _show_name ("Family", 1); }
_show_subfamilyinfo_t372 void _show_subfamily ()
373 {
374 hb_ot_name_id_t name_id = 2;
375
376 unsigned named_instance = hb_font_get_var_named_instance (font);
377 if (named_instance != HB_FONT_NO_VAR_NAMED_INSTANCE)
378 name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, named_instance);
379
380 _show_name ("Subfamily", name_id);
381 }
_show_unique_nameinfo_t382 void _show_unique_name () { _show_name ("Unique name", 3); }
_show_full_nameinfo_t383 void _show_full_name () { _show_name ("Full name", 4); }
_show_postscript_nameinfo_t384 void _show_postscript_name ()
385 {
386 hb_ot_name_id_t name_id = 6;
387
388 unsigned named_instance = hb_font_get_var_named_instance (font);
389 if (named_instance != HB_FONT_NO_VAR_NAMED_INSTANCE)
390 name_id = hb_ot_var_named_instance_get_postscript_name_id (face, named_instance);
391
392
393 _show_name ("Postscript name", name_id);
394 }
_show_versioninfo_t395 void _show_version () { _show_name ("Version", 5); }
396
_has_blobinfo_t397 bool _has_blob (hb_tag_t tag)
398 {
399 hb_blob_t *blob = hb_face_reference_table (face, tag);
400 bool ret = hb_blob_get_length (blob);
401 hb_blob_destroy (blob);
402 return ret;
403 }
404
_show_technologyinfo_t405 void _show_technology ()
406 {
407 if (_has_blob (HB_TAG('g','l','y','f')))
408 printf ("Has TrueType outlines\n");
409 if (_has_blob (HB_TAG('C','F','F',' ')) || _has_blob (HB_TAG('C','F','F','2')))
410 printf ("Has Postscript outlines\n");
411
412 if (_has_blob (HB_TAG('f','p','g','m')) || _has_blob (HB_TAG('p','r','e','p')) || _has_blob (HB_TAG('c','v','t',' ')))
413 printf ("Has TrueType hinting\n");
414
415 if (_has_blob (HB_TAG('G','S','U','B')) || _has_blob (HB_TAG('G','P','O','S')))
416 printf ("Has OpenType layout\n");
417 if (_has_blob (HB_TAG('m','o','r','x')) || _has_blob (HB_TAG('k','e','r','x')))
418 printf ("Has AAT layout\n");
419 if (_has_blob (HB_TAG('S','i','l','f')))
420 printf ("Has Graphite layout\n");
421 if (_has_blob (HB_TAG('k','e','r','n')))
422 printf ("Has legacy kerning\n");
423
424 if (_has_blob (HB_TAG('E','B','D','T')))
425 printf ("Has monochrome bitmaps\n");
426
427 if (_has_blob (HB_TAG('C','B','D','T')) || _has_blob (HB_TAG('s','b','i','x')))
428 printf ("Has color bitmaps\n");
429 if (_has_blob (HB_TAG('S','V','G',' ')))
430 printf ("Has color SVGs\n");
431 if (_has_blob (HB_TAG('C','O','L','R')))
432 printf ("Has color paintings\n");
433
434 if (_has_blob (HB_TAG('f','v','a','r'))) printf ("Has variations\n");
435 }
436
_show_unicode_countinfo_t437 void _show_unicode_count ()
438 {
439 if (verbose)
440 {
441 printf ("Unicode count: ");
442 }
443
444 hb_set_t *unicodes = hb_set_create ();
445 hb_face_collect_unicodes (face, unicodes);
446
447 printf ("%u\n", hb_set_get_population (unicodes));
448
449 hb_set_destroy (unicodes);
450 }
451
_show_glyph_countinfo_t452 void _show_glyph_count ()
453 {
454 if (verbose)
455 {
456 printf ("Glyph count: ");
457 }
458
459 printf ("%u\n", hb_face_get_glyph_count (face));
460 }
461
_show_upeminfo_t462 void _show_upem ()
463 {
464 if (verbose)
465 {
466 printf ("Units-Per-EM: ");
467 }
468
469 printf ("%u\n", hb_face_get_upem (face));
470 }
471
_show_extentsinfo_t472 void _show_extents ()
473 {
474 hb_font_extents_t extents;
475 hb_font_get_extents_for_direction (font, direction, &extents);
476
477 if (verbose) printf ("Ascender: ");
478 printf ("%d\n", extents.ascender);
479
480 if (verbose) printf ("Descender: ");
481 printf ("%d\n", extents.descender);
482
483 if (verbose) printf ("Line gap: ");
484 printf ("%d\n", extents.line_gap);
485 }
486
_get_nameinfo_t487 void _get_name ()
488 {
489 for (char **p = get_name; *p; p++)
490 {
491 hb_ot_name_id_t name_id = (hb_ot_name_id_t) atoi (*p);
492 _show_name (*p, name_id);
493 }
494 }
495
_get_styleinfo_t496 void _get_style ()
497 {
498 for (char **p = get_style; *p; p++)
499 {
500 hb_style_tag_t tag = (hb_style_tag_t) hb_tag_from_string (*p, -1);
501
502 if (verbose)
503 printf ("Style %c%c%c%c: ", HB_UNTAG (tag));
504
505 float v = hb_style_get_value (font, tag);
506 printf ("%g\n", (double) v);
507 }
508 }
509
_get_metricinfo_t510 void _get_metric ()
511 {
512 bool fallback = false;
513 for (char **p = get_metric; *p; p++)
514 {
515 hb_ot_metrics_tag_t tag = (hb_ot_metrics_tag_t) hb_tag_from_string (*p, -1);
516 hb_position_t position;
517
518 if (verbose)
519 printf ("Metric %c%c%c%c: ", HB_UNTAG (tag));
520
521 if (hb_ot_metrics_get_position (font, tag, &position))
522 printf ("%d \n", position);
523 else
524 {
525 hb_ot_metrics_get_position_with_fallback (font, tag, &position);
526 printf ("%d *\n", position);
527 fallback = true;
528 }
529 }
530
531 if (verbose && fallback)
532 {
533 printf ("\n[*] Fallback value\n");
534 }
535 }
536
_get_baselineinfo_t537 void _get_baseline ()
538 {
539 hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
540 hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
541 unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
542 unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
543
544 hb_ot_tags_from_script_and_language (script, language,
545 &script_count, script_tags,
546 &language_count, language_tags);
547
548 hb_tag_t script_tag = script_count ? script_tags[script_count - 1] : HB_TAG_NONE;
549 hb_tag_t language_tag = language_count ? language_tags[0] : HB_TAG_NONE;
550
551 if (ot_script_str)
552 script_tag = hb_tag_from_string (ot_script_str, -1);
553 if (ot_language_str)
554 language_tag = hb_tag_from_string (ot_language_str, -1);
555
556
557 bool fallback = false;
558 for (char **p = get_baseline; *p; p++)
559 {
560 hb_ot_layout_baseline_tag_t tag = (hb_ot_layout_baseline_tag_t) hb_tag_from_string (*p, -1);
561 hb_position_t position;
562
563 if (verbose)
564 printf ("Baseline %c%c%c%c: ", HB_UNTAG (tag));
565
566 if (hb_ot_layout_get_baseline (font, tag, direction, script_tag, language_tag, &position))
567 printf ("%d \n", position);
568 else
569 {
570 hb_ot_layout_get_baseline_with_fallback (font, tag, direction, script_tag, language_tag, &position);
571 printf ("%d *\n", position);
572 fallback = true;
573 }
574 }
575
576 if (verbose && fallback)
577 {
578 printf ("\n[*] Fallback value\n");
579 }
580 }
581
_get_metainfo_t582 void _get_meta ()
583 {
584 for (char **p = get_meta; *p; p++)
585 {
586 hb_ot_meta_tag_t tag = (hb_ot_meta_tag_t) hb_tag_from_string (*p, -1);
587
588 hb_blob_t *blob = hb_ot_meta_reference_entry (face, tag);
589
590 if (verbose)
591 printf ("Meta %c%c%c%c: ", HB_UNTAG (tag));
592
593 printf ("%.*s\n",
594 (int) hb_blob_get_length (blob),
595 hb_blob_get_data (blob, nullptr));
596
597 hb_blob_destroy (blob);
598 }
599 }
600
601 void
_get_tableinfo_t602 _get_table ()
603 {
604 hb_blob_t *blob = hb_face_reference_table (face, hb_tag_from_string (get_table, -1));
605 unsigned count = 0;
606 const char *data = hb_blob_get_data (blob, &count);
607 fwrite (data, 1, count, stdout);
608 hb_blob_destroy (blob);
609 }
610
_list_namesinfo_t611 void _list_names ()
612 {
613 if (verbose)
614 {
615 separator ();
616 printf ("Name information:\n\n");
617 printf ("Id: Name Text\n------------------------------------\n");
618 }
619
620 #ifdef HB_HAS_GOBJECT
621 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_NAME_ID_PREDEFINED);
622 #endif
623
624 unsigned count;
625 const auto *entries = hb_ot_name_list_names (face, &count);
626 for (unsigned i = 0; i < count; i++)
627 {
628 char name[16384];
629 unsigned name_len = sizeof name;
630 _hb_ot_name_get_utf8 (face, entries[i].name_id,
631 language,
632 &name_len, name);
633
634 #ifdef HB_HAS_GOBJECT
635 if (verbose)
636 {
637 GEnumValue *enum_value = g_enum_get_value (enum_class, entries[i].name_id);
638 printf ("%u: %-27s %s\n", entries[i].name_id, enum_value ? enum_value->value_nick : "", name);
639 }
640 else
641 #endif
642 printf ("%u %s\n", entries[i].name_id, name);
643 }
644 }
645
646 #ifdef HB_HAS_GOBJECT
_list_styleinfo_t647 void _list_style ()
648 {
649 if (verbose)
650 {
651 separator ();
652 printf ("Style information:\n\n");
653 printf ("Tag: Name Value\n---------------------------------------------\n");
654 }
655
656 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_STYLE_TAG);
657
658 unsigned count = enum_class->n_values;
659 const auto *entries = enum_class->values;
660 for (unsigned i = 0; i < count; i++)
661 {
662 float v = hb_style_get_value (font, (hb_style_tag_t) entries[i].value);
663 printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
664 if (verbose)
665 printf (": %-33s", entries[i].value_nick);
666 printf (" %g\n", (double) v);
667 }
668 }
669
_list_metricsinfo_t670 void _list_metrics ()
671 {
672 if (verbose)
673 {
674 separator ();
675 printf ("Metrics information:\n\n");
676 printf ("Tag: Name Value\n---------------------------------------------\n");
677 }
678
679 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_METRICS_TAG);
680
681 bool any_fallback = false;
682
683 unsigned count = enum_class->n_values;
684 const auto *entries = enum_class->values;
685 for (unsigned i = 0; i < count; i++)
686 {
687 bool fallback = false;
688 hb_position_t v;
689 if (!hb_ot_metrics_get_position (font,
690 (hb_ot_metrics_tag_t) entries[i].value,
691 &v))
692 {
693 hb_ot_metrics_get_position_with_fallback (font,
694 (hb_ot_metrics_tag_t) entries[i].value,
695 &v);
696 any_fallback = fallback = true;
697 }
698 printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
699 if (verbose)
700 printf (": %-33s", entries[i].value_nick);
701 printf (" %d ", v);
702
703 if (fallback)
704 printf ("*");
705 printf ("\n");
706 }
707
708 if (verbose && any_fallback)
709 {
710 printf ("\n[*] Fallback value\n");
711 }
712 }
713
_list_baselinesinfo_t714 void _list_baselines ()
715 {
716 hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
717 hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
718 unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
719 unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
720
721 hb_ot_tags_from_script_and_language (script, language,
722 &script_count, script_tags,
723 &language_count, language_tags);
724
725 hb_tag_t script_tag = script_count ? script_tags[script_count - 1] : HB_TAG_NONE;
726 hb_tag_t language_tag = language_count ? language_tags[0] : HB_TAG_NONE;
727
728 if (ot_script_str)
729 script_tag = hb_tag_from_string (ot_script_str, -1);
730 if (ot_language_str)
731 language_tag = hb_tag_from_string (ot_language_str, -1);
732
733
734 if (verbose)
735 {
736 separator ();
737 printf ("Baselines information:\n\n");
738 printf ("Tag: Name Value\n---------------------------------------------\n");
739 }
740
741 GEnumClass *enum_class = (GEnumClass *) g_type_class_ref ((GType) HB_GOBJECT_TYPE_OT_LAYOUT_BASELINE_TAG);
742
743 bool any_fallback = false;
744
745 unsigned count = enum_class->n_values;
746 const auto *entries = enum_class->values;
747 for (unsigned i = 0; i < count; i++)
748 {
749 bool fallback = false;
750 hb_position_t v;
751 if (!hb_ot_layout_get_baseline (font, (hb_ot_layout_baseline_tag_t) entries[i].value,
752 direction, script_tag, language_tag,
753 &v))
754 {
755 hb_ot_layout_get_baseline_with_fallback (font, (hb_ot_layout_baseline_tag_t) entries[i].value,
756 direction, script_tag, language_tag,
757 &v);
758 any_fallback = fallback = true;
759 }
760 printf ("%c%c%c%c", HB_UNTAG(entries[i].value));
761 if (verbose)
762 printf (": %-33s", entries[i].value_nick);
763 printf (" %d ", v);
764
765 if (fallback)
766 printf ("*");
767 printf ("\n");
768 }
769
770 if (verbose && any_fallback)
771 {
772 printf ("\n[*] Fallback value\n");
773 }
774 }
775 #endif
776
_list_tablesinfo_t777 void _list_tables ()
778 {
779 if (verbose)
780 {
781 separator ();
782 printf ("Table information:\n\n");
783 printf ("Tag Size\n------------\n");
784 }
785
786 unsigned count = hb_face_get_table_tags (face, 0, nullptr, nullptr);
787 hb_tag_t *tags = (hb_tag_t *) calloc (count, sizeof (hb_tag_t));
788 hb_face_get_table_tags (face, 0, &count, tags);
789
790 for (unsigned i = 0; i < count; i++)
791 {
792 hb_tag_t tag = tags[i];
793
794 hb_blob_t *blob = hb_face_reference_table (face, tag);
795
796 printf ("%c%c%c%c %8u bytes\n", HB_UNTAG (tag), hb_blob_get_length (blob));
797
798 hb_blob_destroy (blob);
799 }
800
801 free (tags);
802 }
803
804 void
_list_unicodesinfo_t805 _list_unicodes ()
806 {
807 if (verbose)
808 {
809 separator ();
810 printf ("Character-set information:\n\n");
811 printf ("Unicode Glyph name\n------------------\n");
812 }
813
814 hb_set_t *unicodes = hb_set_create ();
815 hb_map_t *cmap = hb_map_create ();
816
817 hb_face_collect_nominal_glyph_mapping (face, cmap, unicodes);
818
819 for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
820 hb_set_next (unicodes, &u);)
821 {
822 hb_codepoint_t gid = hb_map_get (cmap, u);
823
824 char glyphname[64];
825 hb_font_glyph_to_string (font, gid,
826 glyphname, sizeof glyphname);
827
828 printf ("U+%04X %s\n", u, glyphname);
829 }
830
831 hb_map_destroy (cmap);
832
833
834 /* List variation-selector sequences. */
835 hb_set_t *vars = hb_set_create ();
836
837 hb_face_collect_variation_selectors (face, vars);
838
839 for (hb_codepoint_t vs = HB_SET_VALUE_INVALID;
840 hb_set_next (vars, &vs);)
841 {
842 hb_set_clear (unicodes);
843 hb_face_collect_variation_unicodes (face, vs, unicodes);
844
845 for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
846 hb_set_next (unicodes, &u);)
847 {
848 hb_codepoint_t gid = 0;
849 HB_UNUSED bool b = hb_font_get_variation_glyph (font, u, vs, &gid);
850 assert (b);
851
852 char glyphname[64];
853 hb_font_glyph_to_string (font, gid,
854 glyphname, sizeof glyphname);
855
856 printf ("U+%04X,U+%04X %s\n", vs, u, glyphname);
857 }
858 }
859
860 hb_set_destroy (vars);
861 hb_set_destroy (unicodes);
862 }
863
864 void
_list_glyphsinfo_t865 _list_glyphs ()
866 {
867 if (verbose)
868 {
869 separator ();
870 printf ("Glyph-set information:\n\n");
871 printf ("GlyphID Glyph name\n------------------\n");
872 }
873
874 unsigned num_glyphs = hb_face_get_glyph_count (face);
875
876 for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
877 {
878 char glyphname[64];
879 hb_font_glyph_to_string (font, gid,
880 glyphname, sizeof glyphname);
881
882 printf ("%u %s\n", gid, glyphname);
883 }
884 }
885
886 void
_list_scriptsinfo_t887 _list_scripts ()
888 {
889 if (verbose)
890 {
891 separator ();
892 printf ("Layout script information:\n\n");
893 }
894
895 hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
896
897 for (unsigned int i = 0; table_tags[i]; i++)
898 {
899 if (verbose) printf ("Table: ");
900 printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
901
902 hb_tag_t script_array[32];
903 unsigned script_count = sizeof script_array / sizeof script_array[0];
904 unsigned script_offset = 0;
905 do
906 {
907 hb_ot_layout_table_get_script_tags (face, table_tags[i],
908 script_offset,
909 &script_count,
910 script_array);
911
912 for (unsigned script_index = 0; script_index < script_count; script_index++)
913 {
914 printf (" ");
915 if (verbose) printf ("Script: ");
916
917 hb_tag_t hb_sc = hb_script_to_iso15924_tag (hb_ot_tag_to_script (script_array[script_index]));
918 if (script_array[script_index] == HB_TAG ('D','F','L','T'))
919 hb_sc = HB_SCRIPT_COMMON;
920
921 printf ("%c%c%c%c (%c%c%c%c)\n",
922 HB_UNTAG (hb_sc),
923 HB_UNTAG (script_array[script_index]));
924
925 hb_tag_t language_array[32];
926 unsigned language_count = sizeof language_array / sizeof language_array[0];
927 unsigned language_offset = 0;
928 do
929 {
930 hb_ot_layout_script_get_language_tags (face, table_tags[i],
931 script_offset + script_index,
932 language_offset,
933 &language_count,
934 language_array);
935
936 for (unsigned language_index = 0; language_index < language_count; language_index++)
937 {
938 printf (" ");
939 if (verbose) printf ("Language: ");
940 printf ("%s (%c%c%c%c)\n",
941 hb_language_to_string (hb_ot_tag_to_language (language_array[language_index])),
942 HB_UNTAG (language_array[language_index]));
943 }
944
945 language_offset += language_count;
946 }
947 while (language_count == sizeof language_array / sizeof language_array[0]);
948 }
949
950 script_offset += script_count;
951 }
952 while (script_count == sizeof script_array / sizeof script_array[0]);
953
954 }
955
956 }
957
958 void
_list_features_no_scriptinfo_t959 _list_features_no_script ()
960 {
961 if (verbose)
962 {
963 printf ("Showing all font features with duplicates removed.\n\n");
964 }
965
966 hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
967
968 hb_set_t *features = hb_set_create ();
969
970 for (unsigned int i = 0; table_tags[i]; i++)
971 {
972 if (verbose) printf ("Table: ");
973 printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
974
975 hb_set_clear (features);
976 hb_tag_t feature_array[32];
977 unsigned feature_count = sizeof feature_array / sizeof feature_array[0];
978 unsigned feature_offset = 0;
979 do
980 {
981 hb_ot_layout_table_get_feature_tags (face, table_tags[i],
982 feature_offset,
983 &feature_count,
984 feature_array);
985
986 for (unsigned feature_index = 0; feature_index < feature_count; feature_index++)
987 {
988 if (hb_set_has (features, feature_array[feature_index]))
989 continue;
990 hb_set_add (features, feature_array[feature_index]);
991
992 hb_ot_name_id_t label_id;
993
994 hb_ot_layout_feature_get_name_ids (face,
995 table_tags[i],
996 feature_offset + feature_index,
997 &label_id,
998 nullptr,
999 nullptr,
1000 nullptr,
1001 nullptr);
1002
1003 char name[64];
1004 unsigned name_len = sizeof name;
1005
1006 _hb_ot_name_get_utf8 (face, label_id,
1007 language,
1008 &name_len, name);
1009
1010 printf (" ");
1011 if (verbose) printf ("Feature: ");
1012 printf ("%c%c%c%c", HB_UNTAG (feature_array[feature_index]));
1013
1014 if (*name)
1015 printf (" %s", name);
1016
1017 printf ("\n");
1018 }
1019
1020 feature_offset += feature_count;
1021 }
1022 while (feature_count == sizeof feature_array / sizeof feature_array[0]);
1023 }
1024
1025 hb_set_destroy (features);
1026 }
1027
1028 void
_list_featuresinfo_t1029 _list_features ()
1030 {
1031 if (verbose)
1032 {
1033 separator ();
1034 printf ("Layout features information:\n\n");
1035 }
1036
1037 hb_tag_t table_tags[] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS, HB_TAG_NONE};
1038
1039 if (script == HB_SCRIPT_INVALID && !ot_script_str)
1040 {
1041 _list_features_no_script ();
1042 return;
1043 }
1044
1045 for (unsigned int i = 0; table_tags[i]; i++)
1046 {
1047 if (verbose) printf ("Table: ");
1048 printf ("%c%c%c%c\n", HB_UNTAG (table_tags[i]));
1049
1050 auto table_tag = table_tags[i];
1051
1052 hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
1053 hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
1054 unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
1055 unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
1056
1057 hb_ot_tags_from_script_and_language (script, language,
1058 &script_count, script_tags,
1059 &language_count, language_tags);
1060
1061 if (ot_script_str)
1062 {
1063 script_tags[0] = hb_tag_from_string (ot_script_str, -1);
1064 script_count = 1;
1065 }
1066 if (ot_language_str)
1067 {
1068 language_tags[0] = hb_tag_from_string (ot_language_str, -1);
1069 language_count = 1;
1070 }
1071
1072 unsigned script_index;
1073 hb_tag_t chosen_script;
1074 hb_ot_layout_table_select_script (face, table_tag,
1075 script_count, script_tags,
1076 &script_index, &chosen_script);
1077
1078 unsigned language_index;
1079 hb_tag_t chosen_language;
1080 hb_ot_layout_script_select_language2 (face, table_tag,
1081 script_index,
1082 language_count, language_tags,
1083 &language_index, &chosen_language);
1084
1085 if (verbose)
1086 {
1087 if (chosen_script)
1088 {
1089 printf (" Script: %c%c%c%c\n", HB_UNTAG (chosen_script));
1090 if (chosen_language)
1091 printf (" Language: %c%c%c%c\n", HB_UNTAG (chosen_language));
1092 else
1093 printf (" Language: Default\n");
1094 }
1095 }
1096
1097 unsigned feature_array[32];
1098 unsigned feature_count = sizeof feature_array / sizeof feature_array[0];
1099 unsigned feature_offset = 0;
1100 do
1101 {
1102 hb_ot_layout_language_get_feature_indexes (face, table_tag,
1103 script_index, language_index,
1104 feature_offset,
1105 &feature_count,
1106 feature_array);
1107
1108 for (unsigned feature_index = 0; feature_index < feature_count; feature_index++)
1109 {
1110 hb_ot_name_id_t label_id;
1111
1112 hb_ot_layout_feature_get_name_ids (face,
1113 table_tags[i],
1114 feature_array[feature_index],
1115 &label_id,
1116 nullptr,
1117 nullptr,
1118 nullptr,
1119 nullptr);
1120
1121 char name[64];
1122 unsigned name_len = sizeof name;
1123
1124 _hb_ot_name_get_utf8 (face, label_id,
1125 language,
1126 &name_len, name);
1127
1128 printf (" ");
1129 if (verbose) printf ("Feature: ");
1130 hb_tag_t feature_tag;
1131 unsigned f_count = 1;
1132 hb_ot_layout_table_get_feature_tags (face, table_tag,
1133 feature_array[feature_index],
1134 &f_count, &feature_tag);
1135 printf ("%c%c%c%c", HB_UNTAG (feature_tag));
1136
1137 if (*name)
1138 printf (" %s", name);
1139
1140 printf ("\n");
1141 }
1142
1143 feature_offset += feature_count;
1144 }
1145 while (feature_count == sizeof feature_array / sizeof feature_array[0]);
1146 }
1147 }
1148
1149 #ifndef HB_NO_VAR
1150 void
_list_variationsinfo_t1151 _list_variations ()
1152 {
1153 if (verbose)
1154 {
1155 separator ();
1156 printf ("Variations information:\n\n");
1157 }
1158
1159 hb_ot_var_axis_info_t *axes;
1160
1161 unsigned count = hb_ot_var_get_axis_infos (face, 0, nullptr, nullptr);
1162 axes = (hb_ot_var_axis_info_t *) calloc (count, sizeof (hb_ot_var_axis_info_t));
1163 hb_ot_var_get_axis_infos (face, 0, &count, axes);
1164
1165 bool has_hidden = false;
1166
1167 if (verbose && count)
1168 {
1169 printf ("Varitation axes:\n\n");
1170 printf ("Tag Minimum Default Maximum Name\n------------------------------------\n");
1171 }
1172 for (unsigned i = 0; i < count; i++)
1173 {
1174 const auto &axis = axes[i];
1175 if (axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN)
1176 has_hidden = true;
1177
1178 char name[64];
1179 unsigned name_len = sizeof name;
1180
1181 _hb_ot_name_get_utf8 (face, axis.name_id,
1182 language,
1183 &name_len, name);
1184
1185 printf ("%c%c%c%c%s %g %g %g %s\n",
1186 HB_UNTAG (axis.tag),
1187 axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN ? "*" : "",
1188 (double) axis.min_value,
1189 (double) axis.default_value,
1190 (double) axis.max_value,
1191 name);
1192 }
1193 if (verbose && has_hidden)
1194 printf ("\n[*] Hidden axis\n");
1195
1196 free (axes);
1197 axes = nullptr;
1198
1199 count = hb_ot_var_get_named_instance_count (face);
1200 if (count)
1201 {
1202 if (verbose)
1203 {
1204 printf ("\n\nNamed instances:\n\n");
1205 printf ("Index Name Position\n------------------------------------------------\n");
1206 }
1207
1208 for (unsigned i = 0; i < count; i++)
1209 {
1210 char name[64];
1211 unsigned name_len = sizeof name;
1212
1213 hb_ot_name_id_t name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
1214 _hb_ot_name_get_utf8 (face, name_id,
1215 language,
1216 &name_len, name);
1217
1218 unsigned coords_count = hb_ot_var_named_instance_get_design_coords (face, i, nullptr, nullptr);
1219 float* coords;
1220 coords = (float *) calloc (coords_count, sizeof (float));
1221 hb_ot_var_named_instance_get_design_coords (face, i, &coords_count, coords);
1222
1223 printf ("%u %-32s", i, name);
1224 for (unsigned j = 0; j < coords_count; j++)
1225 printf ("%g, ", (double) coords[j]);
1226 printf ("\n");
1227
1228 free (coords);
1229 }
1230 }
1231 }
1232 #endif
1233
1234 #ifdef HAVE_CHAFA
1235 GString *
_palette_chafa_strinfo_t1236 _palette_chafa_str (unsigned palette_index)
1237 {
1238 unsigned count = hb_ot_color_palette_get_colors (face, palette_index, 0,
1239 nullptr, nullptr);
1240
1241 hb_color_t *palette = (hb_color_t *) malloc (count * sizeof (hb_color_t));
1242 hb_ot_color_palette_get_colors (face, palette_index, 0,
1243 &count, palette);
1244
1245 #define REPEAT 16
1246 hb_color_t *data = (hb_color_t *) malloc (count * REPEAT * sizeof (hb_color_t));
1247 for (unsigned i = 0; i < count; i++)
1248 for (unsigned j = 0; j < REPEAT; j++)
1249 data[i * REPEAT + j] = palette[i];
1250 free (palette);
1251 palette = nullptr;
1252
1253 chafa_set_n_threads (1); // https://github.com/hpjansson/chafa/issues/125#issuecomment-1397475217
1254 //
1255 gchar **environ = g_get_environ ();
1256 ChafaTermInfo *term_info = chafa_term_db_detect (chafa_term_db_get_default (),
1257 environ);
1258
1259 ChafaCanvasMode mode;
1260 ChafaPixelMode pixel_mode = CHAFA_PIXEL_MODE_SYMBOLS;
1261 if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT))
1262 mode = CHAFA_CANVAS_MODE_TRUECOLOR;
1263 else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_256))
1264 mode = CHAFA_CANVAS_MODE_INDEXED_240;
1265 else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_16))
1266 mode = CHAFA_CANVAS_MODE_INDEXED_16;
1267 else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_INVERT_COLORS))
1268 mode = CHAFA_CANVAS_MODE_FGBG_BGFG;
1269 else
1270 mode = CHAFA_CANVAS_MODE_FGBG;
1271
1272 ChafaSymbolMap *symbol_map = chafa_symbol_map_new ();
1273 chafa_symbol_map_add_by_tags (symbol_map,
1274 (ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK));
1275
1276 ChafaCanvasConfig *config = chafa_canvas_config_new ();
1277 chafa_canvas_config_set_canvas_mode (config, mode);
1278 chafa_canvas_config_set_pixel_mode (config, pixel_mode);
1279 chafa_canvas_config_set_cell_geometry (config, REPEAT, 1);
1280 chafa_canvas_config_set_geometry (config, 2 * count, 1);
1281 chafa_canvas_config_set_symbol_map (config, symbol_map);
1282 chafa_canvas_config_set_color_extractor (config, CHAFA_COLOR_EXTRACTOR_MEDIAN);
1283 chafa_canvas_config_set_work_factor (config, 1.0f);
1284
1285 ChafaCanvas *canvas = chafa_canvas_new (config);
1286 chafa_canvas_draw_all_pixels (canvas,
1287 G_BYTE_ORDER == G_BIG_ENDIAN
1288 ? CHAFA_PIXEL_BGRA8_UNASSOCIATED
1289 : CHAFA_PIXEL_ARGB8_UNASSOCIATED,
1290 (const guint8 *) data,
1291 count * REPEAT,
1292 1,
1293 sizeof (hb_color_t));
1294
1295 free (data);
1296
1297 auto gs = chafa_canvas_print (canvas, term_info);
1298
1299 chafa_canvas_unref (canvas);
1300 chafa_canvas_config_unref (config);
1301 chafa_symbol_map_unref (symbol_map);
1302 chafa_term_info_unref (term_info);
1303 g_strfreev (environ);
1304
1305 return gs;
1306 }
1307 #endif
1308
1309 void
_list_palettesinfo_t1310 _list_palettes ()
1311 {
1312 if (verbose)
1313 {
1314 separator ();
1315 printf ("Color palettes information:\n");
1316 }
1317
1318 {
1319 if (verbose)
1320 {
1321 printf ("\nPalettes:\n\n");
1322 printf ("Index Flags Name\n--------------------\n");
1323 }
1324 unsigned count = hb_ot_color_palette_get_count (face);
1325 for (unsigned i = 0; i < count; i++)
1326 {
1327 hb_ot_name_id_t name_id = hb_ot_color_palette_get_name_id (face, i);
1328 hb_ot_color_palette_flags_t flags = hb_ot_color_palette_get_flags (face, i);
1329
1330 char name[64];
1331 unsigned name_len = sizeof name;
1332
1333 _hb_ot_name_get_utf8 (face, name_id,
1334 language,
1335 &name_len, name);
1336 const char *type = "";
1337 if (flags)
1338 {
1339 if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND)
1340 {
1341 if (flags & HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND)
1342 type = "Both";
1343 else
1344 type = "Light";
1345 }
1346 else {
1347 type = "Dark";
1348 }
1349 }
1350
1351 #ifdef HAVE_CHAFA
1352 char *chafa_env = getenv ("HB_CHAFA");
1353 bool use_chafa = !chafa_env || atoi (chafa_env);
1354 if (verbose && use_chafa && isatty (fileno (stdout)))
1355 {
1356 GString *chafa_str = _palette_chafa_str (i);
1357 printf ("%u %s %-23s %*s\n", i, type, name,
1358 (int) chafa_str->len, chafa_str->str);
1359 g_string_free (chafa_str, TRUE);
1360 }
1361 else
1362 #endif
1363 printf ("%u %s %s\n", i, type, name);
1364 }
1365 }
1366
1367 {
1368 if (verbose)
1369 {
1370 printf ("\nColors:\n\n");
1371 printf ("Index Name\n------------\n");
1372 }
1373 unsigned count = hb_ot_color_palette_get_colors (face, 0, 0, nullptr, nullptr);
1374 for (unsigned i = 0; i < count; i++)
1375 {
1376 hb_ot_name_id_t name_id = hb_ot_color_palette_color_get_name_id (face, i);
1377
1378 char name[64];
1379 unsigned name_len = sizeof name;
1380 _hb_ot_name_get_utf8 (face, name_id,
1381 language,
1382 &name_len, name);
1383
1384 printf ("%u %s\n", i, name);
1385 }
1386 }
1387 }
1388
1389 void
_list_metainfo_t1390 _list_meta ()
1391 {
1392 if (verbose)
1393 {
1394 separator ();
1395 printf ("Meta information:\n");
1396 }
1397
1398 {
1399 if (verbose)
1400 {
1401 printf ("\nTag Data\n------------\n");
1402 }
1403 unsigned count = hb_ot_meta_get_entry_tags (face, 0, nullptr, nullptr);
1404 for (unsigned i = 0; i < count; i++)
1405 {
1406 hb_ot_meta_tag_t tag;
1407 unsigned len = 1;
1408 hb_ot_meta_get_entry_tags (face, i, &len, &tag);
1409
1410 hb_blob_t *blob = hb_ot_meta_reference_entry (face, tag);
1411
1412 printf ("%c%c%c%c %.*s\n", HB_UNTAG (tag),
1413 (int) hb_blob_get_length (blob),
1414 hb_blob_get_data (blob, nullptr));
1415
1416 hb_blob_destroy (blob);
1417 }
1418 }
1419 }
1420
1421 };
1422
1423
1424 template <typename consumer_t,
1425 typename font_options_type>
1426 struct main_font_t :
1427 option_parser_t,
1428 font_options_type,
1429 consumer_t
1430 {
operator ()main_font_t1431 int operator () (int argc, char **argv)
1432 {
1433 add_options ();
1434
1435 if (argc == 2)
1436 consumer_t::show_all = true;
1437
1438 parse (&argc, &argv);
1439
1440 consumer_t::operator () (this);
1441
1442 return 0;
1443 }
1444 };
1445
1446 int
main(int argc,char ** argv)1447 main (int argc, char **argv)
1448 {
1449 return batch_main<info_t> (argc, argv);
1450 }
1451