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