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 #undef MIN
     58 template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
     59 
     60 #undef MAX
     61 template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
     62 
     63 
     64 void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN;
     65 
     66 
     67 extern hb_bool_t debug;
     68 
     69 struct 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 
     78 struct 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 
    116 struct 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 
    142 struct 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     hb_buffer_guess_segment_properties (buffer);
    174   }
    175 
    176   void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
    177 			const char *text_before, const char *text_after)
    178   {
    179     hb_buffer_clear_contents (buffer);
    180     if (text_before) {
    181       unsigned int len = strlen (text_before);
    182       hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
    183     }
    184     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
    185     if (text_after) {
    186       hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
    187     }
    188 
    189     if (!utf8_clusters) {
    190       /* Reset cluster values to refer to Unicode character index
    191        * instead of UTF-8 index. */
    192       unsigned int num_glyphs = hb_buffer_get_length (buffer);
    193       hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
    194       for (unsigned int i = 0; i < num_glyphs; i++)
    195       {
    196 	info->cluster = i;
    197 	info++;
    198       }
    199     }
    200 
    201     setup_buffer (buffer);
    202   }
    203 
    204   hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer)
    205   {
    206     hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers);
    207     if (normalize_glyphs)
    208       hb_buffer_normalize_glyphs (buffer);
    209     return res;
    210   }
    211 
    212   void shape_closure (const char *text, int text_len,
    213 		      hb_font_t *font, hb_buffer_t *buffer,
    214 		      hb_set_t *glyphs)
    215   {
    216     hb_buffer_reset (buffer);
    217     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
    218     setup_buffer (buffer);
    219     hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
    220   }
    221 
    222   /* Buffer properties */
    223   const char *direction;
    224   const char *language;
    225   const char *script;
    226 
    227   /* Buffer flags */
    228   hb_bool_t bot;
    229   hb_bool_t eot;
    230   hb_bool_t preserve_default_ignorables;
    231 
    232   hb_feature_t *features;
    233   unsigned int num_features;
    234   char **shapers;
    235   hb_bool_t utf8_clusters;
    236   hb_bool_t normalize_glyphs;
    237 };
    238 
    239 
    240 struct font_options_t : option_group_t
    241 {
    242   font_options_t (option_parser_t *parser) {
    243     font_file = NULL;
    244     face_index = 0;
    245 
    246     font = NULL;
    247 
    248     add_options (parser);
    249   }
    250   ~font_options_t (void) {
    251     hb_font_destroy (font);
    252   }
    253 
    254   void add_options (option_parser_t *parser);
    255 
    256   hb_font_t *get_font (void) const;
    257 
    258   const char *font_file;
    259   int face_index;
    260 
    261   private:
    262   mutable hb_font_t *font;
    263 };
    264 
    265 
    266 struct text_options_t : option_group_t
    267 {
    268   text_options_t (option_parser_t *parser) {
    269     text_before = NULL;
    270     text_after = NULL;
    271 
    272     text = NULL;
    273     text_file = NULL;
    274 
    275     fp = NULL;
    276     gs = NULL;
    277     text_len = (unsigned int) -1;
    278 
    279     add_options (parser);
    280   }
    281   ~text_options_t (void) {
    282     if (gs)
    283       g_string_free (gs, true);
    284     if (fp)
    285       fclose (fp);
    286   }
    287 
    288   void add_options (option_parser_t *parser);
    289 
    290   void post_parse (GError **error G_GNUC_UNUSED) {
    291     if (text && text_file)
    292       g_set_error (error,
    293 		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
    294 		   "Only one of text and text-file can be set");
    295 
    296   };
    297 
    298   const char *get_line (unsigned int *len);
    299 
    300   const char *text_before;
    301   const char *text_after;
    302 
    303   const char *text;
    304   const char *text_file;
    305 
    306   private:
    307   FILE *fp;
    308   GString *gs;
    309   unsigned int text_len;
    310 };
    311 
    312 struct output_options_t : option_group_t
    313 {
    314   output_options_t (option_parser_t *parser,
    315 		    const char *supported_formats_ = NULL) {
    316     output_file = NULL;
    317     output_format = NULL;
    318     supported_formats = supported_formats_;
    319     explicit_output_format = false;
    320 
    321     fp = NULL;
    322 
    323     add_options (parser);
    324   }
    325   ~output_options_t (void) {
    326     if (fp)
    327       fclose (fp);
    328   }
    329 
    330   void add_options (option_parser_t *parser);
    331 
    332   void post_parse (GError **error G_GNUC_UNUSED)
    333   {
    334     if (output_format)
    335       explicit_output_format = true;
    336 
    337     if (output_file && !output_format) {
    338       output_format = strrchr (output_file, '.');
    339       if (output_format)
    340 	  output_format++; /* skip the dot */
    341     }
    342 
    343     if (output_file && 0 == strcmp (output_file, "-"))
    344       output_file = NULL; /* STDOUT */
    345   }
    346 
    347   FILE *get_file_handle (void);
    348 
    349   const char *output_file;
    350   const char *output_format;
    351   const char *supported_formats;
    352   bool explicit_output_format;
    353 
    354   mutable FILE *fp;
    355 };
    356 
    357 struct format_options_t : option_group_t
    358 {
    359   format_options_t (option_parser_t *parser) {
    360     show_glyph_names = true;
    361     show_positions = true;
    362     show_clusters = true;
    363     show_text = false;
    364     show_unicode = false;
    365     show_line_num = false;
    366 
    367     add_options (parser);
    368   }
    369 
    370   void add_options (option_parser_t *parser);
    371 
    372   void serialize_unicode (hb_buffer_t  *buffer,
    373 			  GString      *gs);
    374   void serialize_glyphs (hb_buffer_t  *buffer,
    375 			 hb_font_t    *font,
    376 			 hb_buffer_serialize_format_t format,
    377 			 hb_buffer_serialize_flags_t flags,
    378 			 GString      *gs);
    379   void serialize_line_no (unsigned int  line_no,
    380 			  GString      *gs);
    381   void serialize_buffer_of_text (hb_buffer_t  *buffer,
    382 				 unsigned int  line_no,
    383 				 const char   *text,
    384 				 unsigned int  text_len,
    385 				 hb_font_t    *font,
    386 				 GString      *gs);
    387   void serialize_message (unsigned int  line_no,
    388 			  const char   *msg,
    389 			  GString      *gs);
    390   void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
    391 				   unsigned int  line_no,
    392 				   const char   *text,
    393 				   unsigned int  text_len,
    394 				   hb_font_t    *font,
    395 				   hb_buffer_serialize_format_t output_format,
    396 				   hb_buffer_serialize_flags_t format_flags,
    397 				   GString      *gs);
    398 
    399 
    400   hb_bool_t show_glyph_names;
    401   hb_bool_t show_positions;
    402   hb_bool_t show_clusters;
    403   hb_bool_t show_text;
    404   hb_bool_t show_unicode;
    405   hb_bool_t show_line_num;
    406 };
    407 
    408 
    409 #endif
    410