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