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