options.hh 13.1 KB
Newer Older
B
Behdad Esfahbod 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 * Copyright © 2011  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Behdad Esfahbod
 */

#ifndef OPTIONS_HH
#define OPTIONS_HH


B
Behdad Esfahbod 已提交
31 32 33 34 35 36 37 38 39 40 41 42
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <locale.h>
#include <errno.h>
#include <fcntl.h>
43 44 45
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* for isatty() */
#endif
B
Behdad Esfahbod 已提交
46
#if defined(_WIN32) || defined(__CYGWIN__)
47
#include <io.h> /* for setmode() under Windows */
B
Behdad Esfahbod 已提交
48 49 50
#endif

#include <hb.h>
51 52 53
#ifdef HAVE_OT
#include <hb-ot.h>
#endif
B
Behdad Esfahbod 已提交
54 55 56
#include <glib.h>
#include <glib/gprintf.h>

B
Behdad Esfahbod 已提交
57 58 59 60
#if !GLIB_CHECK_VERSION (2, 22, 0)
# define g_mapped_file_unref g_mapped_file_free
#endif

61 62 63 64 65 66 67 68 69

/* A few macros copied from hb-private.hh. */

#if __GNUC__ >= 4
#define HB_UNUSED	__attribute__((unused))
#else
#define HB_UNUSED
#endif

70 71 72 73 74 75
#undef MIN
template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }

#undef MAX
template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }

76 77 78 79 80 81 82 83 84 85
#undef  ARRAY_LENGTH
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))

#define _ASSERT_STATIC1(_line, _cond)	HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
#define _ASSERT_STATIC0(_line, _cond)	_ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond)		_ASSERT_STATIC0 (__LINE__, (_cond))

86

B
Behdad Esfahbod 已提交
87
void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
B
Behdad Esfahbod 已提交
88 89


B
Behdad Esfahbod 已提交
90
extern hb_bool_t debug;
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

struct option_group_t
{
  virtual void add_options (struct option_parser_t *parser) = 0;

  virtual void pre_parse (GError **error G_GNUC_UNUSED) {};
  virtual void post_parse (GError **error G_GNUC_UNUSED) {};
};


struct option_parser_t
{
  option_parser_t (const char *usage) {
    memset (this, 0, sizeof (*this));
    usage_str = usage;
    context = g_option_context_new (usage);
B
Behdad Esfahbod 已提交
107
    to_free = g_ptr_array_new ();
108 109 110 111 112

    add_main_options ();
  }
  ~option_parser_t (void) {
    g_option_context_free (context);
B
Behdad Esfahbod 已提交
113 114
    g_ptr_array_foreach (to_free, (GFunc) g_free, NULL);
    g_ptr_array_free (to_free, TRUE);
115 116 117 118 119 120 121 122 123 124
  }

  void add_main_options (void);

  void add_group (GOptionEntry   *entries,
		  const gchar    *name,
		  const gchar    *description,
		  const gchar    *help_description,
		  option_group_t *option_group);

B
Behdad Esfahbod 已提交
125 126 127 128
  void free_later (char *p) {
    g_ptr_array_add (to_free, p);
  }

129 130 131 132 133 134 135
  void parse (int *argc, char ***argv);

  G_GNUC_NORETURN void usage (void) {
    g_printerr ("Usage: %s [OPTION...] %s\n", g_get_prgname (), usage_str);
    exit (1);
  }

B
Behdad Esfahbod 已提交
136
  private:
137 138
  const char *usage_str;
  GOptionContext *context;
B
Behdad Esfahbod 已提交
139
  GPtrArray *to_free;
140 141 142
};


B
Behdad Esfahbod 已提交
143
#define DEFAULT_MARGIN 16
144 145
#define DEFAULT_FORE "#000000"
#define DEFAULT_BACK "#FFFFFF"
146 147
#define FONT_SIZE_UPEM 0x7FFFFFFF
#define FONT_SIZE_NONE 0
148

149
struct view_options_t : option_group_t
B
Behdad Esfahbod 已提交
150
{
151 152
  view_options_t (option_parser_t *parser) {
    annotate = false;
B
Behdad Esfahbod 已提交
153 154
    fore = NULL;
    back = NULL;
155
    line_space = 0;
156
    margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
157 158

    add_options (parser);
B
Behdad Esfahbod 已提交
159
  }
B
Behdad Esfahbod 已提交
160 161 162 163 164
  ~view_options_t (void)
  {
    g_free (fore);
    g_free (back);
  }
B
Behdad Esfahbod 已提交
165

166
  void add_options (option_parser_t *parser);
B
Behdad Esfahbod 已提交
167

B
Behdad Esfahbod 已提交
168
  hb_bool_t annotate;
B
Behdad Esfahbod 已提交
169 170
  char *fore;
  char *back;
B
Behdad Esfahbod 已提交
171 172 173 174
  double line_space;
  struct margin_t {
    double t, r, b, l;
  } margin;
175
};
B
Behdad Esfahbod 已提交
176

177

178
struct shape_options_t : option_group_t
B
Behdad Esfahbod 已提交
179
{
B
Behdad Esfahbod 已提交
180 181
  shape_options_t (option_parser_t *parser)
  {
182
    direction = language = script = NULL;
183
    bot = eot = preserve_default_ignorables = false;
184 185 186
    features = NULL;
    num_features = 0;
    shapers = NULL;
B
Behdad Esfahbod 已提交
187
    utf8_clusters = false;
188
    cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
189
    normalize_glyphs = false;
190
    verify = false;
B
Behdad Esfahbod 已提交
191
    num_iterations = 1;
192 193

    add_options (parser);
B
Behdad Esfahbod 已提交
194
  }
B
Behdad Esfahbod 已提交
195 196
  ~shape_options_t (void)
  {
B
Behdad Esfahbod 已提交
197 198 199
    g_free (direction);
    g_free (language);
    g_free (script);
B
Behdad Esfahbod 已提交
200
    free (features);
B
Behdad Esfahbod 已提交
201
    g_strfreev (shapers);
B
Behdad Esfahbod 已提交
202
  }
B
Behdad Esfahbod 已提交
203

204
  void add_options (option_parser_t *parser);
B
Behdad Esfahbod 已提交
205

B
Behdad Esfahbod 已提交
206 207
  void setup_buffer (hb_buffer_t *buffer)
  {
B
Behdad Esfahbod 已提交
208 209 210
    hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
    hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
    hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
211
    hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_DEFAULT |
212 213 214
			 (bot ? HB_BUFFER_FLAG_BOT : 0) |
			 (eot ? HB_BUFFER_FLAG_EOT : 0) |
			 (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0)));
215
    hb_buffer_set_cluster_level (buffer, cluster_level);
216
    hb_buffer_guess_segment_properties (buffer);
B
Behdad Esfahbod 已提交
217 218
  }

219 220
  void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
			const char *text_before, const char *text_after)
B
Behdad Esfahbod 已提交
221
  {
222
    hb_buffer_clear_contents (buffer);
223 224 225 226
    if (text_before) {
      unsigned int len = strlen (text_before);
      hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
    }
227
    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
228 229 230
    if (text_after) {
      hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
    }
231

B
Behdad Esfahbod 已提交
232 233 234 235 236 237 238 239 240 241
    if (!utf8_clusters) {
      /* Reset cluster values to refer to Unicode character index
       * instead of UTF-8 index. */
      unsigned int num_glyphs = hb_buffer_get_length (buffer);
      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
      for (unsigned int i = 0; i < num_glyphs; i++)
      {
	info->cluster = i;
	info++;
      }
242 243
    }

B
Behdad Esfahbod 已提交
244
    setup_buffer (buffer);
B
Behdad Esfahbod 已提交
245 246
  }

247
  hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=NULL)
B
Behdad Esfahbod 已提交
248
  {
249 250 251 252 253 254 255
    if (!hb_shape_full (font, buffer, features, num_features, shapers))
    {
      if (error)
        *error = "all shapers failed.";
      return false;
    }

256 257
    if (normalize_glyphs)
      hb_buffer_normalize_glyphs (buffer);
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

    if (verify && !verify_buffer (buffer, error))
      return false;

    return true;
  }

  bool verify_buffer (hb_buffer_t *buffer, const char **error=NULL)
  {
    /* Check that clusters are monotone. */
    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ||
	cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
    {
      bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer));

      unsigned int num_glyphs;
      hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs);

      for (unsigned int i = 1; i < num_glyphs; i++)
	if (info[i-1].cluster != info[i].cluster &&
	    (info[i-1].cluster < info[i].cluster) != is_forward)
	{
	  if (error)
	    *error = "clusters are not monotone.";
	  return false;
	}
    }

    return true;
B
Behdad Esfahbod 已提交
287 288
  }

289 290
  void shape_closure (const char *text, int text_len,
		      hb_font_t *font, hb_buffer_t *buffer,
B
Behdad Esfahbod 已提交
291 292
		      hb_set_t *glyphs)
  {
293 294 295 296 297 298
    hb_buffer_reset (buffer);
    hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
    setup_buffer (buffer);
    hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
  }

299
  /* Buffer properties */
B
Behdad Esfahbod 已提交
300 301 302
  char *direction;
  char *language;
  char *script;
303 304 305 306 307 308

  /* Buffer flags */
  hb_bool_t bot;
  hb_bool_t eot;
  hb_bool_t preserve_default_ignorables;

B
Behdad Esfahbod 已提交
309 310 311
  hb_feature_t *features;
  unsigned int num_features;
  char **shapers;
B
Behdad Esfahbod 已提交
312
  hb_bool_t utf8_clusters;
313
  hb_buffer_cluster_level_t cluster_level;
314
  hb_bool_t normalize_glyphs;
315
  hb_bool_t verify;
B
Behdad Esfahbod 已提交
316
  unsigned int num_iterations;
317
};
B
Behdad Esfahbod 已提交
318

319

320
struct font_options_t : option_group_t
B
Behdad Esfahbod 已提交
321
{
322 323
  font_options_t (option_parser_t *parser,
		  int default_font_size_,
B
Behdad Esfahbod 已提交
324 325 326 327
		  unsigned int subpixel_bits_)
  {
    variations = NULL;
    num_variations = 0;
328 329
    default_font_size = default_font_size_;
    subpixel_bits = subpixel_bits_;
330 331
    font_file = NULL;
    face_index = 0;
332
    font_size_x = font_size_y = default_font_size;
333
    font_funcs = NULL;
334 335 336 337 338 339

    font = NULL;

    add_options (parser);
  }
  ~font_options_t (void) {
B
Behdad Esfahbod 已提交
340
    g_free (font_file);
B
Behdad Esfahbod 已提交
341
    free (variations);
B
Behdad Esfahbod 已提交
342
    g_free (font_funcs);
343
    hb_font_destroy (font);
B
Behdad Esfahbod 已提交
344 345
  }

346 347 348
  void add_options (option_parser_t *parser);

  hb_font_t *get_font (void) const;
B
Behdad Esfahbod 已提交
349

B
Behdad Esfahbod 已提交
350
  char *font_file;
B
Behdad Esfahbod 已提交
351
  int face_index;
B
Behdad Esfahbod 已提交
352 353
  hb_variation_t *variations;
  unsigned int num_variations;
354 355 356 357
  int default_font_size;
  unsigned int subpixel_bits;
  mutable double font_size_x;
  mutable double font_size_y;
B
Behdad Esfahbod 已提交
358
  char *font_funcs;
B
Behdad Esfahbod 已提交
359

360 361 362 363 364 365 366 367
  private:
  mutable hb_font_t *font;
};


struct text_options_t : option_group_t
{
  text_options_t (option_parser_t *parser) {
368 369 370
    text_before = NULL;
    text_after = NULL;

371 372 373
    text = NULL;
    text_file = NULL;

B
Behdad Esfahbod 已提交
374 375
    fp = NULL;
    gs = NULL;
B
Behdad Esfahbod 已提交
376 377
    line = NULL;
    line_len = (unsigned int) -1;
378 379 380 381

    add_options (parser);
  }
  ~text_options_t (void) {
B
Behdad Esfahbod 已提交
382 383 384 385
    g_free (text_before);
    g_free (text_after);
    g_free (text);
    g_free (text_file);
B
Behdad Esfahbod 已提交
386
    if (gs)
387
      g_string_free (gs, true);
B
Behdad Esfahbod 已提交
388 389
    if (fp)
      fclose (fp);
390 391 392 393 394 395 396 397
  }

  void add_options (option_parser_t *parser);

  void post_parse (GError **error G_GNUC_UNUSED) {
    if (text && text_file)
      g_set_error (error,
		   G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
398
		   "Only one of text and text-file can be set");
399 400 401 402
  };

  const char *get_line (unsigned int *len);

B
Behdad Esfahbod 已提交
403 404
  char *text_before;
  char *text_after;
405

B
Behdad Esfahbod 已提交
406 407
  char *text;
  char *text_file;
408 409

  private:
B
Behdad Esfahbod 已提交
410 411
  FILE *fp;
  GString *gs;
B
Behdad Esfahbod 已提交
412 413
  char *line;
  unsigned int line_len;
414 415 416 417
};

struct output_options_t : option_group_t
{
418
  output_options_t (option_parser_t *parser,
B
Behdad Esfahbod 已提交
419
		    const char **supported_formats_ = NULL) {
420 421
    output_file = NULL;
    output_format = NULL;
422
    supported_formats = supported_formats_;
423
    explicit_output_format = false;
424

425 426
    fp = NULL;

427 428
    add_options (parser);
  }
429
  ~output_options_t (void) {
B
Behdad Esfahbod 已提交
430 431
    g_free (output_file);
    g_free (output_format);
B
Behdad Esfahbod 已提交
432
    if (fp)
433 434
      fclose (fp);
  }
435 436 437 438 439

  void add_options (option_parser_t *parser);

  void post_parse (GError **error G_GNUC_UNUSED)
  {
440 441 442
    if (output_format)
      explicit_output_format = true;

443 444 445
    if (output_file && !output_format) {
      output_format = strrchr (output_file, '.');
      if (output_format)
446
      {
447
	  output_format++; /* skip the dot */
448 449
	  output_format = strdup (output_format);
      }
450 451
    }

452 453 454 455
    if (output_file && 0 == strcmp (output_file, "-"))
      output_file = NULL; /* STDOUT */
  }

B
Behdad Esfahbod 已提交
456
  FILE *get_file_handle (void);
B
Behdad Esfahbod 已提交
457

B
Behdad Esfahbod 已提交
458 459
  char *output_file;
  char *output_format;
B
Behdad Esfahbod 已提交
460
  const char **supported_formats;
461
  bool explicit_output_format;
462 463

  mutable FILE *fp;
464
};
B
Behdad Esfahbod 已提交
465

B
Behdad Esfahbod 已提交
466 467 468 469 470 471
struct format_options_t : option_group_t
{
  format_options_t (option_parser_t *parser) {
    show_glyph_names = true;
    show_positions = true;
    show_clusters = true;
472 473
    show_text = false;
    show_unicode = false;
B
Behdad Esfahbod 已提交
474
    show_line_num = false;
475
    show_extents = false;
476
    show_flags = false;
477
    trace = false;
B
Behdad Esfahbod 已提交
478 479 480 481 482 483

    add_options (parser);
  }

  void add_options (option_parser_t *parser);

B
Behdad Esfahbod 已提交
484 485 486 487
  void serialize_unicode (hb_buffer_t  *buffer,
			  GString      *gs);
  void serialize_glyphs (hb_buffer_t  *buffer,
			 hb_font_t    *font,
488 489
			 hb_buffer_serialize_format_t format,
			 hb_buffer_serialize_flags_t flags,
B
Behdad Esfahbod 已提交
490 491 492
			 GString      *gs);
  void serialize_line_no (unsigned int  line_no,
			  GString      *gs);
493 494 495 496 497 498 499 500 501 502 503 504 505 506
  void serialize_buffer_of_text (hb_buffer_t  *buffer,
				 unsigned int  line_no,
				 const char   *text,
				 unsigned int  text_len,
				 hb_font_t    *font,
				 GString      *gs);
  void serialize_message (unsigned int  line_no,
			  const char   *msg,
			  GString      *gs);
  void serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
				   unsigned int  line_no,
				   const char   *text,
				   unsigned int  text_len,
				   hb_font_t    *font,
507 508
				   hb_buffer_serialize_format_t output_format,
				   hb_buffer_serialize_flags_t format_flags,
509
				   GString      *gs);
B
Behdad Esfahbod 已提交
510

B
Behdad Esfahbod 已提交
511

B
Behdad Esfahbod 已提交
512 513 514
  hb_bool_t show_glyph_names;
  hb_bool_t show_positions;
  hb_bool_t show_clusters;
515 516
  hb_bool_t show_text;
  hb_bool_t show_unicode;
B
Behdad Esfahbod 已提交
517
  hb_bool_t show_line_num;
518
  hb_bool_t show_extents;
519
  hb_bool_t show_flags;
520
  hb_bool_t trace;
B
Behdad Esfahbod 已提交
521 522
};

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
#if defined (_MSC_VER) && (_MSC_VER < 1800)

#ifndef FLT_RADIX
#define FLT_RADIX 2
#endif

__inline long double scalbn (long double x, int exp)
{
  return x * (pow ((long double) FLT_RADIX, exp));
}

__inline float scalbnf (float x, int exp)
{
  return x * (pow ((float) FLT_RADIX, exp));
}
#endif
B
Behdad Esfahbod 已提交
540 541

#endif