options.hh revision 407f80d62589774f845ef1a6a0a7d841b09d57c6
1/*
2 * Copyright © 2011  Google, Inc.
3 *
4 *  This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
27#ifndef OPTIONS_HH
28#define OPTIONS_HH
29
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <stdlib.h>
36#include <stddef.h>
37#include <string.h>
38#include <stdio.h>
39#include <math.h>
40#include <locale.h>
41#include <errno.h>
42#include <fcntl.h>
43#ifdef HAVE_UNISTD_H
44#include <unistd.h> /* for isatty() */
45#endif
46#ifdef HAVE_IO_H
47#include <io.h> /* for _setmode() under Windows */
48#endif
49
50#include <hb.h>
51#ifdef HAVE_OT
52#include <hb-ot.h>
53#endif
54#include <glib.h>
55#include <glib/gprintf.h>
56
57#undef MIN
58template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
59
60#undef MAX
61template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
62
63
64void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN;
65
66
67extern hb_bool_t debug;
68
69struct option_group_t
70{
71  virtual void add_options (struct option_parser_t *parser) = 0;
72
73  virtual void pre_parse (GError **error G_GNUC_UNUSED) {};
74  virtual void post_parse (GError **error G_GNUC_UNUSED) {};
75};
76
77
78struct option_parser_t
79{
80  option_parser_t (const char *usage) {
81    memset (this, 0, sizeof (*this));
82    usage_str = usage;
83    context = g_option_context_new (usage);
84
85    add_main_options ();
86  }
87  ~option_parser_t (void) {
88    g_option_context_free (context);
89  }
90
91  void add_main_options (void);
92
93  void add_group (GOptionEntry   *entries,
94		  const gchar    *name,
95		  const gchar    *description,
96		  const gchar    *help_description,
97		  option_group_t *option_group);
98
99  void parse (int *argc, char ***argv);
100
101  G_GNUC_NORETURN void usage (void) {
102    g_printerr ("Usage: %s [OPTION...] %s\n", g_get_prgname (), usage_str);
103    exit (1);
104  }
105
106  const char *usage_str;
107  GOptionContext *context;
108};
109
110
111#define DEFAULT_MARGIN 16
112#define DEFAULT_FORE "#000000"
113#define DEFAULT_BACK "#FFFFFF"
114#define DEFAULT_FONT_SIZE 256
115
116struct view_options_t : option_group_t
117{
118  view_options_t (option_parser_t *parser) {
119    annotate = false;
120    fore = DEFAULT_FORE;
121    back = DEFAULT_BACK;
122    line_space = 0;
123    margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
124    font_size = DEFAULT_FONT_SIZE;
125
126    add_options (parser);
127  }
128
129  void add_options (option_parser_t *parser);
130
131  hb_bool_t annotate;
132  const char *fore;
133  const char *back;
134  double line_space;
135  struct margin_t {
136    double t, r, b, l;
137  } margin;
138  double font_size;
139};
140
141
142struct shape_options_t : option_group_t
143{
144  shape_options_t (option_parser_t *parser)
145  {
146    direction = language = script = NULL;
147    bot = eot = preserve_default_ignorables = false;
148    features = NULL;
149    num_features = 0;
150    shapers = NULL;
151    utf8_clusters = false;
152    normalize_glyphs = false;
153
154    add_options (parser);
155  }
156  ~shape_options_t (void)
157  {
158    free (features);
159    g_strfreev (shapers);
160  }
161
162  void add_options (option_parser_t *parser);
163
164  void setup_buffer (hb_buffer_t *buffer)
165  {
166    hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
167    hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
168    hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
169    hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAGS_DEFAULT |
170			 (bot ? HB_BUFFER_FLAG_BOT : 0) |
171			 (eot ? HB_BUFFER_FLAG_EOT : 0) |
172			 (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0)));
173  }
174
175  void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
176			const char *text_before, const char *text_after)
177  {
178    hb_buffer_clear (buffer);
179    if (text_before) {
180      unsigned int len = strlen (text_before);
181      hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
182    }
183    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
184    if (text_after) {
185      hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
186    }
187
188    if (!utf8_clusters) {
189      /* Reset cluster values to refer to Unicode character index
190       * instead of UTF-8 index. */
191      unsigned int num_glyphs = hb_buffer_get_length (buffer);
192      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
193      for (unsigned int i = 0; i < num_glyphs; i++)
194      {
195	info->cluster = i;
196	info++;
197      }
198    }
199
200    setup_buffer (buffer);
201  }
202
203  hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer)
204  {
205    hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers);
206    if (normalize_glyphs)
207      hb_buffer_normalize_glyphs (buffer);
208    return res;
209  }
210
211  void shape_closure (const char *text, int text_len,
212		      hb_font_t *font, hb_buffer_t *buffer,
213		      hb_set_t *glyphs)
214  {
215    hb_buffer_reset (buffer);
216    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
217    setup_buffer (buffer);
218    hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
219  }
220
221  /* Buffer properties */
222  const char *direction;
223  const char *language;
224  const char *script;
225
226  /* Buffer flags */
227  hb_bool_t bot;
228  hb_bool_t eot;
229  hb_bool_t preserve_default_ignorables;
230
231  hb_feature_t *features;
232  unsigned int num_features;
233  char **shapers;
234  hb_bool_t utf8_clusters;
235  hb_bool_t normalize_glyphs;
236};
237
238
239struct font_options_t : option_group_t
240{
241  font_options_t (option_parser_t *parser) {
242    font_file = NULL;
243    face_index = 0;
244
245    font = NULL;
246
247    add_options (parser);
248  }
249  ~font_options_t (void) {
250    hb_font_destroy (font);
251  }
252
253  void add_options (option_parser_t *parser);
254
255  hb_font_t *get_font (void) const;
256
257  const char *font_file;
258  int face_index;
259
260  private:
261  mutable hb_font_t *font;
262};
263
264
265struct text_options_t : option_group_t
266{
267  text_options_t (option_parser_t *parser) {
268    text_before = NULL;
269    text_after = NULL;
270
271    text = NULL;
272    text_file = NULL;
273
274    fp = NULL;
275    gs = NULL;
276    text_len = (unsigned int) -1;
277
278    add_options (parser);
279  }
280  ~text_options_t (void) {
281    if (gs)
282      g_string_free (gs, true);
283    if (fp)
284      fclose (fp);
285  }
286
287  void add_options (option_parser_t *parser);
288
289  void post_parse (GError **error G_GNUC_UNUSED) {
290    if (text && text_file)
291      g_set_error (error,
292		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
293		   "Only one of text and text-file can be set");
294
295  };
296
297  const char *get_line (unsigned int *len);
298
299  const char *text_before;
300  const char *text_after;
301
302  const char *text;
303  const char *text_file;
304
305  private:
306  FILE *fp;
307  GString *gs;
308  unsigned int text_len;
309};
310
311struct output_options_t : option_group_t
312{
313  output_options_t (option_parser_t *parser) {
314    output_file = NULL;
315    output_format = NULL;
316
317    fp = NULL;
318
319    add_options (parser);
320  }
321  ~output_options_t (void) {
322    if (fp)
323      fclose (fp);
324  }
325
326  void add_options (option_parser_t *parser);
327
328  void post_parse (GError **error G_GNUC_UNUSED)
329  {
330    if (output_file && !output_format) {
331      output_format = strrchr (output_file, '.');
332      if (output_format)
333	  output_format++; /* skip the dot */
334    }
335
336    if (output_file && 0 == strcmp (output_file, "-"))
337      output_file = NULL; /* STDOUT */
338  }
339
340  FILE *get_file_handle (void);
341
342  const char *output_file;
343  const char *output_format;
344
345  mutable FILE *fp;
346};
347
348struct format_options_t : option_group_t
349{
350  format_options_t (option_parser_t *parser) {
351    show_glyph_names = true;
352    show_positions = true;
353    show_clusters = true;
354    show_text = false;
355    show_unicode = false;
356    show_line_num = false;
357
358    add_options (parser);
359  }
360
361  void add_options (option_parser_t *parser);
362
363  void serialize_unicode (hb_buffer_t  *buffer,
364			  GString      *gs);
365  void serialize_glyphs (hb_buffer_t  *buffer,
366			 hb_font_t    *font,
367			 hb_bool_t    utf8_clusters,
368			 GString      *gs);
369  void serialize_line_no (unsigned int  line_no,
370			  GString      *gs);
371  void serialize_buffer_of_text (hb_buffer_t  *buffer,
372				 unsigned int  line_no,
373				 const char   *text,
374				 unsigned int  text_len,
375				 hb_font_t    *font,
376				 hb_bool_t     utf8_clusters,
377				 GString      *gs);
378  void serialize_message (unsigned int  line_no,
379			  const char   *msg,
380			  GString      *gs);
381  void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
382				   unsigned int  line_no,
383				   const char   *text,
384				   unsigned int  text_len,
385				   hb_font_t    *font,
386				   hb_bool_t     utf8_clusters,
387				   GString      *gs);
388
389
390  hb_bool_t show_glyph_names;
391  hb_bool_t show_positions;
392  hb_bool_t show_clusters;
393  hb_bool_t show_text;
394  hb_bool_t show_unicode;
395  hb_bool_t show_line_num;
396};
397
398
399#endif
400