Home | History | Annotate | Download | only in util
      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 #if defined(_WIN32) || defined(__CYGWIN__)
     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 #if !GLIB_CHECK_VERSION (2, 22, 0)
     58 # define g_mapped_file_unref g_mapped_file_free
     59 #endif
     60 
     61 
     62 /* A few macros copied from hb-private.hh. */
     63 
     64 #if __GNUC__ >= 4
     65 #define HB_UNUSED	__attribute__((unused))
     66 #else
     67 #define HB_UNUSED
     68 #endif
     69 
     70 #undef MIN
     71 template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
     72 
     73 #undef MAX
     74 template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
     75 
     76 #undef  ARRAY_LENGTH
     77 template <typename Type, unsigned int n>
     78 static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
     79 /* A const version, but does not detect erratically being called on pointers. */
     80 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
     81 
     82 #define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
     83 #define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
     84 #define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))
     85 
     86 
     87 void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
     88 
     89 
     90 extern hb_bool_t debug;
     91 
     92 struct option_group_t
     93 {
     94   virtual void add_options (struct option_parser_t *parser) = 0;
     95 
     96   virtual void pre_parse (GError **error G_GNUC_UNUSED) {};
     97   virtual void post_parse (GError **error G_GNUC_UNUSED) {};
     98 };
     99 
    100 
    101 struct option_parser_t
    102 {
    103   option_parser_t (const char *usage) {
    104     memset (this, 0, sizeof (*this));
    105     usage_str = usage;
    106     context = g_option_context_new (usage);
    107     to_free = g_ptr_array_new ();
    108 
    109     add_main_options ();
    110   }
    111   ~option_parser_t (void) {
    112     g_option_context_free (context);
    113     g_ptr_array_foreach (to_free, (GFunc) g_free, NULL);
    114     g_ptr_array_free (to_free, TRUE);
    115   }
    116 
    117   void add_main_options (void);
    118 
    119   void add_group (GOptionEntry   *entries,
    120 		  const gchar    *name,
    121 		  const gchar    *description,
    122 		  const gchar    *help_description,
    123 		  option_group_t *option_group);
    124 
    125   void free_later (char *p) {
    126     g_ptr_array_add (to_free, p);
    127   }
    128 
    129   void parse (int *argc, char ***argv);
    130 
    131   G_GNUC_NORETURN void usage (void) {
    132     g_printerr ("Usage: %s [OPTION...] %s\n", g_get_prgname (), usage_str);
    133     exit (1);
    134   }
    135 
    136   private:
    137   const char *usage_str;
    138   GOptionContext *context;
    139   GPtrArray *to_free;
    140 };
    141 
    142 
    143 #define DEFAULT_MARGIN 16
    144 #define DEFAULT_FORE "#000000"
    145 #define DEFAULT_BACK "#FFFFFF"
    146 #define DEFAULT_FONT_SIZE 256
    147 
    148 struct view_options_t : option_group_t
    149 {
    150   view_options_t (option_parser_t *parser) {
    151     annotate = false;
    152     fore = DEFAULT_FORE;
    153     back = DEFAULT_BACK;
    154     line_space = 0;
    155     margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
    156     font_size = DEFAULT_FONT_SIZE;
    157 
    158     add_options (parser);
    159   }
    160 
    161   void add_options (option_parser_t *parser);
    162 
    163   hb_bool_t annotate;
    164   const char *fore;
    165   const char *back;
    166   double line_space;
    167   struct margin_t {
    168     double t, r, b, l;
    169   } margin;
    170   double font_size;
    171 };
    172 
    173 
    174 struct shape_options_t : option_group_t
    175 {
    176   shape_options_t (option_parser_t *parser)
    177   {
    178     direction = language = script = NULL;
    179     bot = eot = preserve_default_ignorables = false;
    180     features = NULL;
    181     num_features = 0;
    182     shapers = NULL;
    183     utf8_clusters = false;
    184     normalize_glyphs = false;
    185     num_iterations = 1;
    186 
    187     add_options (parser);
    188   }
    189   ~shape_options_t (void)
    190   {
    191     free (features);
    192     g_strfreev (shapers);
    193   }
    194 
    195   void add_options (option_parser_t *parser);
    196 
    197   void setup_buffer (hb_buffer_t *buffer)
    198   {
    199     hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
    200     hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
    201     hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
    202     hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_DEFAULT |
    203 			 (bot ? HB_BUFFER_FLAG_BOT : 0) |
    204 			 (eot ? HB_BUFFER_FLAG_EOT : 0) |
    205 			 (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0)));
    206     hb_buffer_guess_segment_properties (buffer);
    207   }
    208 
    209   void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
    210 			const char *text_before, const char *text_after)
    211   {
    212     hb_buffer_clear_contents (buffer);
    213     if (text_before) {
    214       unsigned int len = strlen (text_before);
    215       hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
    216     }
    217     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
    218     if (text_after) {
    219       hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
    220     }
    221 
    222     if (!utf8_clusters) {
    223       /* Reset cluster values to refer to Unicode character index
    224        * instead of UTF-8 index. */
    225       unsigned int num_glyphs = hb_buffer_get_length (buffer);
    226       hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
    227       for (unsigned int i = 0; i < num_glyphs; i++)
    228       {
    229 	info->cluster = i;
    230 	info++;
    231       }
    232     }
    233 
    234     setup_buffer (buffer);
    235   }
    236 
    237   hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer)
    238   {
    239     hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers);
    240     if (normalize_glyphs)
    241       hb_buffer_normalize_glyphs (buffer);
    242     return res;
    243   }
    244 
    245   void shape_closure (const char *text, int text_len,
    246 		      hb_font_t *font, hb_buffer_t *buffer,
    247 		      hb_set_t *glyphs)
    248   {
    249     hb_buffer_reset (buffer);
    250     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
    251     setup_buffer (buffer);
    252     hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
    253   }
    254 
    255   /* Buffer properties */
    256   const char *direction;
    257   const char *language;
    258   const char *script;
    259 
    260   /* Buffer flags */
    261   hb_bool_t bot;
    262   hb_bool_t eot;
    263   hb_bool_t preserve_default_ignorables;
    264 
    265   hb_feature_t *features;
    266   unsigned int num_features;
    267   char **shapers;
    268   hb_bool_t utf8_clusters;
    269   hb_bool_t normalize_glyphs;
    270   unsigned int num_iterations;
    271 };
    272 
    273 
    274 struct font_options_t : option_group_t
    275 {
    276   font_options_t (option_parser_t *parser) {
    277     font_file = NULL;
    278     face_index = 0;
    279     font_funcs = NULL;
    280 
    281     font = NULL;
    282 
    283     add_options (parser);
    284   }
    285   ~font_options_t (void) {
    286     hb_font_destroy (font);
    287   }
    288 
    289   void add_options (option_parser_t *parser);
    290 
    291   hb_font_t *get_font (void) const;
    292 
    293   const char *font_file;
    294   int face_index;
    295   const char *font_funcs;
    296 
    297   private:
    298   mutable hb_font_t *font;
    299 };
    300 
    301 
    302 struct text_options_t : option_group_t
    303 {
    304   text_options_t (option_parser_t *parser) {
    305     text_before = NULL;
    306     text_after = NULL;
    307 
    308     text = NULL;
    309     text_file = NULL;
    310 
    311     fp = NULL;
    312     gs = NULL;
    313     text_len = (unsigned int) -1;
    314 
    315     add_options (parser);
    316   }
    317   ~text_options_t (void) {
    318     if (gs)
    319       g_string_free (gs, true);
    320     if (fp)
    321       fclose (fp);
    322   }
    323 
    324   void add_options (option_parser_t *parser);
    325 
    326   void post_parse (GError **error G_GNUC_UNUSED) {
    327     if (text && text_file)
    328       g_set_error (error,
    329 		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
    330 		   "Only one of text and text-file can be set");
    331 
    332   };
    333 
    334   const char *get_line (unsigned int *len);
    335 
    336   const char *text_before;
    337   const char *text_after;
    338 
    339   const char *text;
    340   const char *text_file;
    341 
    342   private:
    343   FILE *fp;
    344   GString *gs;
    345   unsigned int text_len;
    346 };
    347 
    348 struct output_options_t : option_group_t
    349 {
    350   output_options_t (option_parser_t *parser,
    351 		    const char **supported_formats_ = NULL) {
    352     output_file = NULL;
    353     output_format = NULL;
    354     supported_formats = supported_formats_;
    355     explicit_output_format = false;
    356 
    357     fp = NULL;
    358 
    359     add_options (parser);
    360   }
    361   ~output_options_t (void) {
    362     if (fp)
    363       fclose (fp);
    364   }
    365 
    366   void add_options (option_parser_t *parser);
    367 
    368   void post_parse (GError **error G_GNUC_UNUSED)
    369   {
    370     if (output_format)
    371       explicit_output_format = true;
    372 
    373     if (output_file && !output_format) {
    374       output_format = strrchr (output_file, '.');
    375       if (output_format)
    376 	  output_format++; /* skip the dot */
    377     }
    378 
    379     if (output_file && 0 == strcmp (output_file, "-"))
    380       output_file = NULL; /* STDOUT */
    381   }
    382 
    383   FILE *get_file_handle (void);
    384 
    385   const char *output_file;
    386   const char *output_format;
    387   const char **supported_formats;
    388   bool explicit_output_format;
    389 
    390   mutable FILE *fp;
    391 };
    392 
    393 struct format_options_t : option_group_t
    394 {
    395   format_options_t (option_parser_t *parser) {
    396     show_glyph_names = true;
    397     show_positions = true;
    398     show_clusters = true;
    399     show_text = false;
    400     show_unicode = false;
    401     show_line_num = false;
    402 
    403     add_options (parser);
    404   }
    405 
    406   void add_options (option_parser_t *parser);
    407 
    408   void serialize_unicode (hb_buffer_t  *buffer,
    409 			  GString      *gs);
    410   void serialize_glyphs (hb_buffer_t  *buffer,
    411 			 hb_font_t    *font,
    412 			 hb_buffer_serialize_format_t format,
    413 			 hb_buffer_serialize_flags_t flags,
    414 			 GString      *gs);
    415   void serialize_line_no (unsigned int  line_no,
    416 			  GString      *gs);
    417   void serialize_buffer_of_text (hb_buffer_t  *buffer,
    418 				 unsigned int  line_no,
    419 				 const char   *text,
    420 				 unsigned int  text_len,
    421 				 hb_font_t    *font,
    422 				 GString      *gs);
    423   void serialize_message (unsigned int  line_no,
    424 			  const char   *msg,
    425 			  GString      *gs);
    426   void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
    427 				   unsigned int  line_no,
    428 				   const char   *text,
    429 				   unsigned int  text_len,
    430 				   hb_font_t    *font,
    431 				   hb_buffer_serialize_format_t output_format,
    432 				   hb_buffer_serialize_flags_t format_flags,
    433 				   GString      *gs);
    434 
    435 
    436   hb_bool_t show_glyph_names;
    437   hb_bool_t show_positions;
    438   hb_bool_t show_clusters;
    439   hb_bool_t show_text;
    440   hb_bool_t show_unicode;
    441   hb_bool_t show_line_num;
    442 };
    443 
    444 
    445 #endif
    446