xref: /aosp_15_r20/external/harfbuzz_ng/util/hb-subset.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2010  Behdad Esfahbod
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2011,2012  Google, Inc.
4*2d1272b8SAndroid Build Coastguard Worker  *
5*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
6*2d1272b8SAndroid Build Coastguard Worker  *
7*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
8*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
9*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
10*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
11*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
12*2d1272b8SAndroid Build Coastguard Worker  *
13*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
18*2d1272b8SAndroid Build Coastguard Worker  *
19*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24*2d1272b8SAndroid Build Coastguard Worker  *
25*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Garret Rieger, Rod Sheeter
26*2d1272b8SAndroid Build Coastguard Worker  */
27*2d1272b8SAndroid Build Coastguard Worker 
28*2d1272b8SAndroid Build Coastguard Worker #include "batch.hh"
29*2d1272b8SAndroid Build Coastguard Worker #include "face-options.hh"
30*2d1272b8SAndroid Build Coastguard Worker #include "glib.h"
31*2d1272b8SAndroid Build Coastguard Worker #include "main-font-text.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "output-options.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "helper-subset.hh"
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker #include <hb-subset.h>
36*2d1272b8SAndroid Build Coastguard Worker 
preprocess_face(hb_face_t * face)37*2d1272b8SAndroid Build Coastguard Worker static hb_face_t* preprocess_face(hb_face_t* face)
38*2d1272b8SAndroid Build Coastguard Worker {
39*2d1272b8SAndroid Build Coastguard Worker   return hb_subset_preprocess (face);
40*2d1272b8SAndroid Build Coastguard Worker }
41*2d1272b8SAndroid Build Coastguard Worker 
42*2d1272b8SAndroid Build Coastguard Worker /*
43*2d1272b8SAndroid Build Coastguard Worker  * Command line interface to the harfbuzz font subsetter.
44*2d1272b8SAndroid Build Coastguard Worker  */
45*2d1272b8SAndroid Build Coastguard Worker 
46*2d1272b8SAndroid Build Coastguard Worker struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
47*2d1272b8SAndroid Build Coastguard Worker {
subset_main_tsubset_main_t48*2d1272b8SAndroid Build Coastguard Worker   subset_main_t ()
49*2d1272b8SAndroid Build Coastguard Worker   : input (hb_subset_input_create_or_fail ())
50*2d1272b8SAndroid Build Coastguard Worker   {}
~subset_main_tsubset_main_t51*2d1272b8SAndroid Build Coastguard Worker   ~subset_main_t ()
52*2d1272b8SAndroid Build Coastguard Worker   {
53*2d1272b8SAndroid Build Coastguard Worker     hb_subset_input_destroy (input);
54*2d1272b8SAndroid Build Coastguard Worker   }
55*2d1272b8SAndroid Build Coastguard Worker 
parse_facesubset_main_t56*2d1272b8SAndroid Build Coastguard Worker   void parse_face (int argc, const char * const *argv)
57*2d1272b8SAndroid Build Coastguard Worker   {
58*2d1272b8SAndroid Build Coastguard Worker     option_parser_t parser;
59*2d1272b8SAndroid Build Coastguard Worker     face_options_t face_opts;
60*2d1272b8SAndroid Build Coastguard Worker 
61*2d1272b8SAndroid Build Coastguard Worker     face_opts.add_options (&parser);
62*2d1272b8SAndroid Build Coastguard Worker 
63*2d1272b8SAndroid Build Coastguard Worker     GOptionEntry entries[] =
64*2d1272b8SAndroid Build Coastguard Worker     {
65*2d1272b8SAndroid Build Coastguard Worker       {G_OPTION_REMAINING,	0, G_OPTION_FLAG_IN_MAIN,
66*2d1272b8SAndroid Build Coastguard Worker 				G_OPTION_ARG_CALLBACK,	(gpointer) &collect_face,	nullptr,	"[FONT-FILE] [TEXT]"},
67*2d1272b8SAndroid Build Coastguard Worker       {nullptr}
68*2d1272b8SAndroid Build Coastguard Worker     };
69*2d1272b8SAndroid Build Coastguard Worker     parser.add_main_group (entries, &face_opts);
70*2d1272b8SAndroid Build Coastguard Worker     parser.add_options ();
71*2d1272b8SAndroid Build Coastguard Worker 
72*2d1272b8SAndroid Build Coastguard Worker     g_option_context_set_ignore_unknown_options (parser.context, true);
73*2d1272b8SAndroid Build Coastguard Worker     g_option_context_set_help_enabled (parser.context, false);
74*2d1272b8SAndroid Build Coastguard Worker 
75*2d1272b8SAndroid Build Coastguard Worker     char **args = (char **)
76*2d1272b8SAndroid Build Coastguard Worker #if GLIB_CHECK_VERSION (2, 68, 0)
77*2d1272b8SAndroid Build Coastguard Worker       g_memdup2
78*2d1272b8SAndroid Build Coastguard Worker #else
79*2d1272b8SAndroid Build Coastguard Worker       g_memdup
80*2d1272b8SAndroid Build Coastguard Worker #endif
81*2d1272b8SAndroid Build Coastguard Worker       (argv, argc * sizeof (*argv));
82*2d1272b8SAndroid Build Coastguard Worker     parser.parse (&argc, &args);
83*2d1272b8SAndroid Build Coastguard Worker     g_free (args);
84*2d1272b8SAndroid Build Coastguard Worker 
85*2d1272b8SAndroid Build Coastguard Worker     set_face (face_opts.face);
86*2d1272b8SAndroid Build Coastguard Worker   }
87*2d1272b8SAndroid Build Coastguard Worker 
parsesubset_main_t88*2d1272b8SAndroid Build Coastguard Worker   void parse (int argc, char **argv)
89*2d1272b8SAndroid Build Coastguard Worker   {
90*2d1272b8SAndroid Build Coastguard Worker     bool help = false;
91*2d1272b8SAndroid Build Coastguard Worker     for (auto i = 1; i < argc; i++)
92*2d1272b8SAndroid Build Coastguard Worker       if (!strncmp ("--help", argv[i], 6))
93*2d1272b8SAndroid Build Coastguard Worker       {
94*2d1272b8SAndroid Build Coastguard Worker 	help = true;
95*2d1272b8SAndroid Build Coastguard Worker 	break;
96*2d1272b8SAndroid Build Coastguard Worker       }
97*2d1272b8SAndroid Build Coastguard Worker 
98*2d1272b8SAndroid Build Coastguard Worker     if (likely (!help))
99*2d1272b8SAndroid Build Coastguard Worker     {
100*2d1272b8SAndroid Build Coastguard Worker       /* Do a preliminary parse to load font-face, such that we can use it
101*2d1272b8SAndroid Build Coastguard Worker        * during main option parsing. */
102*2d1272b8SAndroid Build Coastguard Worker       parse_face (argc, argv);
103*2d1272b8SAndroid Build Coastguard Worker     }
104*2d1272b8SAndroid Build Coastguard Worker 
105*2d1272b8SAndroid Build Coastguard Worker     add_options ();
106*2d1272b8SAndroid Build Coastguard Worker     option_parser_t::parse (&argc, &argv);
107*2d1272b8SAndroid Build Coastguard Worker   }
108*2d1272b8SAndroid Build Coastguard Worker 
operator ()subset_main_t109*2d1272b8SAndroid Build Coastguard Worker   int operator () (int argc, char **argv)
110*2d1272b8SAndroid Build Coastguard Worker   {
111*2d1272b8SAndroid Build Coastguard Worker     parse (argc, argv);
112*2d1272b8SAndroid Build Coastguard Worker 
113*2d1272b8SAndroid Build Coastguard Worker     hb_face_t* orig_face = face;
114*2d1272b8SAndroid Build Coastguard Worker     if (preprocess)
115*2d1272b8SAndroid Build Coastguard Worker       orig_face = preprocess_face (face);
116*2d1272b8SAndroid Build Coastguard Worker 
117*2d1272b8SAndroid Build Coastguard Worker     hb_face_t *new_face = nullptr;
118*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < num_iterations; i++)
119*2d1272b8SAndroid Build Coastguard Worker     {
120*2d1272b8SAndroid Build Coastguard Worker       hb_face_destroy (new_face);
121*2d1272b8SAndroid Build Coastguard Worker       new_face = hb_subset_or_fail (orig_face, input);
122*2d1272b8SAndroid Build Coastguard Worker     }
123*2d1272b8SAndroid Build Coastguard Worker 
124*2d1272b8SAndroid Build Coastguard Worker     bool success = new_face;
125*2d1272b8SAndroid Build Coastguard Worker     if (success)
126*2d1272b8SAndroid Build Coastguard Worker     {
127*2d1272b8SAndroid Build Coastguard Worker       hb_blob_t *result = hb_face_reference_blob (new_face);
128*2d1272b8SAndroid Build Coastguard Worker       write_file (output_file, result);
129*2d1272b8SAndroid Build Coastguard Worker       hb_blob_destroy (result);
130*2d1272b8SAndroid Build Coastguard Worker     }
131*2d1272b8SAndroid Build Coastguard Worker     else if (hb_face_get_glyph_count (orig_face) == 0)
132*2d1272b8SAndroid Build Coastguard Worker       fail (false, "Invalid font file.");
133*2d1272b8SAndroid Build Coastguard Worker 
134*2d1272b8SAndroid Build Coastguard Worker     hb_face_destroy (new_face);
135*2d1272b8SAndroid Build Coastguard Worker     if (preprocess)
136*2d1272b8SAndroid Build Coastguard Worker       hb_face_destroy (orig_face);
137*2d1272b8SAndroid Build Coastguard Worker 
138*2d1272b8SAndroid Build Coastguard Worker     return success ? 0 : 1;
139*2d1272b8SAndroid Build Coastguard Worker   }
140*2d1272b8SAndroid Build Coastguard Worker 
141*2d1272b8SAndroid Build Coastguard Worker   bool
write_filesubset_main_t142*2d1272b8SAndroid Build Coastguard Worker   write_file (const char *output_file, hb_blob_t *blob)
143*2d1272b8SAndroid Build Coastguard Worker   {
144*2d1272b8SAndroid Build Coastguard Worker     assert (out_fp);
145*2d1272b8SAndroid Build Coastguard Worker 
146*2d1272b8SAndroid Build Coastguard Worker     unsigned int size;
147*2d1272b8SAndroid Build Coastguard Worker     const char* data = hb_blob_get_data (blob, &size);
148*2d1272b8SAndroid Build Coastguard Worker 
149*2d1272b8SAndroid Build Coastguard Worker     while (size)
150*2d1272b8SAndroid Build Coastguard Worker     {
151*2d1272b8SAndroid Build Coastguard Worker       size_t ret = fwrite (data, 1, size, out_fp);
152*2d1272b8SAndroid Build Coastguard Worker       size -= ret;
153*2d1272b8SAndroid Build Coastguard Worker       data += ret;
154*2d1272b8SAndroid Build Coastguard Worker       if (size && ferror (out_fp))
155*2d1272b8SAndroid Build Coastguard Worker         fail (false, "Failed to write output: %s", strerror (errno));
156*2d1272b8SAndroid Build Coastguard Worker     }
157*2d1272b8SAndroid Build Coastguard Worker 
158*2d1272b8SAndroid Build Coastguard Worker     return true;
159*2d1272b8SAndroid Build Coastguard Worker   }
160*2d1272b8SAndroid Build Coastguard Worker 
161*2d1272b8SAndroid Build Coastguard Worker   void add_options ();
162*2d1272b8SAndroid Build Coastguard Worker 
163*2d1272b8SAndroid Build Coastguard Worker   protected:
164*2d1272b8SAndroid Build Coastguard Worker   static gboolean
165*2d1272b8SAndroid Build Coastguard Worker   collect_face (const char *name,
166*2d1272b8SAndroid Build Coastguard Worker 		const char *arg,
167*2d1272b8SAndroid Build Coastguard Worker 		gpointer    data,
168*2d1272b8SAndroid Build Coastguard Worker 		GError    **error);
169*2d1272b8SAndroid Build Coastguard Worker   static gboolean
170*2d1272b8SAndroid Build Coastguard Worker   collect_rest (const char *name,
171*2d1272b8SAndroid Build Coastguard Worker 		const char *arg,
172*2d1272b8SAndroid Build Coastguard Worker 		gpointer    data,
173*2d1272b8SAndroid Build Coastguard Worker 		GError    **error);
174*2d1272b8SAndroid Build Coastguard Worker 
175*2d1272b8SAndroid Build Coastguard Worker   public:
176*2d1272b8SAndroid Build Coastguard Worker 
177*2d1272b8SAndroid Build Coastguard Worker   unsigned num_iterations = 1;
178*2d1272b8SAndroid Build Coastguard Worker   gboolean preprocess = false;
179*2d1272b8SAndroid Build Coastguard Worker   hb_subset_input_t *input = nullptr;
180*2d1272b8SAndroid Build Coastguard Worker };
181*2d1272b8SAndroid Build Coastguard Worker 
182*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_gids(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error)183*2d1272b8SAndroid Build Coastguard Worker parse_gids (const char *name G_GNUC_UNUSED,
184*2d1272b8SAndroid Build Coastguard Worker 	    const char *arg,
185*2d1272b8SAndroid Build Coastguard Worker 	    gpointer    data,
186*2d1272b8SAndroid Build Coastguard Worker 	    GError    **error)
187*2d1272b8SAndroid Build Coastguard Worker {
188*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
189*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
190*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
191*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *gids = hb_subset_input_glyph_set (subset_main->input);
192*2d1272b8SAndroid Build Coastguard Worker 
193*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (gids);
194*2d1272b8SAndroid Build Coastguard Worker 
195*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
196*2d1272b8SAndroid Build Coastguard Worker   {
197*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (gids);
198*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
199*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (gids);
200*2d1272b8SAndroid Build Coastguard Worker     return true;
201*2d1272b8SAndroid Build Coastguard Worker   }
202*2d1272b8SAndroid Build Coastguard Worker 
203*2d1272b8SAndroid Build Coastguard Worker   char *s = (char *) arg;
204*2d1272b8SAndroid Build Coastguard Worker   char *p;
205*2d1272b8SAndroid Build Coastguard Worker 
206*2d1272b8SAndroid Build Coastguard Worker   while (s && *s)
207*2d1272b8SAndroid Build Coastguard Worker   {
208*2d1272b8SAndroid Build Coastguard Worker     while (*s && strchr (", ", *s))
209*2d1272b8SAndroid Build Coastguard Worker       s++;
210*2d1272b8SAndroid Build Coastguard Worker     if (!*s)
211*2d1272b8SAndroid Build Coastguard Worker       break;
212*2d1272b8SAndroid Build Coastguard Worker 
213*2d1272b8SAndroid Build Coastguard Worker     errno = 0;
214*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t start_code = strtoul (s, &p, 10);
215*2d1272b8SAndroid Build Coastguard Worker     if (s[0] == '-' || errno || s == p)
216*2d1272b8SAndroid Build Coastguard Worker     {
217*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
218*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing glyph-index at: '%s'", s);
219*2d1272b8SAndroid Build Coastguard Worker       return false;
220*2d1272b8SAndroid Build Coastguard Worker     }
221*2d1272b8SAndroid Build Coastguard Worker 
222*2d1272b8SAndroid Build Coastguard Worker     if (p && p[0] == '-') // ranges
223*2d1272b8SAndroid Build Coastguard Worker     {
224*2d1272b8SAndroid Build Coastguard Worker       s = ++p;
225*2d1272b8SAndroid Build Coastguard Worker       hb_codepoint_t end_code = strtoul (s, &p, 10);
226*2d1272b8SAndroid Build Coastguard Worker       if (s[0] == '-' || errno || s == p)
227*2d1272b8SAndroid Build Coastguard Worker       {
228*2d1272b8SAndroid Build Coastguard Worker 	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
229*2d1272b8SAndroid Build Coastguard Worker 		     "Failed parsing glyph-index at: '%s'", s);
230*2d1272b8SAndroid Build Coastguard Worker 	return false;
231*2d1272b8SAndroid Build Coastguard Worker       }
232*2d1272b8SAndroid Build Coastguard Worker 
233*2d1272b8SAndroid Build Coastguard Worker       if (end_code < start_code)
234*2d1272b8SAndroid Build Coastguard Worker       {
235*2d1272b8SAndroid Build Coastguard Worker 	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
236*2d1272b8SAndroid Build Coastguard Worker 		     "Invalid glyph-index range %u-%u", start_code, end_code);
237*2d1272b8SAndroid Build Coastguard Worker 	return false;
238*2d1272b8SAndroid Build Coastguard Worker       }
239*2d1272b8SAndroid Build Coastguard Worker       if (!is_remove)
240*2d1272b8SAndroid Build Coastguard Worker         hb_set_add_range (gids, start_code, end_code);
241*2d1272b8SAndroid Build Coastguard Worker       else
242*2d1272b8SAndroid Build Coastguard Worker         hb_set_del_range (gids, start_code, end_code);
243*2d1272b8SAndroid Build Coastguard Worker     }
244*2d1272b8SAndroid Build Coastguard Worker     else
245*2d1272b8SAndroid Build Coastguard Worker     {
246*2d1272b8SAndroid Build Coastguard Worker       if (!is_remove)
247*2d1272b8SAndroid Build Coastguard Worker         hb_set_add (gids, start_code);
248*2d1272b8SAndroid Build Coastguard Worker       else
249*2d1272b8SAndroid Build Coastguard Worker         hb_set_del (gids, start_code);
250*2d1272b8SAndroid Build Coastguard Worker     }
251*2d1272b8SAndroid Build Coastguard Worker 
252*2d1272b8SAndroid Build Coastguard Worker     s = p;
253*2d1272b8SAndroid Build Coastguard Worker   }
254*2d1272b8SAndroid Build Coastguard Worker 
255*2d1272b8SAndroid Build Coastguard Worker   return true;
256*2d1272b8SAndroid Build Coastguard Worker }
257*2d1272b8SAndroid Build Coastguard Worker 
258*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_glyphs(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)259*2d1272b8SAndroid Build Coastguard Worker parse_glyphs (const char *name G_GNUC_UNUSED,
260*2d1272b8SAndroid Build Coastguard Worker 	      const char *arg,
261*2d1272b8SAndroid Build Coastguard Worker 	      gpointer    data,
262*2d1272b8SAndroid Build Coastguard Worker 	      GError    **error G_GNUC_UNUSED)
263*2d1272b8SAndroid Build Coastguard Worker {
264*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
265*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
266*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
267*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *gids = hb_subset_input_glyph_set (subset_main->input);
268*2d1272b8SAndroid Build Coastguard Worker 
269*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (gids);
270*2d1272b8SAndroid Build Coastguard Worker 
271*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
272*2d1272b8SAndroid Build Coastguard Worker   {
273*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (gids);
274*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
275*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (gids);
276*2d1272b8SAndroid Build Coastguard Worker     return true;
277*2d1272b8SAndroid Build Coastguard Worker   }
278*2d1272b8SAndroid Build Coastguard Worker 
279*2d1272b8SAndroid Build Coastguard Worker   const char *p = arg;
280*2d1272b8SAndroid Build Coastguard Worker   const char *p_end = arg + strlen (arg);
281*2d1272b8SAndroid Build Coastguard Worker 
282*2d1272b8SAndroid Build Coastguard Worker   hb_font_t *font = hb_font_create (subset_main->face);
283*2d1272b8SAndroid Build Coastguard Worker   while (p < p_end)
284*2d1272b8SAndroid Build Coastguard Worker   {
285*2d1272b8SAndroid Build Coastguard Worker     while (p < p_end && (*p == ' ' || *p == ','))
286*2d1272b8SAndroid Build Coastguard Worker       p++;
287*2d1272b8SAndroid Build Coastguard Worker 
288*2d1272b8SAndroid Build Coastguard Worker     const char *end = p;
289*2d1272b8SAndroid Build Coastguard Worker     while (end < p_end && *end != ' ' && *end != ',')
290*2d1272b8SAndroid Build Coastguard Worker       end++;
291*2d1272b8SAndroid Build Coastguard Worker 
292*2d1272b8SAndroid Build Coastguard Worker     if (p < end)
293*2d1272b8SAndroid Build Coastguard Worker     {
294*2d1272b8SAndroid Build Coastguard Worker       hb_codepoint_t gid;
295*2d1272b8SAndroid Build Coastguard Worker       if (!hb_font_get_glyph_from_name (font, p, end - p, &gid))
296*2d1272b8SAndroid Build Coastguard Worker       {
297*2d1272b8SAndroid Build Coastguard Worker 	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
298*2d1272b8SAndroid Build Coastguard Worker 		     "Failed parsing glyph name: '%s'", p);
299*2d1272b8SAndroid Build Coastguard Worker 	return false;
300*2d1272b8SAndroid Build Coastguard Worker       }
301*2d1272b8SAndroid Build Coastguard Worker 
302*2d1272b8SAndroid Build Coastguard Worker       if (!is_remove)
303*2d1272b8SAndroid Build Coastguard Worker         hb_set_add (gids, gid);
304*2d1272b8SAndroid Build Coastguard Worker       else
305*2d1272b8SAndroid Build Coastguard Worker         hb_set_del (gids, gid);
306*2d1272b8SAndroid Build Coastguard Worker     }
307*2d1272b8SAndroid Build Coastguard Worker 
308*2d1272b8SAndroid Build Coastguard Worker     p = end + 1;
309*2d1272b8SAndroid Build Coastguard Worker   }
310*2d1272b8SAndroid Build Coastguard Worker   hb_font_destroy (font);
311*2d1272b8SAndroid Build Coastguard Worker 
312*2d1272b8SAndroid Build Coastguard Worker   return true;
313*2d1272b8SAndroid Build Coastguard Worker }
314*2d1272b8SAndroid Build Coastguard Worker 
315*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_text(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)316*2d1272b8SAndroid Build Coastguard Worker parse_text (const char *name G_GNUC_UNUSED,
317*2d1272b8SAndroid Build Coastguard Worker 	    const char *arg,
318*2d1272b8SAndroid Build Coastguard Worker 	    gpointer    data,
319*2d1272b8SAndroid Build Coastguard Worker 	    GError    **error G_GNUC_UNUSED)
320*2d1272b8SAndroid Build Coastguard Worker {
321*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
322*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
323*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
324*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *unicodes = hb_subset_input_unicode_set (subset_main->input);
325*2d1272b8SAndroid Build Coastguard Worker 
326*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (unicodes);
327*2d1272b8SAndroid Build Coastguard Worker 
328*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
329*2d1272b8SAndroid Build Coastguard Worker   {
330*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (unicodes);
331*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
332*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (unicodes);
333*2d1272b8SAndroid Build Coastguard Worker     return true;
334*2d1272b8SAndroid Build Coastguard Worker   }
335*2d1272b8SAndroid Build Coastguard Worker 
336*2d1272b8SAndroid Build Coastguard Worker   for (gchar *c = (gchar *) arg;
337*2d1272b8SAndroid Build Coastguard Worker        *c;
338*2d1272b8SAndroid Build Coastguard Worker        c = g_utf8_find_next_char(c, nullptr))
339*2d1272b8SAndroid Build Coastguard Worker   {
340*2d1272b8SAndroid Build Coastguard Worker     gunichar cp = g_utf8_get_char(c);
341*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
342*2d1272b8SAndroid Build Coastguard Worker       hb_set_add (unicodes, cp);
343*2d1272b8SAndroid Build Coastguard Worker     else
344*2d1272b8SAndroid Build Coastguard Worker       hb_set_del (unicodes, cp);
345*2d1272b8SAndroid Build Coastguard Worker   }
346*2d1272b8SAndroid Build Coastguard Worker   return true;
347*2d1272b8SAndroid Build Coastguard Worker }
348*2d1272b8SAndroid Build Coastguard Worker 
349*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_unicodes(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error)350*2d1272b8SAndroid Build Coastguard Worker parse_unicodes (const char *name G_GNUC_UNUSED,
351*2d1272b8SAndroid Build Coastguard Worker 		const char *arg,
352*2d1272b8SAndroid Build Coastguard Worker 		gpointer    data,
353*2d1272b8SAndroid Build Coastguard Worker 		GError    **error)
354*2d1272b8SAndroid Build Coastguard Worker {
355*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
356*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
357*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
358*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *unicodes = hb_subset_input_unicode_set (subset_main->input);
359*2d1272b8SAndroid Build Coastguard Worker 
360*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (unicodes);
361*2d1272b8SAndroid Build Coastguard Worker 
362*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
363*2d1272b8SAndroid Build Coastguard Worker   {
364*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (unicodes);
365*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
366*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (unicodes);
367*2d1272b8SAndroid Build Coastguard Worker     return true;
368*2d1272b8SAndroid Build Coastguard Worker   }
369*2d1272b8SAndroid Build Coastguard Worker 
370*2d1272b8SAndroid Build Coastguard Worker   // XXX TODO Ranges
371*2d1272b8SAndroid Build Coastguard Worker #define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r "
372*2d1272b8SAndroid Build Coastguard Worker 
373*2d1272b8SAndroid Build Coastguard Worker   char *s = (char *) arg;
374*2d1272b8SAndroid Build Coastguard Worker   char *p;
375*2d1272b8SAndroid Build Coastguard Worker 
376*2d1272b8SAndroid Build Coastguard Worker   while (s && *s)
377*2d1272b8SAndroid Build Coastguard Worker   {
378*2d1272b8SAndroid Build Coastguard Worker     while (*s && strchr (DELIMITERS, *s))
379*2d1272b8SAndroid Build Coastguard Worker       s++;
380*2d1272b8SAndroid Build Coastguard Worker     if (!*s)
381*2d1272b8SAndroid Build Coastguard Worker       break;
382*2d1272b8SAndroid Build Coastguard Worker 
383*2d1272b8SAndroid Build Coastguard Worker     errno = 0;
384*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t start_code = strtoul (s, &p, 16);
385*2d1272b8SAndroid Build Coastguard Worker     if (errno || s == p)
386*2d1272b8SAndroid Build Coastguard Worker     {
387*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
388*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing Unicode at: '%s'", s);
389*2d1272b8SAndroid Build Coastguard Worker       return false;
390*2d1272b8SAndroid Build Coastguard Worker     }
391*2d1272b8SAndroid Build Coastguard Worker 
392*2d1272b8SAndroid Build Coastguard Worker     if (p && p[0] == '-') // ranges
393*2d1272b8SAndroid Build Coastguard Worker     {
394*2d1272b8SAndroid Build Coastguard Worker       s = ++p;
395*2d1272b8SAndroid Build Coastguard Worker       hb_codepoint_t end_code = strtoul (s, &p, 16);
396*2d1272b8SAndroid Build Coastguard Worker       if (s[0] == '-' || errno || s == p)
397*2d1272b8SAndroid Build Coastguard Worker       {
398*2d1272b8SAndroid Build Coastguard Worker 	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
399*2d1272b8SAndroid Build Coastguard Worker 		     "Failed parsing Unicode at: '%s'", s);
400*2d1272b8SAndroid Build Coastguard Worker 	return false;
401*2d1272b8SAndroid Build Coastguard Worker       }
402*2d1272b8SAndroid Build Coastguard Worker 
403*2d1272b8SAndroid Build Coastguard Worker       if (end_code < start_code)
404*2d1272b8SAndroid Build Coastguard Worker       {
405*2d1272b8SAndroid Build Coastguard Worker 	g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
406*2d1272b8SAndroid Build Coastguard Worker 		     "Invalid Unicode range %u-%u", start_code, end_code);
407*2d1272b8SAndroid Build Coastguard Worker 	return false;
408*2d1272b8SAndroid Build Coastguard Worker       }
409*2d1272b8SAndroid Build Coastguard Worker       if (!is_remove)
410*2d1272b8SAndroid Build Coastguard Worker         hb_set_add_range (unicodes, start_code, end_code);
411*2d1272b8SAndroid Build Coastguard Worker       else
412*2d1272b8SAndroid Build Coastguard Worker         hb_set_del_range (unicodes, start_code, end_code);
413*2d1272b8SAndroid Build Coastguard Worker     }
414*2d1272b8SAndroid Build Coastguard Worker     else
415*2d1272b8SAndroid Build Coastguard Worker     {
416*2d1272b8SAndroid Build Coastguard Worker       if (!is_remove)
417*2d1272b8SAndroid Build Coastguard Worker         hb_set_add (unicodes, start_code);
418*2d1272b8SAndroid Build Coastguard Worker       else
419*2d1272b8SAndroid Build Coastguard Worker         hb_set_del (unicodes, start_code);
420*2d1272b8SAndroid Build Coastguard Worker     }
421*2d1272b8SAndroid Build Coastguard Worker 
422*2d1272b8SAndroid Build Coastguard Worker     s = p;
423*2d1272b8SAndroid Build Coastguard Worker   }
424*2d1272b8SAndroid Build Coastguard Worker 
425*2d1272b8SAndroid Build Coastguard Worker   return true;
426*2d1272b8SAndroid Build Coastguard Worker }
427*2d1272b8SAndroid Build Coastguard Worker 
428*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_nameids(const char * name,const char * arg,gpointer data,GError ** error)429*2d1272b8SAndroid Build Coastguard Worker parse_nameids (const char *name,
430*2d1272b8SAndroid Build Coastguard Worker 	       const char *arg,
431*2d1272b8SAndroid Build Coastguard Worker 	       gpointer    data,
432*2d1272b8SAndroid Build Coastguard Worker 	       GError    **error)
433*2d1272b8SAndroid Build Coastguard Worker {
434*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
435*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
436*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
437*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *name_ids = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_NAME_ID);
438*2d1272b8SAndroid Build Coastguard Worker 
439*2d1272b8SAndroid Build Coastguard Worker 
440*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (name_ids);
441*2d1272b8SAndroid Build Coastguard Worker 
442*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
443*2d1272b8SAndroid Build Coastguard Worker   {
444*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (name_ids);
445*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
446*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (name_ids);
447*2d1272b8SAndroid Build Coastguard Worker     return true;
448*2d1272b8SAndroid Build Coastguard Worker   }
449*2d1272b8SAndroid Build Coastguard Worker 
450*2d1272b8SAndroid Build Coastguard Worker   char *s = (char *) arg;
451*2d1272b8SAndroid Build Coastguard Worker   char *p;
452*2d1272b8SAndroid Build Coastguard Worker 
453*2d1272b8SAndroid Build Coastguard Worker   while (s && *s)
454*2d1272b8SAndroid Build Coastguard Worker   {
455*2d1272b8SAndroid Build Coastguard Worker     while (*s && strchr (", ", *s))
456*2d1272b8SAndroid Build Coastguard Worker       s++;
457*2d1272b8SAndroid Build Coastguard Worker     if (!*s)
458*2d1272b8SAndroid Build Coastguard Worker       break;
459*2d1272b8SAndroid Build Coastguard Worker 
460*2d1272b8SAndroid Build Coastguard Worker     errno = 0;
461*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t u = strtoul (s, &p, 10);
462*2d1272b8SAndroid Build Coastguard Worker     if (errno || s == p)
463*2d1272b8SAndroid Build Coastguard Worker     {
464*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
465*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing nameID at: '%s'", s);
466*2d1272b8SAndroid Build Coastguard Worker       return false;
467*2d1272b8SAndroid Build Coastguard Worker     }
468*2d1272b8SAndroid Build Coastguard Worker 
469*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
470*2d1272b8SAndroid Build Coastguard Worker     {
471*2d1272b8SAndroid Build Coastguard Worker       hb_set_add (name_ids, u);
472*2d1272b8SAndroid Build Coastguard Worker     } else {
473*2d1272b8SAndroid Build Coastguard Worker       hb_set_del (name_ids, u);
474*2d1272b8SAndroid Build Coastguard Worker     }
475*2d1272b8SAndroid Build Coastguard Worker 
476*2d1272b8SAndroid Build Coastguard Worker     s = p;
477*2d1272b8SAndroid Build Coastguard Worker   }
478*2d1272b8SAndroid Build Coastguard Worker 
479*2d1272b8SAndroid Build Coastguard Worker   return true;
480*2d1272b8SAndroid Build Coastguard Worker }
481*2d1272b8SAndroid Build Coastguard Worker 
482*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_name_languages(const char * name,const char * arg,gpointer data,GError ** error)483*2d1272b8SAndroid Build Coastguard Worker parse_name_languages (const char *name,
484*2d1272b8SAndroid Build Coastguard Worker 		      const char *arg,
485*2d1272b8SAndroid Build Coastguard Worker 		      gpointer    data,
486*2d1272b8SAndroid Build Coastguard Worker 		      GError    **error)
487*2d1272b8SAndroid Build Coastguard Worker {
488*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
489*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
490*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
491*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *name_languages = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_NAME_LANG_ID);
492*2d1272b8SAndroid Build Coastguard Worker 
493*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (name_languages);
494*2d1272b8SAndroid Build Coastguard Worker 
495*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
496*2d1272b8SAndroid Build Coastguard Worker   {
497*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (name_languages);
498*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
499*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (name_languages);
500*2d1272b8SAndroid Build Coastguard Worker     return true;
501*2d1272b8SAndroid Build Coastguard Worker   }
502*2d1272b8SAndroid Build Coastguard Worker 
503*2d1272b8SAndroid Build Coastguard Worker   char *s = (char *) arg;
504*2d1272b8SAndroid Build Coastguard Worker   char *p;
505*2d1272b8SAndroid Build Coastguard Worker 
506*2d1272b8SAndroid Build Coastguard Worker   while (s && *s)
507*2d1272b8SAndroid Build Coastguard Worker   {
508*2d1272b8SAndroid Build Coastguard Worker     while (*s && strchr (", ", *s))
509*2d1272b8SAndroid Build Coastguard Worker       s++;
510*2d1272b8SAndroid Build Coastguard Worker     if (!*s)
511*2d1272b8SAndroid Build Coastguard Worker       break;
512*2d1272b8SAndroid Build Coastguard Worker 
513*2d1272b8SAndroid Build Coastguard Worker     errno = 0;
514*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t u = strtoul (s, &p, 10);
515*2d1272b8SAndroid Build Coastguard Worker     if (errno || s == p)
516*2d1272b8SAndroid Build Coastguard Worker     {
517*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
518*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing name-language code at: '%s'", s);
519*2d1272b8SAndroid Build Coastguard Worker       return false;
520*2d1272b8SAndroid Build Coastguard Worker     }
521*2d1272b8SAndroid Build Coastguard Worker 
522*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
523*2d1272b8SAndroid Build Coastguard Worker     {
524*2d1272b8SAndroid Build Coastguard Worker       hb_set_add (name_languages, u);
525*2d1272b8SAndroid Build Coastguard Worker     } else {
526*2d1272b8SAndroid Build Coastguard Worker       hb_set_del (name_languages, u);
527*2d1272b8SAndroid Build Coastguard Worker     }
528*2d1272b8SAndroid Build Coastguard Worker 
529*2d1272b8SAndroid Build Coastguard Worker     s = p;
530*2d1272b8SAndroid Build Coastguard Worker   }
531*2d1272b8SAndroid Build Coastguard Worker 
532*2d1272b8SAndroid Build Coastguard Worker   return true;
533*2d1272b8SAndroid Build Coastguard Worker }
534*2d1272b8SAndroid Build Coastguard Worker 
535*2d1272b8SAndroid Build Coastguard Worker static gboolean
_keep_everything(const char * name,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)536*2d1272b8SAndroid Build Coastguard Worker _keep_everything (const char *name,
537*2d1272b8SAndroid Build Coastguard Worker 		  const char *arg,
538*2d1272b8SAndroid Build Coastguard Worker 		  gpointer    data,
539*2d1272b8SAndroid Build Coastguard Worker 		  GError    **error G_GNUC_UNUSED)
540*2d1272b8SAndroid Build Coastguard Worker {
541*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
542*2d1272b8SAndroid Build Coastguard Worker 
543*2d1272b8SAndroid Build Coastguard Worker   hb_subset_input_keep_everything (subset_main->input);
544*2d1272b8SAndroid Build Coastguard Worker 
545*2d1272b8SAndroid Build Coastguard Worker   return true;
546*2d1272b8SAndroid Build Coastguard Worker }
547*2d1272b8SAndroid Build Coastguard Worker 
548*2d1272b8SAndroid Build Coastguard Worker template <hb_subset_flags_t flag>
549*2d1272b8SAndroid Build Coastguard Worker static gboolean
set_flag(const char * name,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)550*2d1272b8SAndroid Build Coastguard Worker set_flag (const char *name,
551*2d1272b8SAndroid Build Coastguard Worker 	  const char *arg,
552*2d1272b8SAndroid Build Coastguard Worker 	  gpointer    data,
553*2d1272b8SAndroid Build Coastguard Worker 	  GError    **error G_GNUC_UNUSED)
554*2d1272b8SAndroid Build Coastguard Worker {
555*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
556*2d1272b8SAndroid Build Coastguard Worker 
557*2d1272b8SAndroid Build Coastguard Worker   hb_subset_input_set_flags (subset_main->input,
558*2d1272b8SAndroid Build Coastguard Worker 			     hb_subset_input_get_flags (subset_main->input) | flag);
559*2d1272b8SAndroid Build Coastguard Worker 
560*2d1272b8SAndroid Build Coastguard Worker   return true;
561*2d1272b8SAndroid Build Coastguard Worker }
562*2d1272b8SAndroid Build Coastguard Worker 
563*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_layout_tag_list(hb_subset_sets_t set_type,const char * name,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)564*2d1272b8SAndroid Build Coastguard Worker parse_layout_tag_list (hb_subset_sets_t set_type,
565*2d1272b8SAndroid Build Coastguard Worker                        const char *name,
566*2d1272b8SAndroid Build Coastguard Worker                        const char *arg,
567*2d1272b8SAndroid Build Coastguard Worker                        gpointer    data,
568*2d1272b8SAndroid Build Coastguard Worker                        GError    **error G_GNUC_UNUSED)
569*2d1272b8SAndroid Build Coastguard Worker {
570*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
571*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
572*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
573*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *layout_tags = hb_subset_input_set (subset_main->input, set_type);
574*2d1272b8SAndroid Build Coastguard Worker 
575*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (layout_tags);
576*2d1272b8SAndroid Build Coastguard Worker 
577*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
578*2d1272b8SAndroid Build Coastguard Worker   {
579*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (layout_tags);
580*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
581*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (layout_tags);
582*2d1272b8SAndroid Build Coastguard Worker     return true;
583*2d1272b8SAndroid Build Coastguard Worker   }
584*2d1272b8SAndroid Build Coastguard Worker 
585*2d1272b8SAndroid Build Coastguard Worker   char *s = strtok((char *) arg, ", ");
586*2d1272b8SAndroid Build Coastguard Worker   while (s)
587*2d1272b8SAndroid Build Coastguard Worker   {
588*2d1272b8SAndroid Build Coastguard Worker     if (strlen (s) > 4) // tags are at most 4 bytes
589*2d1272b8SAndroid Build Coastguard Worker     {
590*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
591*2d1272b8SAndroid Build Coastguard Worker                    "Failed parsing table tag at: '%s'", s);
592*2d1272b8SAndroid Build Coastguard Worker       return false;
593*2d1272b8SAndroid Build Coastguard Worker     }
594*2d1272b8SAndroid Build Coastguard Worker 
595*2d1272b8SAndroid Build Coastguard Worker     hb_tag_t tag = hb_tag_from_string (s, strlen (s));
596*2d1272b8SAndroid Build Coastguard Worker 
597*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
598*2d1272b8SAndroid Build Coastguard Worker       hb_set_add (layout_tags, tag);
599*2d1272b8SAndroid Build Coastguard Worker     else
600*2d1272b8SAndroid Build Coastguard Worker       hb_set_del (layout_tags, tag);
601*2d1272b8SAndroid Build Coastguard Worker 
602*2d1272b8SAndroid Build Coastguard Worker     s = strtok(nullptr, ", ");
603*2d1272b8SAndroid Build Coastguard Worker   }
604*2d1272b8SAndroid Build Coastguard Worker 
605*2d1272b8SAndroid Build Coastguard Worker   return true;
606*2d1272b8SAndroid Build Coastguard Worker }
607*2d1272b8SAndroid Build Coastguard Worker 
608*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_layout_features(const char * name,const char * arg,gpointer data,GError ** error)609*2d1272b8SAndroid Build Coastguard Worker parse_layout_features (const char *name,
610*2d1272b8SAndroid Build Coastguard Worker 		       const char *arg,
611*2d1272b8SAndroid Build Coastguard Worker 		       gpointer    data,
612*2d1272b8SAndroid Build Coastguard Worker 		       GError    **error)
613*2d1272b8SAndroid Build Coastguard Worker 
614*2d1272b8SAndroid Build Coastguard Worker {
615*2d1272b8SAndroid Build Coastguard Worker   return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
616*2d1272b8SAndroid Build Coastguard Worker                                 name,
617*2d1272b8SAndroid Build Coastguard Worker                                 arg,
618*2d1272b8SAndroid Build Coastguard Worker                                 data,
619*2d1272b8SAndroid Build Coastguard Worker                                 error);
620*2d1272b8SAndroid Build Coastguard Worker }
621*2d1272b8SAndroid Build Coastguard Worker 
622*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_layout_scripts(const char * name,const char * arg,gpointer data,GError ** error)623*2d1272b8SAndroid Build Coastguard Worker parse_layout_scripts (const char *name,
624*2d1272b8SAndroid Build Coastguard Worker 		       const char *arg,
625*2d1272b8SAndroid Build Coastguard Worker 		       gpointer    data,
626*2d1272b8SAndroid Build Coastguard Worker 		       GError    **error)
627*2d1272b8SAndroid Build Coastguard Worker 
628*2d1272b8SAndroid Build Coastguard Worker {
629*2d1272b8SAndroid Build Coastguard Worker   return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
630*2d1272b8SAndroid Build Coastguard Worker                                 name,
631*2d1272b8SAndroid Build Coastguard Worker                                 arg,
632*2d1272b8SAndroid Build Coastguard Worker                                 data,
633*2d1272b8SAndroid Build Coastguard Worker                                 error);
634*2d1272b8SAndroid Build Coastguard Worker }
635*2d1272b8SAndroid Build Coastguard Worker 
636*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_drop_tables(const char * name,const char * arg,gpointer data,GError ** error)637*2d1272b8SAndroid Build Coastguard Worker parse_drop_tables (const char *name,
638*2d1272b8SAndroid Build Coastguard Worker 		   const char *arg,
639*2d1272b8SAndroid Build Coastguard Worker 		   gpointer    data,
640*2d1272b8SAndroid Build Coastguard Worker 		   GError    **error)
641*2d1272b8SAndroid Build Coastguard Worker {
642*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
643*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
644*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t is_add = (name[strlen (name) - 1] == '+');
645*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *drop_tables = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_DROP_TABLE_TAG);
646*2d1272b8SAndroid Build Coastguard Worker 
647*2d1272b8SAndroid Build Coastguard Worker   if (!is_remove && !is_add) hb_set_clear (drop_tables);
648*2d1272b8SAndroid Build Coastguard Worker 
649*2d1272b8SAndroid Build Coastguard Worker   if (0 == strcmp (arg, "*"))
650*2d1272b8SAndroid Build Coastguard Worker   {
651*2d1272b8SAndroid Build Coastguard Worker     hb_set_clear (drop_tables);
652*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
653*2d1272b8SAndroid Build Coastguard Worker       hb_set_invert (drop_tables);
654*2d1272b8SAndroid Build Coastguard Worker     return true;
655*2d1272b8SAndroid Build Coastguard Worker   }
656*2d1272b8SAndroid Build Coastguard Worker 
657*2d1272b8SAndroid Build Coastguard Worker   char *s = strtok((char *) arg, ", ");
658*2d1272b8SAndroid Build Coastguard Worker   while (s)
659*2d1272b8SAndroid Build Coastguard Worker   {
660*2d1272b8SAndroid Build Coastguard Worker     if (strlen (s) > 4) // Table tags are at most 4 bytes.
661*2d1272b8SAndroid Build Coastguard Worker     {
662*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
663*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing table tag at: '%s'", s);
664*2d1272b8SAndroid Build Coastguard Worker       return false;
665*2d1272b8SAndroid Build Coastguard Worker     }
666*2d1272b8SAndroid Build Coastguard Worker 
667*2d1272b8SAndroid Build Coastguard Worker     hb_tag_t tag = hb_tag_from_string (s, strlen (s));
668*2d1272b8SAndroid Build Coastguard Worker 
669*2d1272b8SAndroid Build Coastguard Worker     if (!is_remove)
670*2d1272b8SAndroid Build Coastguard Worker       hb_set_add (drop_tables, tag);
671*2d1272b8SAndroid Build Coastguard Worker     else
672*2d1272b8SAndroid Build Coastguard Worker       hb_set_del (drop_tables, tag);
673*2d1272b8SAndroid Build Coastguard Worker 
674*2d1272b8SAndroid Build Coastguard Worker     s = strtok(nullptr, ", ");
675*2d1272b8SAndroid Build Coastguard Worker   }
676*2d1272b8SAndroid Build Coastguard Worker 
677*2d1272b8SAndroid Build Coastguard Worker   return true;
678*2d1272b8SAndroid Build Coastguard Worker }
679*2d1272b8SAndroid Build Coastguard Worker 
680*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_VAR
681*2d1272b8SAndroid Build Coastguard Worker 
682*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_instance(const char * name,const char * arg,gpointer data,GError ** error)683*2d1272b8SAndroid Build Coastguard Worker parse_instance (const char *name,
684*2d1272b8SAndroid Build Coastguard Worker 		const char *arg,
685*2d1272b8SAndroid Build Coastguard Worker 		gpointer    data,
686*2d1272b8SAndroid Build Coastguard Worker 		GError    **error)
687*2d1272b8SAndroid Build Coastguard Worker {
688*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
689*2d1272b8SAndroid Build Coastguard Worker   if (!subset_main->face) {
690*2d1272b8SAndroid Build Coastguard Worker     // There is no face, which is needed to set up instancing. Skip parsing these options.
691*2d1272b8SAndroid Build Coastguard Worker     return true;
692*2d1272b8SAndroid Build Coastguard Worker   }
693*2d1272b8SAndroid Build Coastguard Worker 
694*2d1272b8SAndroid Build Coastguard Worker   return parse_instancing_spec(arg, subset_main->face, subset_main->input, error);
695*2d1272b8SAndroid Build Coastguard Worker }
696*2d1272b8SAndroid Build Coastguard Worker #endif
697*2d1272b8SAndroid Build Coastguard Worker 
698*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_glyph_map(const char * name,const char * arg,gpointer data,GError ** error)699*2d1272b8SAndroid Build Coastguard Worker parse_glyph_map (const char *name,
700*2d1272b8SAndroid Build Coastguard Worker 		 const char *arg,
701*2d1272b8SAndroid Build Coastguard Worker 		 gpointer    data,
702*2d1272b8SAndroid Build Coastguard Worker 		 GError    **error)
703*2d1272b8SAndroid Build Coastguard Worker {
704*2d1272b8SAndroid Build Coastguard Worker   // Glyph map has the following format:
705*2d1272b8SAndroid Build Coastguard Worker   // <entry 1>,<entry 2>,...,<entry n>
706*2d1272b8SAndroid Build Coastguard Worker   // <entry> = <old gid>:<new gid>
707*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *subset_main = (subset_main_t *) data;
708*2d1272b8SAndroid Build Coastguard Worker   hb_subset_input_t* input = subset_main->input;
709*2d1272b8SAndroid Build Coastguard Worker   hb_set_t *glyphs = hb_subset_input_glyph_set(input);
710*2d1272b8SAndroid Build Coastguard Worker 
711*2d1272b8SAndroid Build Coastguard Worker   char *s = (char *) arg;
712*2d1272b8SAndroid Build Coastguard Worker   char *p;
713*2d1272b8SAndroid Build Coastguard Worker 
714*2d1272b8SAndroid Build Coastguard Worker   while (s && *s)
715*2d1272b8SAndroid Build Coastguard Worker   {
716*2d1272b8SAndroid Build Coastguard Worker     while (*s && strchr (", ", *s))
717*2d1272b8SAndroid Build Coastguard Worker       s++;
718*2d1272b8SAndroid Build Coastguard Worker     if (!*s)
719*2d1272b8SAndroid Build Coastguard Worker       break;
720*2d1272b8SAndroid Build Coastguard Worker 
721*2d1272b8SAndroid Build Coastguard Worker     errno = 0;
722*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t start_code = strtoul (s, &p, 10);
723*2d1272b8SAndroid Build Coastguard Worker     if (s[0] == '-' || errno || s == p)
724*2d1272b8SAndroid Build Coastguard Worker     {
725*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
726*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing glyph map at: '%s'", s);
727*2d1272b8SAndroid Build Coastguard Worker       return false;
728*2d1272b8SAndroid Build Coastguard Worker     }
729*2d1272b8SAndroid Build Coastguard Worker 
730*2d1272b8SAndroid Build Coastguard Worker     if (!p || p[0] != ':') // ranges
731*2d1272b8SAndroid Build Coastguard Worker     {
732*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
733*2d1272b8SAndroid Build Coastguard Worker 		   "Failed parsing glyph map at: '%s'", s);
734*2d1272b8SAndroid Build Coastguard Worker       return false;
735*2d1272b8SAndroid Build Coastguard Worker     }
736*2d1272b8SAndroid Build Coastguard Worker 
737*2d1272b8SAndroid Build Coastguard Worker     s = ++p;
738*2d1272b8SAndroid Build Coastguard Worker     hb_codepoint_t end_code = strtoul (s, &p, 10);
739*2d1272b8SAndroid Build Coastguard Worker     if (s[0] == '-' || errno || s == p)
740*2d1272b8SAndroid Build Coastguard Worker     {
741*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
742*2d1272b8SAndroid Build Coastguard Worker 		"Failed parsing glyph map at: '%s'", s);
743*2d1272b8SAndroid Build Coastguard Worker       return false;
744*2d1272b8SAndroid Build Coastguard Worker     }
745*2d1272b8SAndroid Build Coastguard Worker 
746*2d1272b8SAndroid Build Coastguard Worker     hb_set_add(glyphs, start_code);
747*2d1272b8SAndroid Build Coastguard Worker     hb_map_set (hb_subset_input_old_to_new_glyph_mapping (input), start_code, end_code);
748*2d1272b8SAndroid Build Coastguard Worker 
749*2d1272b8SAndroid Build Coastguard Worker     s = p;
750*2d1272b8SAndroid Build Coastguard Worker   }
751*2d1272b8SAndroid Build Coastguard Worker 
752*2d1272b8SAndroid Build Coastguard Worker   return true;
753*2d1272b8SAndroid Build Coastguard Worker }
754*2d1272b8SAndroid Build Coastguard Worker 
755*2d1272b8SAndroid Build Coastguard Worker template <GOptionArgFunc line_parser, bool allow_comments=true>
756*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_file_for(const char * name,const char * arg,gpointer data,GError ** error)757*2d1272b8SAndroid Build Coastguard Worker parse_file_for (const char *name,
758*2d1272b8SAndroid Build Coastguard Worker 		const char *arg,
759*2d1272b8SAndroid Build Coastguard Worker 		gpointer    data,
760*2d1272b8SAndroid Build Coastguard Worker 		GError    **error)
761*2d1272b8SAndroid Build Coastguard Worker {
762*2d1272b8SAndroid Build Coastguard Worker   FILE *fp = nullptr;
763*2d1272b8SAndroid Build Coastguard Worker   if (0 != strcmp (arg, "-"))
764*2d1272b8SAndroid Build Coastguard Worker     fp = fopen (arg, "r");
765*2d1272b8SAndroid Build Coastguard Worker   else
766*2d1272b8SAndroid Build Coastguard Worker     fp = stdin;
767*2d1272b8SAndroid Build Coastguard Worker 
768*2d1272b8SAndroid Build Coastguard Worker   if (!fp)
769*2d1272b8SAndroid Build Coastguard Worker   {
770*2d1272b8SAndroid Build Coastguard Worker     g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
771*2d1272b8SAndroid Build Coastguard Worker 		 "Failed opening file `%s': %s",
772*2d1272b8SAndroid Build Coastguard Worker 		 arg, strerror (errno));
773*2d1272b8SAndroid Build Coastguard Worker     return false;
774*2d1272b8SAndroid Build Coastguard Worker   }
775*2d1272b8SAndroid Build Coastguard Worker 
776*2d1272b8SAndroid Build Coastguard Worker   GString *gs = g_string_new (nullptr);
777*2d1272b8SAndroid Build Coastguard Worker   do
778*2d1272b8SAndroid Build Coastguard Worker   {
779*2d1272b8SAndroid Build Coastguard Worker     g_string_set_size (gs, 0);
780*2d1272b8SAndroid Build Coastguard Worker     char buf[BUFSIZ];
781*2d1272b8SAndroid Build Coastguard Worker     while (fgets (buf, sizeof (buf), fp))
782*2d1272b8SAndroid Build Coastguard Worker     {
783*2d1272b8SAndroid Build Coastguard Worker       unsigned bytes = strlen (buf);
784*2d1272b8SAndroid Build Coastguard Worker       if (bytes && buf[bytes - 1] == '\n')
785*2d1272b8SAndroid Build Coastguard Worker       {
786*2d1272b8SAndroid Build Coastguard Worker 	bytes--;
787*2d1272b8SAndroid Build Coastguard Worker 	g_string_append_len (gs, buf, bytes);
788*2d1272b8SAndroid Build Coastguard Worker 	break;
789*2d1272b8SAndroid Build Coastguard Worker       }
790*2d1272b8SAndroid Build Coastguard Worker       g_string_append_len (gs, buf, bytes);
791*2d1272b8SAndroid Build Coastguard Worker     }
792*2d1272b8SAndroid Build Coastguard Worker     if (ferror (fp))
793*2d1272b8SAndroid Build Coastguard Worker     {
794*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
795*2d1272b8SAndroid Build Coastguard Worker 		   "Failed reading file `%s': %s",
796*2d1272b8SAndroid Build Coastguard Worker 		   arg, strerror (errno));
797*2d1272b8SAndroid Build Coastguard Worker       fclose (fp);
798*2d1272b8SAndroid Build Coastguard Worker       return false;
799*2d1272b8SAndroid Build Coastguard Worker     }
800*2d1272b8SAndroid Build Coastguard Worker     g_string_append_c (gs, '\0');
801*2d1272b8SAndroid Build Coastguard Worker 
802*2d1272b8SAndroid Build Coastguard Worker     if (allow_comments)
803*2d1272b8SAndroid Build Coastguard Worker     {
804*2d1272b8SAndroid Build Coastguard Worker       char *comment = strchr (gs->str, '#');
805*2d1272b8SAndroid Build Coastguard Worker       if (comment)
806*2d1272b8SAndroid Build Coastguard Worker         *comment = '\0';
807*2d1272b8SAndroid Build Coastguard Worker     }
808*2d1272b8SAndroid Build Coastguard Worker 
809*2d1272b8SAndroid Build Coastguard Worker     line_parser ("+", gs->str, data, error);
810*2d1272b8SAndroid Build Coastguard Worker 
811*2d1272b8SAndroid Build Coastguard Worker     if (*error)
812*2d1272b8SAndroid Build Coastguard Worker       break;
813*2d1272b8SAndroid Build Coastguard Worker   }
814*2d1272b8SAndroid Build Coastguard Worker   while (!feof (fp));
815*2d1272b8SAndroid Build Coastguard Worker 
816*2d1272b8SAndroid Build Coastguard Worker   g_string_free (gs, false);
817*2d1272b8SAndroid Build Coastguard Worker 
818*2d1272b8SAndroid Build Coastguard Worker   fclose (fp);
819*2d1272b8SAndroid Build Coastguard Worker 
820*2d1272b8SAndroid Build Coastguard Worker   return true;
821*2d1272b8SAndroid Build Coastguard Worker }
822*2d1272b8SAndroid Build Coastguard Worker 
823*2d1272b8SAndroid Build Coastguard Worker gboolean
collect_face(const char * name,const char * arg,gpointer data,GError ** error)824*2d1272b8SAndroid Build Coastguard Worker subset_main_t::collect_face (const char *name,
825*2d1272b8SAndroid Build Coastguard Worker 			     const char *arg,
826*2d1272b8SAndroid Build Coastguard Worker 			     gpointer    data,
827*2d1272b8SAndroid Build Coastguard Worker 			     GError    **error)
828*2d1272b8SAndroid Build Coastguard Worker {
829*2d1272b8SAndroid Build Coastguard Worker   face_options_t *thiz = (face_options_t *) data;
830*2d1272b8SAndroid Build Coastguard Worker 
831*2d1272b8SAndroid Build Coastguard Worker   if (!thiz->font_file)
832*2d1272b8SAndroid Build Coastguard Worker   {
833*2d1272b8SAndroid Build Coastguard Worker     thiz->font_file = g_strdup (arg);
834*2d1272b8SAndroid Build Coastguard Worker     return true;
835*2d1272b8SAndroid Build Coastguard Worker   }
836*2d1272b8SAndroid Build Coastguard Worker 
837*2d1272b8SAndroid Build Coastguard Worker   return true;
838*2d1272b8SAndroid Build Coastguard Worker }
839*2d1272b8SAndroid Build Coastguard Worker 
840*2d1272b8SAndroid Build Coastguard Worker gboolean
collect_rest(const char * name,const char * arg,gpointer data,GError ** error)841*2d1272b8SAndroid Build Coastguard Worker subset_main_t::collect_rest (const char *name,
842*2d1272b8SAndroid Build Coastguard Worker 			     const char *arg,
843*2d1272b8SAndroid Build Coastguard Worker 			     gpointer    data,
844*2d1272b8SAndroid Build Coastguard Worker 			     GError    **error)
845*2d1272b8SAndroid Build Coastguard Worker {
846*2d1272b8SAndroid Build Coastguard Worker   subset_main_t *thiz = (subset_main_t *) data;
847*2d1272b8SAndroid Build Coastguard Worker 
848*2d1272b8SAndroid Build Coastguard Worker   if (!thiz->font_file)
849*2d1272b8SAndroid Build Coastguard Worker   {
850*2d1272b8SAndroid Build Coastguard Worker     thiz->font_file = g_strdup (arg);
851*2d1272b8SAndroid Build Coastguard Worker     return true;
852*2d1272b8SAndroid Build Coastguard Worker   }
853*2d1272b8SAndroid Build Coastguard Worker 
854*2d1272b8SAndroid Build Coastguard Worker   parse_text (name, arg, data, error);
855*2d1272b8SAndroid Build Coastguard Worker   return true;
856*2d1272b8SAndroid Build Coastguard Worker }
857*2d1272b8SAndroid Build Coastguard Worker 
858*2d1272b8SAndroid Build Coastguard Worker void
add_options()859*2d1272b8SAndroid Build Coastguard Worker subset_main_t::add_options ()
860*2d1272b8SAndroid Build Coastguard Worker {
861*2d1272b8SAndroid Build Coastguard Worker   set_summary ("Subset fonts to specification.");
862*2d1272b8SAndroid Build Coastguard Worker 
863*2d1272b8SAndroid Build Coastguard Worker   face_options_t::add_options (this);
864*2d1272b8SAndroid Build Coastguard Worker 
865*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry glyphset_entries[] =
866*2d1272b8SAndroid Build Coastguard Worker   {
867*2d1272b8SAndroid Build Coastguard Worker     {"gids",		'g', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,
868*2d1272b8SAndroid Build Coastguard Worker      "Specify glyph IDs or ranges to include in the subset.\n"
869*2d1272b8SAndroid Build Coastguard Worker      "                                                        "
870*2d1272b8SAndroid Build Coastguard Worker      "Use --gids-=... to subtract codepoints from the current set.", "list of glyph indices/ranges or *"},
871*2d1272b8SAndroid Build Coastguard Worker     {"gids-",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,			"Specify glyph IDs or ranges to remove from the subset", "list of glyph indices/ranges or *"},
872*2d1272b8SAndroid Build Coastguard Worker     {"gids+",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids,			"Specify glyph IDs or ranges to include in the subset", "list of glyph indices/ranges or *"},
873*2d1272b8SAndroid Build Coastguard Worker     {"gids-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_gids>,	"Specify file to read glyph IDs or ranges from", "filename"},
874*2d1272b8SAndroid Build Coastguard Worker     {"glyphs",		0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs,			"Specify glyph names to include in the subset. Use --glyphs-=... to subtract glyphs from the current set.", "list of glyph names or *"},
875*2d1272b8SAndroid Build Coastguard Worker     {"glyphs+",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs,			"Specify glyph names to include in the subset", "list of glyph names"},
876*2d1272b8SAndroid Build Coastguard Worker     {"glyphs-",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyphs,			"Specify glyph names to remove from the subset", "list of glyph names"},
877*2d1272b8SAndroid Build Coastguard Worker 
878*2d1272b8SAndroid Build Coastguard Worker 
879*2d1272b8SAndroid Build Coastguard Worker     {"glyphs-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_glyphs>,	"Specify file to read glyph names from", "filename"},
880*2d1272b8SAndroid Build Coastguard Worker 
881*2d1272b8SAndroid Build Coastguard Worker     {"text",		't', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,			"Specify text to include in the subset. Use --text-=... to subtract codepoints from the current set.", "string"},
882*2d1272b8SAndroid Build Coastguard Worker     {"text-",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,			"Specify text to remove from the subset", "string"},
883*2d1272b8SAndroid Build Coastguard Worker     {"text+",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text,			"Specify text to include in the subset", "string"},
884*2d1272b8SAndroid Build Coastguard Worker 
885*2d1272b8SAndroid Build Coastguard Worker 
886*2d1272b8SAndroid Build Coastguard Worker     {"text-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_text, false>,"Specify file to read text from", "filename"},
887*2d1272b8SAndroid Build Coastguard Worker     {"unicodes",	'u', 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes,
888*2d1272b8SAndroid Build Coastguard Worker      "Specify Unicode codepoints or ranges to include in the subset. Use * to include all codepoints.\n"
889*2d1272b8SAndroid Build Coastguard Worker      "                                                        "
890*2d1272b8SAndroid Build Coastguard Worker      "--unicodes-=... can be used to subtract codepoints from the current set.\n"
891*2d1272b8SAndroid Build Coastguard Worker      "                                                        "
892*2d1272b8SAndroid Build Coastguard Worker      "For example: --unicodes=* --unicodes-=41,42,43 would create a subset with all codepoints\n"
893*2d1272b8SAndroid Build Coastguard Worker      "                                                        "
894*2d1272b8SAndroid Build Coastguard Worker      "except for 41, 42, 43.",
895*2d1272b8SAndroid Build Coastguard Worker      "list of hex numbers/ranges or *"},
896*2d1272b8SAndroid Build Coastguard Worker     {"unicodes-",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Specify Unicode codepoints or ranges to remove from the subset", "list of hex numbers/ranges or *"},
897*2d1272b8SAndroid Build Coastguard Worker     {"unicodes+",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes, "Specify Unicode codepoints or ranges to include in the subset", "list of hex numbers/ranges or *"},
898*2d1272b8SAndroid Build Coastguard Worker 
899*2d1272b8SAndroid Build Coastguard Worker     {"unicodes-file",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_file_for<parse_unicodes>,"Specify file to read Unicode codepoints or ranges from", "filename"},
900*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
901*2d1272b8SAndroid Build Coastguard Worker   };
902*2d1272b8SAndroid Build Coastguard Worker   add_group (glyphset_entries,
903*2d1272b8SAndroid Build Coastguard Worker 	     "subset-glyphset",
904*2d1272b8SAndroid Build Coastguard Worker 	     "Subset glyph-set option:",
905*2d1272b8SAndroid Build Coastguard Worker 	     "Subsetting glyph-set options",
906*2d1272b8SAndroid Build Coastguard Worker 	     this);
907*2d1272b8SAndroid Build Coastguard Worker 
908*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry other_entries[] =
909*2d1272b8SAndroid Build Coastguard Worker   {
910*2d1272b8SAndroid Build Coastguard Worker     {"gid-map", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_glyph_map, "Specify a glyph mapping to use, any unmapped gids will be automatically assigned.", "List of pairs old_gid1:new_gid1,old_gid2:new_gid2,..."},
911*2d1272b8SAndroid Build Coastguard Worker     {"name-IDs",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,		"Subset specified nameids. Use --name-IDs-=... to subtract from the current set.", "list of int numbers or *"},
912*2d1272b8SAndroid Build Coastguard Worker     {"name-IDs-",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,		"Subset specified nameids", "list of int numbers or *"},
913*2d1272b8SAndroid Build Coastguard Worker     {"name-IDs+",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids,		"Subset specified nameids", "list of int numbers or *"},
914*2d1272b8SAndroid Build Coastguard Worker     {"name-languages",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,	"Subset nameRecords with specified language IDs. Use --name-languages-=... to subtract from the current set.", "list of int numbers or *"},
915*2d1272b8SAndroid Build Coastguard Worker     {"name-languages-",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,	"Subset nameRecords with specified language IDs", "list of int numbers or *"},
916*2d1272b8SAndroid Build Coastguard Worker     {"name-languages+",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages,	"Subset nameRecords with specified language IDs", "list of int numbers or *"},
917*2d1272b8SAndroid Build Coastguard Worker 
918*2d1272b8SAndroid Build Coastguard Worker     {"layout-features",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,	"Specify set of layout feature tags that will be preserved. Use --layout-features-=... to subtract from the current set.", "list of string table tags or *"},
919*2d1272b8SAndroid Build Coastguard Worker     {"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,	"Specify set of layout feature tags that will be preserved", "list of string tags or *"},
920*2d1272b8SAndroid Build Coastguard Worker     {"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features,	"Specify set of layout feature tags that will be preserved", "list of string tags or *"},
921*2d1272b8SAndroid Build Coastguard Worker 
922*2d1272b8SAndroid Build Coastguard Worker     {"layout-scripts",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts,	"Specify set of layout script tags that will be preserved. Use --layout-scripts-=... to subtract from the current set.", "list of string table tags or *"},
923*2d1272b8SAndroid Build Coastguard Worker     {"layout-scripts+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts,	"Specify set of layout script tags that will be preserved", "list of string tags or *"},
924*2d1272b8SAndroid Build Coastguard Worker     {"layout-scripts-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts,	"Specify set of layout script tags that will be preserved", "list of string tags or *"},
925*2d1272b8SAndroid Build Coastguard Worker 
926*2d1272b8SAndroid Build Coastguard Worker     {"drop-tables",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,	"Drop the specified tables. Use --drop-tables-=... to subtract from the current set.", "list of string table tags or *"},
927*2d1272b8SAndroid Build Coastguard Worker     {"drop-tables+",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,	"Drop the specified tables.", "list of string table tags or *"},
928*2d1272b8SAndroid Build Coastguard Worker     {"drop-tables-",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables,	"Drop the specified tables.", "list of string table tags or *"},
929*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_VAR
930*2d1272b8SAndroid Build Coastguard Worker      {"variations",	0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
931*2d1272b8SAndroid Build Coastguard Worker      "(Partially|Fully) Instantiate a variable font. A location consists of the tag "
932*2d1272b8SAndroid Build Coastguard Worker      "of a variation axis, followed by '=', followed by a number or the literal "
933*2d1272b8SAndroid Build Coastguard Worker      "string 'drop'. For example: --variations=\"wdth=100 wght=200\" or --variations=\"wdth=drop\""
934*2d1272b8SAndroid Build Coastguard Worker      ,
935*2d1272b8SAndroid Build Coastguard Worker      "list of comma separated axis-locations."
936*2d1272b8SAndroid Build Coastguard Worker      },
937*2d1272b8SAndroid Build Coastguard Worker      {"instance",	0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_instance,
938*2d1272b8SAndroid Build Coastguard Worker      "Alias for --variations.", "list of comma separated axis-locations"},
939*2d1272b8SAndroid Build Coastguard Worker #endif
940*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
941*2d1272b8SAndroid Build Coastguard Worker   };
942*2d1272b8SAndroid Build Coastguard Worker   add_group (other_entries,
943*2d1272b8SAndroid Build Coastguard Worker 	     "subset-other",
944*2d1272b8SAndroid Build Coastguard Worker 	     "Subset other option:",
945*2d1272b8SAndroid Build Coastguard Worker 	     "Subsetting other options",
946*2d1272b8SAndroid Build Coastguard Worker 	     this);
947*2d1272b8SAndroid Build Coastguard Worker 
948*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry flag_entries[] =
949*2d1272b8SAndroid Build Coastguard Worker   {
950*2d1272b8SAndroid Build Coastguard Worker     {"keep-everything",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &_keep_everything,
951*2d1272b8SAndroid Build Coastguard Worker      "Keep everything by default. Options after this can override the operation.", nullptr},
952*2d1272b8SAndroid Build Coastguard Worker     {"no-hinting",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_HINTING>,		"Whether to drop hints", nullptr},
953*2d1272b8SAndroid Build Coastguard Worker     {"retain-gids",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_RETAIN_GIDS>,		"If set don't renumber glyph ids in the subset.", nullptr},
954*2d1272b8SAndroid Build Coastguard Worker     {"desubroutinize",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_DESUBROUTINIZE>,		"Remove CFF/CFF2 use of subroutines", nullptr},
955*2d1272b8SAndroid Build Coastguard Worker     {"name-legacy",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NAME_LEGACY>,		"Keep legacy (non-Unicode) 'name' table entries", nullptr},
956*2d1272b8SAndroid Build Coastguard Worker     {"set-overlaps-flag",	0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG>,	"Set the overlaps flag on each glyph.", nullptr},
957*2d1272b8SAndroid Build Coastguard Worker     {"notdef-outline",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NOTDEF_OUTLINE>,		"Keep the outline of \'.notdef\' glyph", nullptr},
958*2d1272b8SAndroid Build Coastguard Worker     {"no-prune-unicode-ranges",	0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>,	"Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
959*2d1272b8SAndroid Build Coastguard Worker     {"no-layout-closure",	0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE>,	"Don't perform glyph closure for layout substitution (GSUB).", nullptr},
960*2d1272b8SAndroid Build Coastguard Worker     {"glyph-names",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>,		"Keep PS glyph names in TT-flavored fonts. ", nullptr},
961*2d1272b8SAndroid Build Coastguard Worker     {"passthrough-tables",	0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>,	"Do not drop tables that the tool does not know how to subset.", nullptr},
962*2d1272b8SAndroid Build Coastguard Worker     {"preprocess-face",		0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &this->preprocess,
963*2d1272b8SAndroid Build Coastguard Worker      "Alternative name for --preprocess.", nullptr},
964*2d1272b8SAndroid Build Coastguard Worker     {"preprocess",		0, 0, G_OPTION_ARG_NONE, &this->preprocess,
965*2d1272b8SAndroid Build Coastguard Worker      "If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr},
966*2d1272b8SAndroid Build Coastguard Worker #ifdef HB_EXPERIMENTAL_API
967*2d1272b8SAndroid Build Coastguard Worker     {"iftb-requirements",	0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_IFTB_REQUIREMENTS>,	"Enforce requirements needed to use the subset with incremental font transfer IFTB patches.", nullptr},
968*2d1272b8SAndroid Build Coastguard Worker #endif
969*2d1272b8SAndroid Build Coastguard Worker     {"optimize",		0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS>,	"Perform IUP delta optimization on the resulting gvar table's deltas", nullptr},
970*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
971*2d1272b8SAndroid Build Coastguard Worker   };
972*2d1272b8SAndroid Build Coastguard Worker   add_group (flag_entries,
973*2d1272b8SAndroid Build Coastguard Worker 	     "subset-flags",
974*2d1272b8SAndroid Build Coastguard Worker 	     "Subset boolean option:",
975*2d1272b8SAndroid Build Coastguard Worker 	     "Subsetting boolean options",
976*2d1272b8SAndroid Build Coastguard Worker 	     this);
977*2d1272b8SAndroid Build Coastguard Worker 
978*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry app_entries[] =
979*2d1272b8SAndroid Build Coastguard Worker   {
980*2d1272b8SAndroid Build Coastguard Worker     {"num-iterations",	'n', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT,
981*2d1272b8SAndroid Build Coastguard Worker      &this->num_iterations,
982*2d1272b8SAndroid Build Coastguard Worker      "Run subsetter N times (default: 1)", "N"},
983*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
984*2d1272b8SAndroid Build Coastguard Worker   };
985*2d1272b8SAndroid Build Coastguard Worker   add_group (app_entries,
986*2d1272b8SAndroid Build Coastguard Worker 	     "subset-app",
987*2d1272b8SAndroid Build Coastguard Worker 	     "Subset app option:",
988*2d1272b8SAndroid Build Coastguard Worker 	     "Subsetting application options",
989*2d1272b8SAndroid Build Coastguard Worker 	     this);
990*2d1272b8SAndroid Build Coastguard Worker 
991*2d1272b8SAndroid Build Coastguard Worker   output_options_t::add_options (this);
992*2d1272b8SAndroid Build Coastguard Worker 
993*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry entries[] =
994*2d1272b8SAndroid Build Coastguard Worker   {
995*2d1272b8SAndroid Build Coastguard Worker     {G_OPTION_REMAINING,	0, G_OPTION_FLAG_IN_MAIN,
996*2d1272b8SAndroid Build Coastguard Worker 			      G_OPTION_ARG_CALLBACK,	(gpointer) &collect_rest,	nullptr,	"[FONT-FILE] [TEXT]"},
997*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
998*2d1272b8SAndroid Build Coastguard Worker   };
999*2d1272b8SAndroid Build Coastguard Worker   add_main_group (entries, this);
1000*2d1272b8SAndroid Build Coastguard Worker   option_parser_t::add_options ();
1001*2d1272b8SAndroid Build Coastguard Worker }
1002*2d1272b8SAndroid Build Coastguard Worker 
1003*2d1272b8SAndroid Build Coastguard Worker int
main(int argc,char ** argv)1004*2d1272b8SAndroid Build Coastguard Worker main (int argc, char **argv)
1005*2d1272b8SAndroid Build Coastguard Worker {
1006*2d1272b8SAndroid Build Coastguard Worker   return batch_main<subset_main_t, true> (argc, argv);
1007*2d1272b8SAndroid Build Coastguard Worker }
1008