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 #include "hb-private.hh" 31 32 #include <stdlib.h> 33 #include <stddef.h> 34 #include <string.h> 35 #include <stdio.h> 36 #include <assert.h> 37 #include <math.h> 38 #include <locale.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #ifdef HAVE_UNISTD_H 42 #include <unistd.h> /* for isatty() */ 43 #endif 44 #if defined(_WIN32) || defined(__CYGWIN__) 45 #include <io.h> /* for setmode() under Windows */ 46 #endif 47 48 #include <hb.h> 49 #ifdef HAVE_OT 50 #include <hb-ot.h> 51 #endif 52 #include <glib.h> 53 #include <glib/gprintf.h> 54 55 #if !GLIB_CHECK_VERSION (2, 22, 0) 56 # define g_mapped_file_unref g_mapped_file_free 57 #endif 58 59 void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3); 60 61 extern hb_bool_t debug; 62 63 struct option_group_t 64 { 65 virtual void add_options (struct option_parser_t *parser) = 0; 66 67 virtual void pre_parse (GError **error G_GNUC_UNUSED) {}; 68 virtual void post_parse (GError **error G_GNUC_UNUSED) {}; 69 }; 70 71 72 struct option_parser_t 73 { 74 option_parser_t (const char *usage) { 75 memset (this, 0, sizeof (*this)); 76 usage_str = usage; 77 context = g_option_context_new (usage); 78 to_free = g_ptr_array_new (); 79 80 add_main_options (); 81 } 82 ~option_parser_t (void) { 83 g_option_context_free (context); 84 g_ptr_array_foreach (to_free, (GFunc) g_free, nullptr); 85 g_ptr_array_free (to_free, TRUE); 86 } 87 88 void add_main_options (void); 89 90 void add_group (GOptionEntry *entries, 91 const gchar *name, 92 const gchar *description, 93 const gchar *help_description, 94 option_group_t *option_group); 95 96 void free_later (char *p) { 97 g_ptr_array_add (to_free, p); 98 } 99 100 void parse (int *argc, char ***argv); 101 102 G_GNUC_NORETURN void usage (void) { 103 g_printerr ("Usage: %s [OPTION...] %s\n", g_get_prgname (), usage_str); 104 exit (1); 105 } 106 107 private: 108 const char *usage_str; 109 GOptionContext *context; 110 GPtrArray *to_free; 111 }; 112 113 114 #define DEFAULT_MARGIN 16 115 #define DEFAULT_FORE "#000000" 116 #define DEFAULT_BACK "#FFFFFF" 117 #define FONT_SIZE_UPEM 0x7FFFFFFF 118 #define FONT_SIZE_NONE 0 119 120 struct view_options_t : option_group_t 121 { 122 view_options_t (option_parser_t *parser) { 123 annotate = false; 124 fore = nullptr; 125 back = nullptr; 126 line_space = 0; 127 margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN; 128 129 add_options (parser); 130 } 131 ~view_options_t (void) 132 { 133 g_free (fore); 134 g_free (back); 135 } 136 137 void add_options (option_parser_t *parser); 138 139 hb_bool_t annotate; 140 char *fore; 141 char *back; 142 double line_space; 143 struct margin_t { 144 double t, r, b, l; 145 } margin; 146 }; 147 148 149 struct shape_options_t : option_group_t 150 { 151 shape_options_t (option_parser_t *parser) 152 { 153 direction = language = script = nullptr; 154 bot = eot = preserve_default_ignorables = false; 155 features = nullptr; 156 num_features = 0; 157 shapers = nullptr; 158 utf8_clusters = false; 159 cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT; 160 normalize_glyphs = false; 161 verify = false; 162 num_iterations = 1; 163 164 add_options (parser); 165 } 166 ~shape_options_t (void) 167 { 168 g_free (direction); 169 g_free (language); 170 g_free (script); 171 free (features); 172 g_strfreev (shapers); 173 } 174 175 void add_options (option_parser_t *parser); 176 177 void setup_buffer (hb_buffer_t *buffer) 178 { 179 hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1)); 180 hb_buffer_set_script (buffer, hb_script_from_string (script, -1)); 181 hb_buffer_set_language (buffer, hb_language_from_string (language, -1)); 182 hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_DEFAULT | 183 (bot ? HB_BUFFER_FLAG_BOT : 0) | 184 (eot ? HB_BUFFER_FLAG_EOT : 0) | 185 (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0))); 186 hb_buffer_set_cluster_level (buffer, cluster_level); 187 hb_buffer_guess_segment_properties (buffer); 188 } 189 190 static void copy_buffer_properties (hb_buffer_t *dst, hb_buffer_t *src) 191 { 192 hb_segment_properties_t props; 193 hb_buffer_get_segment_properties (src, &props); 194 hb_buffer_set_segment_properties (dst, &props); 195 hb_buffer_set_flags (dst, hb_buffer_get_flags (src)); 196 hb_buffer_set_cluster_level (dst, hb_buffer_get_cluster_level (src)); 197 } 198 199 void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len, 200 const char *text_before, const char *text_after) 201 { 202 hb_buffer_clear_contents (buffer); 203 if (text_before) { 204 unsigned int len = strlen (text_before); 205 hb_buffer_add_utf8 (buffer, text_before, len, len, 0); 206 } 207 hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len); 208 if (text_after) { 209 hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0); 210 } 211 212 if (!utf8_clusters) { 213 /* Reset cluster values to refer to Unicode character index 214 * instead of UTF-8 index. */ 215 unsigned int num_glyphs = hb_buffer_get_length (buffer); 216 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); 217 for (unsigned int i = 0; i < num_glyphs; i++) 218 { 219 info->cluster = i; 220 info++; 221 } 222 } 223 224 setup_buffer (buffer); 225 } 226 227 hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr) 228 { 229 hb_buffer_t *text_buffer = nullptr; 230 if (verify) 231 { 232 text_buffer = hb_buffer_create (); 233 hb_buffer_append (text_buffer, buffer, 0, -1); 234 } 235 236 if (!hb_shape_full (font, buffer, features, num_features, shapers)) 237 { 238 if (error) 239 *error = "all shapers failed."; 240 return false; 241 } 242 243 if (normalize_glyphs) 244 hb_buffer_normalize_glyphs (buffer); 245 246 if (verify && !verify_buffer (buffer, text_buffer, font, error)) 247 return false; 248 249 if (text_buffer) 250 hb_buffer_destroy (text_buffer); 251 252 return true; 253 } 254 255 bool verify_buffer (hb_buffer_t *buffer, 256 hb_buffer_t *text_buffer, 257 hb_font_t *font, 258 const char **error=nullptr) 259 { 260 if (!verify_buffer_monotone (buffer, error)) 261 return false; 262 if (!verify_buffer_safe_to_break (buffer, text_buffer, font, error)) 263 return false; 264 return true; 265 } 266 267 bool verify_buffer_monotone (hb_buffer_t *buffer, const char **error=nullptr) 268 { 269 /* Check that clusters are monotone. */ 270 if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES || 271 cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) 272 { 273 bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); 274 275 unsigned int num_glyphs; 276 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); 277 278 for (unsigned int i = 1; i < num_glyphs; i++) 279 if (info[i-1].cluster != info[i].cluster && 280 (info[i-1].cluster < info[i].cluster) != is_forward) 281 { 282 if (error) 283 *error = "clusters are not monotone."; 284 return false; 285 } 286 } 287 288 return true; 289 } 290 291 bool verify_buffer_safe_to_break (hb_buffer_t *buffer, 292 hb_buffer_t *text_buffer, 293 hb_font_t *font, 294 const char **error=nullptr) 295 { 296 if (cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && 297 cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) 298 { 299 /* Cannot perform this check without monotone clusters. 300 * Then again, unsafe-to-break flag is much harder to use without 301 * monotone clusters. */ 302 return true; 303 } 304 305 /* Check that breaking up shaping at safe-to-break is indeed safe. */ 306 307 hb_buffer_t *fragment = hb_buffer_create (); 308 hb_buffer_t *reconstruction = hb_buffer_create (); 309 copy_buffer_properties (reconstruction, buffer); 310 311 unsigned int num_glyphs; 312 hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); 313 314 unsigned int num_chars; 315 hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars); 316 317 /* Chop text and shape fragments. */ 318 bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); 319 unsigned int start = 0; 320 unsigned int text_start = forward ? 0 : num_chars; 321 unsigned int text_end = text_start; 322 for (unsigned int end = 1; end < num_glyphs + 1; end++) 323 { 324 if (end < num_glyphs && 325 (info[end].cluster == info[end-1].cluster || 326 info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)) 327 continue; 328 329 /* Shape segment corresponding to glyphs start..end. */ 330 if (end == num_glyphs) 331 { 332 if (forward) 333 text_end = num_chars; 334 else 335 text_start = 0; 336 } 337 else 338 { 339 if (forward) 340 { 341 unsigned int cluster = info[end].cluster; 342 while (text_end < num_chars && text[text_end].cluster < cluster) 343 text_end++; 344 } 345 else 346 { 347 unsigned int cluster = info[end - 1].cluster; 348 while (text_start && text[text_start - 1].cluster >= cluster) 349 text_start--; 350 } 351 } 352 assert (text_start < text_end); 353 354 if (0) 355 printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); 356 357 hb_buffer_clear_contents (fragment); 358 copy_buffer_properties (fragment, buffer); 359 360 /* TODO: Add pre/post context text. */ 361 hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); 362 if (0 < text_start) 363 flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); 364 if (text_end < num_chars) 365 flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); 366 hb_buffer_set_flags (fragment, flags); 367 368 hb_buffer_append (fragment, text_buffer, text_start, text_end); 369 if (!hb_shape_full (font, fragment, features, num_features, shapers)) 370 { 371 if (error) 372 *error = "all shapers failed while shaping fragment."; 373 hb_buffer_destroy (reconstruction); 374 hb_buffer_destroy (fragment); 375 return false; 376 } 377 hb_buffer_append (reconstruction, fragment, 0, -1); 378 379 start = end; 380 if (forward) 381 text_start = text_end; 382 else 383 text_end = text_start; 384 } 385 386 bool ret = true; 387 hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); 388 if (diff) 389 { 390 if (error) 391 *error = "Safe-to-break test failed."; 392 ret = false; 393 394 /* Return the reconstructed result instead so it can be inspected. */ 395 hb_buffer_set_length (buffer, 0); 396 hb_buffer_append (buffer, reconstruction, 0, -1); 397 } 398 399 hb_buffer_destroy (reconstruction); 400 hb_buffer_destroy (fragment); 401 402 return ret; 403 } 404 405 void shape_closure (const char *text, int text_len, 406 hb_font_t *font, hb_buffer_t *buffer, 407 hb_set_t *glyphs) 408 { 409 hb_buffer_reset (buffer); 410 hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len); 411 setup_buffer (buffer); 412 hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs); 413 } 414 415 /* Buffer properties */ 416 char *direction; 417 char *language; 418 char *script; 419 420 /* Buffer flags */ 421 hb_bool_t bot; 422 hb_bool_t eot; 423 hb_bool_t preserve_default_ignorables; 424 425 hb_feature_t *features; 426 unsigned int num_features; 427 char **shapers; 428 hb_bool_t utf8_clusters; 429 hb_buffer_cluster_level_t cluster_level; 430 hb_bool_t normalize_glyphs; 431 hb_bool_t verify; 432 unsigned int num_iterations; 433 }; 434 435 436 struct font_options_t : option_group_t 437 { 438 font_options_t (option_parser_t *parser, 439 int default_font_size_, 440 unsigned int subpixel_bits_) 441 { 442 variations = nullptr; 443 num_variations = 0; 444 default_font_size = default_font_size_; 445 subpixel_bits = subpixel_bits_; 446 font_file = nullptr; 447 face_index = 0; 448 font_size_x = font_size_y = default_font_size; 449 font_funcs = nullptr; 450 451 font = nullptr; 452 453 add_options (parser); 454 } 455 ~font_options_t (void) { 456 g_free (font_file); 457 free (variations); 458 g_free (font_funcs); 459 hb_font_destroy (font); 460 } 461 462 void add_options (option_parser_t *parser); 463 464 hb_font_t *get_font (void) const; 465 466 char *font_file; 467 int face_index; 468 hb_variation_t *variations; 469 unsigned int num_variations; 470 int default_font_size; 471 unsigned int subpixel_bits; 472 mutable double font_size_x; 473 mutable double font_size_y; 474 char *font_funcs; 475 476 private: 477 mutable hb_font_t *font; 478 }; 479 480 481 struct text_options_t : option_group_t 482 { 483 text_options_t (option_parser_t *parser) { 484 text_before = nullptr; 485 text_after = nullptr; 486 487 text = nullptr; 488 text_file = nullptr; 489 490 fp = nullptr; 491 gs = nullptr; 492 line = nullptr; 493 line_len = (unsigned int) -1; 494 495 add_options (parser); 496 } 497 ~text_options_t (void) { 498 g_free (text_before); 499 g_free (text_after); 500 g_free (text); 501 g_free (text_file); 502 if (gs) 503 g_string_free (gs, true); 504 if (fp) 505 fclose (fp); 506 } 507 508 void add_options (option_parser_t *parser); 509 510 void post_parse (GError **error G_GNUC_UNUSED) { 511 if (text && text_file) 512 g_set_error (error, 513 G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, 514 "Only one of text and text-file can be set"); 515 }; 516 517 const char *get_line (unsigned int *len); 518 519 char *text_before; 520 char *text_after; 521 522 char *text; 523 char *text_file; 524 525 private: 526 FILE *fp; 527 GString *gs; 528 char *line; 529 unsigned int line_len; 530 }; 531 532 struct output_options_t : option_group_t 533 { 534 output_options_t (option_parser_t *parser, 535 const char **supported_formats_ = nullptr) { 536 output_file = nullptr; 537 output_format = nullptr; 538 supported_formats = supported_formats_; 539 explicit_output_format = false; 540 541 fp = nullptr; 542 543 add_options (parser); 544 } 545 ~output_options_t (void) { 546 g_free (output_file); 547 g_free (output_format); 548 if (fp) 549 fclose (fp); 550 } 551 552 void add_options (option_parser_t *parser); 553 554 void post_parse (GError **error G_GNUC_UNUSED) 555 { 556 if (output_format) 557 explicit_output_format = true; 558 559 if (output_file && !output_format) { 560 output_format = strrchr (output_file, '.'); 561 if (output_format) 562 { 563 output_format++; /* skip the dot */ 564 output_format = strdup (output_format); 565 } 566 } 567 568 if (output_file && 0 == strcmp (output_file, "-")) 569 output_file = nullptr; /* STDOUT */ 570 } 571 572 FILE *get_file_handle (void); 573 574 char *output_file; 575 char *output_format; 576 const char **supported_formats; 577 bool explicit_output_format; 578 579 mutable FILE *fp; 580 }; 581 582 struct format_options_t : option_group_t 583 { 584 format_options_t (option_parser_t *parser) { 585 show_glyph_names = true; 586 show_positions = true; 587 show_clusters = true; 588 show_text = false; 589 show_unicode = false; 590 show_line_num = false; 591 show_extents = false; 592 show_flags = false; 593 trace = false; 594 595 add_options (parser); 596 } 597 598 void add_options (option_parser_t *parser); 599 600 void serialize_unicode (hb_buffer_t *buffer, 601 GString *gs); 602 void serialize_glyphs (hb_buffer_t *buffer, 603 hb_font_t *font, 604 hb_buffer_serialize_format_t format, 605 hb_buffer_serialize_flags_t flags, 606 GString *gs); 607 void serialize_line_no (unsigned int line_no, 608 GString *gs); 609 void serialize_buffer_of_text (hb_buffer_t *buffer, 610 unsigned int line_no, 611 const char *text, 612 unsigned int text_len, 613 hb_font_t *font, 614 GString *gs); 615 void serialize_message (unsigned int line_no, 616 const char *type, 617 const char *msg, 618 GString *gs); 619 void serialize_buffer_of_glyphs (hb_buffer_t *buffer, 620 unsigned int line_no, 621 const char *text, 622 unsigned int text_len, 623 hb_font_t *font, 624 hb_buffer_serialize_format_t output_format, 625 hb_buffer_serialize_flags_t format_flags, 626 GString *gs); 627 628 629 hb_bool_t show_glyph_names; 630 hb_bool_t show_positions; 631 hb_bool_t show_clusters; 632 hb_bool_t show_text; 633 hb_bool_t show_unicode; 634 hb_bool_t show_line_num; 635 hb_bool_t show_extents; 636 hb_bool_t show_flags; 637 hb_bool_t trace; 638 }; 639 640 /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */ 641 #if defined (_MSC_VER) && (_MSC_VER < 1800) 642 643 #ifndef FLT_RADIX 644 #define FLT_RADIX 2 645 #endif 646 647 __inline long double scalbn (long double x, int exp) 648 { 649 return x * (pow ((long double) FLT_RADIX, exp)); 650 } 651 652 __inline float scalbnf (float x, int exp) 653 { 654 return x * (pow ((float) FLT_RADIX, exp)); 655 } 656 #endif 657 658 #endif 659