xref: /aosp_15_r20/external/harfbuzz_ng/util/shape-options.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2011  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #ifndef SHAPE_OPTIONS_HH
28*2d1272b8SAndroid Build Coastguard Worker #define SHAPE_OPTIONS_HH
29*2d1272b8SAndroid Build Coastguard Worker 
30*2d1272b8SAndroid Build Coastguard Worker #include "options.hh"
31*2d1272b8SAndroid Build Coastguard Worker 
32*2d1272b8SAndroid Build Coastguard Worker struct shape_options_t
33*2d1272b8SAndroid Build Coastguard Worker {
~shape_options_tshape_options_t34*2d1272b8SAndroid Build Coastguard Worker   ~shape_options_t ()
35*2d1272b8SAndroid Build Coastguard Worker   {
36*2d1272b8SAndroid Build Coastguard Worker     g_free (direction);
37*2d1272b8SAndroid Build Coastguard Worker     g_free (language);
38*2d1272b8SAndroid Build Coastguard Worker     g_free (script);
39*2d1272b8SAndroid Build Coastguard Worker     free (features);
40*2d1272b8SAndroid Build Coastguard Worker     g_strfreev (shapers);
41*2d1272b8SAndroid Build Coastguard Worker   }
42*2d1272b8SAndroid Build Coastguard Worker 
43*2d1272b8SAndroid Build Coastguard Worker   void add_options (option_parser_t *parser);
44*2d1272b8SAndroid Build Coastguard Worker 
setup_buffershape_options_t45*2d1272b8SAndroid Build Coastguard Worker   void setup_buffer (hb_buffer_t *buffer)
46*2d1272b8SAndroid Build Coastguard Worker   {
47*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
48*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
49*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
50*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_flags (buffer, (hb_buffer_flags_t)
51*2d1272b8SAndroid Build Coastguard Worker 				 (HB_BUFFER_FLAG_DEFAULT |
52*2d1272b8SAndroid Build Coastguard Worker 				  (bot ? HB_BUFFER_FLAG_BOT : 0) |
53*2d1272b8SAndroid Build Coastguard Worker 				  (eot ? HB_BUFFER_FLAG_EOT : 0) |
54*2d1272b8SAndroid Build Coastguard Worker 				  (verify ? HB_BUFFER_FLAG_VERIFY : 0) |
55*2d1272b8SAndroid Build Coastguard Worker 				  (unsafe_to_concat ? HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT : 0) |
56*2d1272b8SAndroid Build Coastguard Worker 				  (safe_to_insert_tatweel ? HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL : 0) |
57*2d1272b8SAndroid Build Coastguard Worker 				  (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) |
58*2d1272b8SAndroid Build Coastguard Worker 				  (remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
59*2d1272b8SAndroid Build Coastguard Worker 				  0));
60*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
61*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_not_found_glyph (buffer, not_found_glyph);
62*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_not_found_variation_selector_glyph (buffer, not_found_variation_selector_glyph);
63*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_set_cluster_level (buffer, cluster_level);
64*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_guess_segment_properties (buffer);
65*2d1272b8SAndroid Build Coastguard Worker   }
66*2d1272b8SAndroid Build Coastguard Worker 
populate_buffershape_options_t67*2d1272b8SAndroid Build Coastguard Worker   void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
68*2d1272b8SAndroid Build Coastguard Worker 			const char *text_before, const char *text_after,
69*2d1272b8SAndroid Build Coastguard Worker 			hb_font_t *font)
70*2d1272b8SAndroid Build Coastguard Worker   {
71*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_clear_contents (buffer);
72*2d1272b8SAndroid Build Coastguard Worker 
73*2d1272b8SAndroid Build Coastguard Worker     if (glyphs)
74*2d1272b8SAndroid Build Coastguard Worker     {
75*2d1272b8SAndroid Build Coastguard Worker       /* Call the setup_buffer first while the buffer is empty,
76*2d1272b8SAndroid Build Coastguard Worker        * as guess_segment_properties doesn't like glyphs in the buffer. */
77*2d1272b8SAndroid Build Coastguard Worker 
78*2d1272b8SAndroid Build Coastguard Worker       setup_buffer (buffer);
79*2d1272b8SAndroid Build Coastguard Worker       char *glyphs_text = (char *) text;
80*2d1272b8SAndroid Build Coastguard Worker       int glyphs_len = text_len;
81*2d1272b8SAndroid Build Coastguard Worker       if (glyphs_len < 0)
82*2d1272b8SAndroid Build Coastguard Worker 	glyphs_len = strlen (glyphs_text);
83*2d1272b8SAndroid Build Coastguard Worker 
84*2d1272b8SAndroid Build Coastguard Worker       if (glyphs_len && glyphs_text[glyphs_len - 1] != ']')
85*2d1272b8SAndroid Build Coastguard Worker       {
86*2d1272b8SAndroid Build Coastguard Worker 	glyphs_text = g_strdup_printf ("%*s]", glyphs_len, glyphs_text);
87*2d1272b8SAndroid Build Coastguard Worker 	glyphs_len = -1;
88*2d1272b8SAndroid Build Coastguard Worker       }
89*2d1272b8SAndroid Build Coastguard Worker 
90*2d1272b8SAndroid Build Coastguard Worker       hb_buffer_deserialize_glyphs (buffer,
91*2d1272b8SAndroid Build Coastguard Worker 				    glyphs_text, glyphs_len,
92*2d1272b8SAndroid Build Coastguard Worker 				    nullptr,
93*2d1272b8SAndroid Build Coastguard Worker 				    font,
94*2d1272b8SAndroid Build Coastguard Worker 				    HB_BUFFER_SERIALIZE_FORMAT_TEXT);
95*2d1272b8SAndroid Build Coastguard Worker 
96*2d1272b8SAndroid Build Coastguard Worker       if (!strchr (glyphs_text, '+'))
97*2d1272b8SAndroid Build Coastguard Worker       {
98*2d1272b8SAndroid Build Coastguard Worker         scale_advances = false;
99*2d1272b8SAndroid Build Coastguard Worker         unsigned count;
100*2d1272b8SAndroid Build Coastguard Worker 	hb_direction_t direction = hb_buffer_get_direction (buffer);
101*2d1272b8SAndroid Build Coastguard Worker 	hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, &count);
102*2d1272b8SAndroid Build Coastguard Worker 	hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, &count);
103*2d1272b8SAndroid Build Coastguard Worker 	for (unsigned i = 0; i < count; i++)
104*2d1272b8SAndroid Build Coastguard Worker 	  hb_font_get_glyph_advance_for_direction (font,
105*2d1272b8SAndroid Build Coastguard Worker 						   infos[i].codepoint,
106*2d1272b8SAndroid Build Coastguard Worker 						   direction,
107*2d1272b8SAndroid Build Coastguard Worker 						   &positions[i].x_advance,
108*2d1272b8SAndroid Build Coastguard Worker 						   &positions[i].y_advance);
109*2d1272b8SAndroid Build Coastguard Worker       }
110*2d1272b8SAndroid Build Coastguard Worker 
111*2d1272b8SAndroid Build Coastguard Worker       if (glyphs_text != text)
112*2d1272b8SAndroid Build Coastguard Worker         g_free (glyphs_text);
113*2d1272b8SAndroid Build Coastguard Worker 
114*2d1272b8SAndroid Build Coastguard Worker       return;
115*2d1272b8SAndroid Build Coastguard Worker     }
116*2d1272b8SAndroid Build Coastguard Worker 
117*2d1272b8SAndroid Build Coastguard Worker     if (text_before) {
118*2d1272b8SAndroid Build Coastguard Worker       unsigned int len = strlen (text_before);
119*2d1272b8SAndroid Build Coastguard Worker       hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
120*2d1272b8SAndroid Build Coastguard Worker     }
121*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
122*2d1272b8SAndroid Build Coastguard Worker     if (text_after) {
123*2d1272b8SAndroid Build Coastguard Worker       hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
124*2d1272b8SAndroid Build Coastguard Worker     }
125*2d1272b8SAndroid Build Coastguard Worker 
126*2d1272b8SAndroid Build Coastguard Worker     if (!utf8_clusters) {
127*2d1272b8SAndroid Build Coastguard Worker       /* Reset cluster values to refer to Unicode character index
128*2d1272b8SAndroid Build Coastguard Worker        * instead of UTF-8 index. */
129*2d1272b8SAndroid Build Coastguard Worker       unsigned int num_glyphs = hb_buffer_get_length (buffer);
130*2d1272b8SAndroid Build Coastguard Worker       hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
131*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int i = 0; i < num_glyphs; i++)
132*2d1272b8SAndroid Build Coastguard Worker       {
133*2d1272b8SAndroid Build Coastguard Worker 	info->cluster = i;
134*2d1272b8SAndroid Build Coastguard Worker 	info++;
135*2d1272b8SAndroid Build Coastguard Worker       }
136*2d1272b8SAndroid Build Coastguard Worker     }
137*2d1272b8SAndroid Build Coastguard Worker 
138*2d1272b8SAndroid Build Coastguard Worker     setup_buffer (buffer);
139*2d1272b8SAndroid Build Coastguard Worker   }
140*2d1272b8SAndroid Build Coastguard Worker 
shapeshape_options_t141*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer, const char **error=nullptr)
142*2d1272b8SAndroid Build Coastguard Worker   {
143*2d1272b8SAndroid Build Coastguard Worker     if (glyphs)
144*2d1272b8SAndroid Build Coastguard Worker     {
145*2d1272b8SAndroid Build Coastguard Worker       /* Scale positions. */
146*2d1272b8SAndroid Build Coastguard Worker       int x_scale, y_scale;
147*2d1272b8SAndroid Build Coastguard Worker       hb_font_get_scale (font, &x_scale, &y_scale);
148*2d1272b8SAndroid Build Coastguard Worker       unsigned upem = hb_face_get_upem (hb_font_get_face (font));
149*2d1272b8SAndroid Build Coastguard Worker       unsigned count;
150*2d1272b8SAndroid Build Coastguard Worker       auto *positions = hb_buffer_get_glyph_positions (buffer, &count);
151*2d1272b8SAndroid Build Coastguard Worker       for (unsigned i = 0; i < count; i++)
152*2d1272b8SAndroid Build Coastguard Worker       {
153*2d1272b8SAndroid Build Coastguard Worker 	auto &pos = positions[i];
154*2d1272b8SAndroid Build Coastguard Worker 	pos.x_offset = pos.x_offset * x_scale / upem;
155*2d1272b8SAndroid Build Coastguard Worker 	pos.y_offset = pos.y_offset * y_scale / upem;
156*2d1272b8SAndroid Build Coastguard Worker 	if (scale_advances)
157*2d1272b8SAndroid Build Coastguard Worker 	{
158*2d1272b8SAndroid Build Coastguard Worker 	  pos.x_advance = pos.x_advance * x_scale / upem;
159*2d1272b8SAndroid Build Coastguard Worker 	  pos.y_advance = pos.y_advance * y_scale / upem;
160*2d1272b8SAndroid Build Coastguard Worker 	}
161*2d1272b8SAndroid Build Coastguard Worker       }
162*2d1272b8SAndroid Build Coastguard Worker     }
163*2d1272b8SAndroid Build Coastguard Worker     else
164*2d1272b8SAndroid Build Coastguard Worker     {
165*2d1272b8SAndroid Build Coastguard Worker       if (advance <= 0)
166*2d1272b8SAndroid Build Coastguard Worker       {
167*2d1272b8SAndroid Build Coastguard Worker 	if (!hb_shape_full (font, buffer, features, num_features, shapers))
168*2d1272b8SAndroid Build Coastguard Worker 	{
169*2d1272b8SAndroid Build Coastguard Worker 	  if (error)
170*2d1272b8SAndroid Build Coastguard Worker 	    *error = "Shaping failed.";
171*2d1272b8SAndroid Build Coastguard Worker 	  goto fail;
172*2d1272b8SAndroid Build Coastguard Worker 	}
173*2d1272b8SAndroid Build Coastguard Worker 
174*2d1272b8SAndroid Build Coastguard Worker 	if (advance < 0)
175*2d1272b8SAndroid Build Coastguard Worker 	{
176*2d1272b8SAndroid Build Coastguard Worker 	  float unit = (1 << SUBPIXEL_BITS);
177*2d1272b8SAndroid Build Coastguard Worker 
178*2d1272b8SAndroid Build Coastguard Worker 	  /* Calculate buffer advance */
179*2d1272b8SAndroid Build Coastguard Worker 	  float w = 0;
180*2d1272b8SAndroid Build Coastguard Worker 	  unsigned count = 0;
181*2d1272b8SAndroid Build Coastguard Worker 	  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &count);
182*2d1272b8SAndroid Build Coastguard Worker 	  if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction (buffer)))
183*2d1272b8SAndroid Build Coastguard Worker 	    for (unsigned i = 0; i < count; i++)
184*2d1272b8SAndroid Build Coastguard Worker 	      w += pos[i].x_advance;
185*2d1272b8SAndroid Build Coastguard Worker 	  else
186*2d1272b8SAndroid Build Coastguard Worker 	    for (unsigned i = 0; i < count; i++)
187*2d1272b8SAndroid Build Coastguard Worker 	      w += pos[i].y_advance;
188*2d1272b8SAndroid Build Coastguard Worker 
189*2d1272b8SAndroid Build Coastguard Worker 	  printf ("Default size: %u\n", (unsigned) roundf (w / unit));
190*2d1272b8SAndroid Build Coastguard Worker 	  exit (0);
191*2d1272b8SAndroid Build Coastguard Worker 	}
192*2d1272b8SAndroid Build Coastguard Worker       }
193*2d1272b8SAndroid Build Coastguard Worker #ifdef HB_EXPERIMENTAL_API
194*2d1272b8SAndroid Build Coastguard Worker       else
195*2d1272b8SAndroid Build Coastguard Worker       {
196*2d1272b8SAndroid Build Coastguard Worker         float unit = (1 << SUBPIXEL_BITS);
197*2d1272b8SAndroid Build Coastguard Worker         float target_advance = advance * unit;
198*2d1272b8SAndroid Build Coastguard Worker 	float w = 0;
199*2d1272b8SAndroid Build Coastguard Worker 	hb_tag_t var_tag;
200*2d1272b8SAndroid Build Coastguard Worker 	float var_value;
201*2d1272b8SAndroid Build Coastguard Worker 	if (!hb_shape_justify (font, buffer, features, num_features, shapers,
202*2d1272b8SAndroid Build Coastguard Worker 			       target_advance - unit * 0.5f, target_advance + unit * 0.5f,
203*2d1272b8SAndroid Build Coastguard Worker 			       &w, &var_tag, &var_value))
204*2d1272b8SAndroid Build Coastguard Worker 	{
205*2d1272b8SAndroid Build Coastguard Worker 	  if (error)
206*2d1272b8SAndroid Build Coastguard Worker 	    *error = "Shaping failed.";
207*2d1272b8SAndroid Build Coastguard Worker 	  goto fail;
208*2d1272b8SAndroid Build Coastguard Worker 	}
209*2d1272b8SAndroid Build Coastguard Worker       }
210*2d1272b8SAndroid Build Coastguard Worker #endif
211*2d1272b8SAndroid Build Coastguard Worker     }
212*2d1272b8SAndroid Build Coastguard Worker 
213*2d1272b8SAndroid Build Coastguard Worker     if (normalize_glyphs)
214*2d1272b8SAndroid Build Coastguard Worker       hb_buffer_normalize_glyphs (buffer);
215*2d1272b8SAndroid Build Coastguard Worker 
216*2d1272b8SAndroid Build Coastguard Worker     return true;
217*2d1272b8SAndroid Build Coastguard Worker 
218*2d1272b8SAndroid Build Coastguard Worker   fail:
219*2d1272b8SAndroid Build Coastguard Worker     return false;
220*2d1272b8SAndroid Build Coastguard Worker   }
221*2d1272b8SAndroid Build Coastguard Worker 
shape_closureshape_options_t222*2d1272b8SAndroid Build Coastguard Worker   void shape_closure (const char *text, int text_len,
223*2d1272b8SAndroid Build Coastguard Worker 		      hb_font_t *font, hb_buffer_t *buffer,
224*2d1272b8SAndroid Build Coastguard Worker 		      hb_set_t *glyphs)
225*2d1272b8SAndroid Build Coastguard Worker   {
226*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_reset (buffer);
227*2d1272b8SAndroid Build Coastguard Worker     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
228*2d1272b8SAndroid Build Coastguard Worker     setup_buffer (buffer);
229*2d1272b8SAndroid Build Coastguard Worker     hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
230*2d1272b8SAndroid Build Coastguard Worker   }
231*2d1272b8SAndroid Build Coastguard Worker 
232*2d1272b8SAndroid Build Coastguard Worker   /* Buffer properties */
233*2d1272b8SAndroid Build Coastguard Worker   char *direction = nullptr;
234*2d1272b8SAndroid Build Coastguard Worker   char *language = nullptr;
235*2d1272b8SAndroid Build Coastguard Worker   char *script = nullptr;
236*2d1272b8SAndroid Build Coastguard Worker 
237*2d1272b8SAndroid Build Coastguard Worker   /* Buffer flags */
238*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t bot = false;
239*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t eot = false;
240*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t preserve_default_ignorables = false;
241*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t remove_default_ignorables = false;
242*2d1272b8SAndroid Build Coastguard Worker 
243*2d1272b8SAndroid Build Coastguard Worker   hb_feature_t *features = nullptr;
244*2d1272b8SAndroid Build Coastguard Worker   unsigned int num_features = 0;
245*2d1272b8SAndroid Build Coastguard Worker   char **shapers = nullptr;
246*2d1272b8SAndroid Build Coastguard Worker   signed advance = 0;
247*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t utf8_clusters = false;
248*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t invisible_glyph = 0;
249*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t not_found_glyph = 0;
250*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t not_found_variation_selector_glyph = HB_CODEPOINT_INVALID;
251*2d1272b8SAndroid Build Coastguard Worker   hb_buffer_cluster_level_t cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
252*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t normalize_glyphs = false;
253*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t glyphs = false;
254*2d1272b8SAndroid Build Coastguard Worker   bool scale_advances = true;
255*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t verify = false;
256*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t unsafe_to_concat = false;
257*2d1272b8SAndroid Build Coastguard Worker   hb_bool_t safe_to_insert_tatweel = false;
258*2d1272b8SAndroid Build Coastguard Worker   unsigned int num_iterations = 1;
259*2d1272b8SAndroid Build Coastguard Worker };
260*2d1272b8SAndroid Build Coastguard Worker 
261*2d1272b8SAndroid Build Coastguard Worker 
262*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_shapers(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error)263*2d1272b8SAndroid Build Coastguard Worker parse_shapers (const char *name G_GNUC_UNUSED,
264*2d1272b8SAndroid Build Coastguard Worker 	       const char *arg,
265*2d1272b8SAndroid Build Coastguard Worker 	       gpointer    data,
266*2d1272b8SAndroid Build Coastguard Worker 	       GError    **error)
267*2d1272b8SAndroid Build Coastguard Worker {
268*2d1272b8SAndroid Build Coastguard Worker   shape_options_t *shape_opts = (shape_options_t *) data;
269*2d1272b8SAndroid Build Coastguard Worker   char **shapers = g_strsplit (arg, ",", 0);
270*2d1272b8SAndroid Build Coastguard Worker 
271*2d1272b8SAndroid Build Coastguard Worker   for (char **shaper = shapers; *shaper; shaper++)
272*2d1272b8SAndroid Build Coastguard Worker   {
273*2d1272b8SAndroid Build Coastguard Worker     bool found = false;
274*2d1272b8SAndroid Build Coastguard Worker     for (const char **hb_shaper = hb_shape_list_shapers (); *hb_shaper; hb_shaper++) {
275*2d1272b8SAndroid Build Coastguard Worker       if (strcmp (*shaper, *hb_shaper) == 0)
276*2d1272b8SAndroid Build Coastguard Worker       {
277*2d1272b8SAndroid Build Coastguard Worker 	found = true;
278*2d1272b8SAndroid Build Coastguard Worker 	break;
279*2d1272b8SAndroid Build Coastguard Worker       }
280*2d1272b8SAndroid Build Coastguard Worker     }
281*2d1272b8SAndroid Build Coastguard Worker     if (!found)
282*2d1272b8SAndroid Build Coastguard Worker     {
283*2d1272b8SAndroid Build Coastguard Worker       g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
284*2d1272b8SAndroid Build Coastguard Worker 		   "Unknown or unsupported shaper: %s", *shaper);
285*2d1272b8SAndroid Build Coastguard Worker       g_strfreev (shapers);
286*2d1272b8SAndroid Build Coastguard Worker       return false;
287*2d1272b8SAndroid Build Coastguard Worker     }
288*2d1272b8SAndroid Build Coastguard Worker   }
289*2d1272b8SAndroid Build Coastguard Worker 
290*2d1272b8SAndroid Build Coastguard Worker   g_strfreev (shape_opts->shapers);
291*2d1272b8SAndroid Build Coastguard Worker   shape_opts->shapers = shapers;
292*2d1272b8SAndroid Build Coastguard Worker   return true;
293*2d1272b8SAndroid Build Coastguard Worker }
294*2d1272b8SAndroid Build Coastguard Worker 
295*2d1272b8SAndroid Build Coastguard Worker static G_GNUC_NORETURN gboolean
list_shapers(const char * name G_GNUC_UNUSED,const char * arg G_GNUC_UNUSED,gpointer data G_GNUC_UNUSED,GError ** error G_GNUC_UNUSED)296*2d1272b8SAndroid Build Coastguard Worker list_shapers (const char *name G_GNUC_UNUSED,
297*2d1272b8SAndroid Build Coastguard Worker 	      const char *arg G_GNUC_UNUSED,
298*2d1272b8SAndroid Build Coastguard Worker 	      gpointer    data G_GNUC_UNUSED,
299*2d1272b8SAndroid Build Coastguard Worker 	      GError    **error G_GNUC_UNUSED)
300*2d1272b8SAndroid Build Coastguard Worker {
301*2d1272b8SAndroid Build Coastguard Worker   for (const char **shaper = hb_shape_list_shapers (); *shaper; shaper++)
302*2d1272b8SAndroid Build Coastguard Worker     g_printf ("%s\n", *shaper);
303*2d1272b8SAndroid Build Coastguard Worker 
304*2d1272b8SAndroid Build Coastguard Worker   exit(0);
305*2d1272b8SAndroid Build Coastguard Worker }
306*2d1272b8SAndroid Build Coastguard Worker 
307*2d1272b8SAndroid Build Coastguard Worker 
308*2d1272b8SAndroid Build Coastguard Worker static gboolean
parse_features(const char * name G_GNUC_UNUSED,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)309*2d1272b8SAndroid Build Coastguard Worker parse_features (const char *name G_GNUC_UNUSED,
310*2d1272b8SAndroid Build Coastguard Worker 		const char *arg,
311*2d1272b8SAndroid Build Coastguard Worker 		gpointer    data,
312*2d1272b8SAndroid Build Coastguard Worker 		GError    **error G_GNUC_UNUSED)
313*2d1272b8SAndroid Build Coastguard Worker {
314*2d1272b8SAndroid Build Coastguard Worker   shape_options_t *shape_opts = (shape_options_t *) data;
315*2d1272b8SAndroid Build Coastguard Worker   char *s = (char *) arg;
316*2d1272b8SAndroid Build Coastguard Worker   size_t l = strlen (s);
317*2d1272b8SAndroid Build Coastguard Worker   char *p;
318*2d1272b8SAndroid Build Coastguard Worker 
319*2d1272b8SAndroid Build Coastguard Worker   shape_opts->num_features = 0;
320*2d1272b8SAndroid Build Coastguard Worker   g_free (shape_opts->features);
321*2d1272b8SAndroid Build Coastguard Worker   shape_opts->features = nullptr;
322*2d1272b8SAndroid Build Coastguard Worker 
323*2d1272b8SAndroid Build Coastguard Worker   /* if the string is quoted, strip the quotes */
324*2d1272b8SAndroid Build Coastguard Worker   if (s[0] == s[l - 1] && (s[0] == '\"' || s[0] == '\''))
325*2d1272b8SAndroid Build Coastguard Worker   {
326*2d1272b8SAndroid Build Coastguard Worker     s[l - 1] = '\0';
327*2d1272b8SAndroid Build Coastguard Worker     s++;
328*2d1272b8SAndroid Build Coastguard Worker   }
329*2d1272b8SAndroid Build Coastguard Worker 
330*2d1272b8SAndroid Build Coastguard Worker   if (!*s)
331*2d1272b8SAndroid Build Coastguard Worker     return true;
332*2d1272b8SAndroid Build Coastguard Worker 
333*2d1272b8SAndroid Build Coastguard Worker   /* count the features first, so we can allocate memory */
334*2d1272b8SAndroid Build Coastguard Worker   p = s;
335*2d1272b8SAndroid Build Coastguard Worker   do {
336*2d1272b8SAndroid Build Coastguard Worker     shape_opts->num_features++;
337*2d1272b8SAndroid Build Coastguard Worker     p = strpbrk (p, ", ");
338*2d1272b8SAndroid Build Coastguard Worker     if (p)
339*2d1272b8SAndroid Build Coastguard Worker       p++;
340*2d1272b8SAndroid Build Coastguard Worker   } while (p);
341*2d1272b8SAndroid Build Coastguard Worker 
342*2d1272b8SAndroid Build Coastguard Worker   shape_opts->features = (hb_feature_t *) calloc (shape_opts->num_features, sizeof (*shape_opts->features));
343*2d1272b8SAndroid Build Coastguard Worker   if (!shape_opts->features)
344*2d1272b8SAndroid Build Coastguard Worker     return false;
345*2d1272b8SAndroid Build Coastguard Worker 
346*2d1272b8SAndroid Build Coastguard Worker   /* now do the actual parsing */
347*2d1272b8SAndroid Build Coastguard Worker   p = s;
348*2d1272b8SAndroid Build Coastguard Worker   shape_opts->num_features = 0;
349*2d1272b8SAndroid Build Coastguard Worker   while (p && *p) {
350*2d1272b8SAndroid Build Coastguard Worker     char *end = strpbrk (p, ", ");
351*2d1272b8SAndroid Build Coastguard Worker     if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
352*2d1272b8SAndroid Build Coastguard Worker       shape_opts->num_features++;
353*2d1272b8SAndroid Build Coastguard Worker     p = end ? end + 1 : nullptr;
354*2d1272b8SAndroid Build Coastguard Worker   }
355*2d1272b8SAndroid Build Coastguard Worker 
356*2d1272b8SAndroid Build Coastguard Worker   return true;
357*2d1272b8SAndroid Build Coastguard Worker }
358*2d1272b8SAndroid Build Coastguard Worker 
359*2d1272b8SAndroid Build Coastguard Worker void
add_options(option_parser_t * parser)360*2d1272b8SAndroid Build Coastguard Worker shape_options_t::add_options (option_parser_t *parser)
361*2d1272b8SAndroid Build Coastguard Worker {
362*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry entries[] =
363*2d1272b8SAndroid Build Coastguard Worker   {
364*2d1272b8SAndroid Build Coastguard Worker     {"list-shapers",	0, G_OPTION_FLAG_NO_ARG,
365*2d1272b8SAndroid Build Coastguard Worker 			      G_OPTION_ARG_CALLBACK,	(gpointer) &list_shapers,	"List available shapers and quit",	nullptr},
366*2d1272b8SAndroid Build Coastguard Worker     {"shaper",		0, G_OPTION_FLAG_HIDDEN,
367*2d1272b8SAndroid Build Coastguard Worker 			      G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Hidden duplicate of --shapers",	nullptr},
368*2d1272b8SAndroid Build Coastguard Worker     {"shapers",		0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_shapers,	"Set comma-separated list of shapers to try","list"},
369*2d1272b8SAndroid Build Coastguard Worker     {"direction",	0, 0, G_OPTION_ARG_STRING,	&this->direction,		"Set text direction (default: auto)",	"ltr/rtl/ttb/btt"},
370*2d1272b8SAndroid Build Coastguard Worker     {"language",	0, 0, G_OPTION_ARG_STRING,	&this->language,		"Set text language (default: $LANG)",	"BCP 47 tag"},
371*2d1272b8SAndroid Build Coastguard Worker     {"script",		0, 0, G_OPTION_ARG_STRING,	&this->script,			"Set text script (default: auto)",	"ISO-15924 tag"},
372*2d1272b8SAndroid Build Coastguard Worker     {"bot",		0, 0, G_OPTION_ARG_NONE,	&this->bot,			"Treat text as beginning-of-paragraph",	nullptr},
373*2d1272b8SAndroid Build Coastguard Worker     {"eot",		0, 0, G_OPTION_ARG_NONE,	&this->eot,			"Treat text as end-of-paragraph",	nullptr},
374*2d1272b8SAndroid Build Coastguard Worker #ifdef HB_EXPERIMENTAL_API
375*2d1272b8SAndroid Build Coastguard Worker     {"justify-to",	0, 0,
376*2d1272b8SAndroid Build Coastguard Worker 			      G_OPTION_ARG_INT,		&this->advance,			"Target size to justify to",		"SIZE, or -1"},
377*2d1272b8SAndroid Build Coastguard Worker #endif
378*2d1272b8SAndroid Build Coastguard Worker     {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE,	&this->preserve_default_ignorables,	"Preserve Default-Ignorable characters",	nullptr},
379*2d1272b8SAndroid Build Coastguard Worker     {"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE,	&this->remove_default_ignorables,	"Remove Default-Ignorable characters",	nullptr},
380*2d1272b8SAndroid Build Coastguard Worker     {"invisible-glyph",	0, 0, G_OPTION_ARG_INT,		&this->invisible_glyph,		"Glyph value to replace Default-Ignorables with",	nullptr},
381*2d1272b8SAndroid Build Coastguard Worker     {"not-found-glyph",	0, 0, G_OPTION_ARG_INT,		&this->not_found_glyph,		"Glyph value to replace not-found characters with",	nullptr},
382*2d1272b8SAndroid Build Coastguard Worker     {"not-found-variation-selector-glyph",
383*2d1272b8SAndroid Build Coastguard Worker 			0, 0, G_OPTION_ARG_INT,		&this->not_found_variation_selector_glyph,
384*2d1272b8SAndroid Build Coastguard Worker 											"Glyph value to replace not-found variation-selector characters with",	nullptr},
385*2d1272b8SAndroid Build Coastguard Worker     {"utf8-clusters",	0, 0, G_OPTION_ARG_NONE,	&this->utf8_clusters,		"Use UTF8 byte indices, not char indices",	nullptr},
386*2d1272b8SAndroid Build Coastguard Worker     {"cluster-level",	0, 0, G_OPTION_ARG_INT,		&this->cluster_level,		"Cluster merging level (default: 0)",	"0/1/2"},
387*2d1272b8SAndroid Build Coastguard Worker     {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,	&this->normalize_glyphs,	"Rearrange glyph clusters in nominal order",	nullptr},
388*2d1272b8SAndroid Build Coastguard Worker     {"unsafe-to-concat",0, 0, G_OPTION_ARG_NONE,	&this->unsafe_to_concat,	"Produce unsafe-to-concat glyph flag",	nullptr},
389*2d1272b8SAndroid Build Coastguard Worker     {"safe-to-insert-tatweel",0, 0, G_OPTION_ARG_NONE,	&this->safe_to_insert_tatweel,	"Produce safe-to-insert-tatweel glyph flag",	nullptr},
390*2d1272b8SAndroid Build Coastguard Worker     {"glyphs",		0, 0, G_OPTION_ARG_NONE,	&this->glyphs,			"Interpret input as glyph string",	nullptr},
391*2d1272b8SAndroid Build Coastguard Worker     {"verify",		0, 0, G_OPTION_ARG_NONE,	&this->verify,			"Perform sanity checks on shaping results",	nullptr},
392*2d1272b8SAndroid Build Coastguard Worker     {"num-iterations",	'n',G_OPTION_FLAG_IN_MAIN,
393*2d1272b8SAndroid Build Coastguard Worker 			      G_OPTION_ARG_INT,		&this->num_iterations,		"Run shaper N times (default: 1)",	"N"},
394*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
395*2d1272b8SAndroid Build Coastguard Worker   };
396*2d1272b8SAndroid Build Coastguard Worker   parser->add_group (entries,
397*2d1272b8SAndroid Build Coastguard Worker 		     "shape",
398*2d1272b8SAndroid Build Coastguard Worker 		     "Shape options:",
399*2d1272b8SAndroid Build Coastguard Worker 		     "Options for the shaping process",
400*2d1272b8SAndroid Build Coastguard Worker 		     this);
401*2d1272b8SAndroid Build Coastguard Worker 
402*2d1272b8SAndroid Build Coastguard Worker   const gchar *features_help = "Comma-separated list of font features\n"
403*2d1272b8SAndroid Build Coastguard Worker     "\n"
404*2d1272b8SAndroid Build Coastguard Worker     "    Features can be enabled or disabled, either globally or limited to\n"
405*2d1272b8SAndroid Build Coastguard Worker     "    specific character ranges.  The format for specifying feature settings\n"
406*2d1272b8SAndroid Build Coastguard Worker     "    follows.  All valid CSS font-feature-settings values other than 'normal'\n"
407*2d1272b8SAndroid Build Coastguard Worker     "    and the global values are also accepted, though not documented below.\n"
408*2d1272b8SAndroid Build Coastguard Worker     "    CSS string escapes are not supported."
409*2d1272b8SAndroid Build Coastguard Worker     "\n"
410*2d1272b8SAndroid Build Coastguard Worker     "    The range indices refer to the positions between Unicode characters,\n"
411*2d1272b8SAndroid Build Coastguard Worker     "    unless the --utf8-clusters is provided, in which case range indices\n"
412*2d1272b8SAndroid Build Coastguard Worker     "    refer to UTF-8 byte indices. The position before the first character\n"
413*2d1272b8SAndroid Build Coastguard Worker     "    is always 0.\n"
414*2d1272b8SAndroid Build Coastguard Worker     "\n"
415*2d1272b8SAndroid Build Coastguard Worker     "    The format is Python-esque.  Here is how it all works:\n"
416*2d1272b8SAndroid Build Coastguard Worker     "\n"
417*2d1272b8SAndroid Build Coastguard Worker     "      Syntax:       Value:    Start:    End:\n"
418*2d1272b8SAndroid Build Coastguard Worker     "\n"
419*2d1272b8SAndroid Build Coastguard Worker     "    Setting value:\n"
420*2d1272b8SAndroid Build Coastguard Worker     "      \"kern\"        1         0         ∞         # Turn feature on\n"
421*2d1272b8SAndroid Build Coastguard Worker     "      \"+kern\"       1         0         ∞         # Turn feature on\n"
422*2d1272b8SAndroid Build Coastguard Worker     "      \"-kern\"       0         0         ∞         # Turn feature off\n"
423*2d1272b8SAndroid Build Coastguard Worker     "      \"kern=0\"      0         0         ∞         # Turn feature off\n"
424*2d1272b8SAndroid Build Coastguard Worker     "      \"kern=1\"      1         0         ∞         # Turn feature on\n"
425*2d1272b8SAndroid Build Coastguard Worker     "      \"aalt=2\"      2         0         ∞         # Choose 2nd alternate\n"
426*2d1272b8SAndroid Build Coastguard Worker     "\n"
427*2d1272b8SAndroid Build Coastguard Worker     "    Setting index:\n"
428*2d1272b8SAndroid Build Coastguard Worker     "      \"kern[]\"      1         0         ∞         # Turn feature on\n"
429*2d1272b8SAndroid Build Coastguard Worker     "      \"kern[:]\"     1         0         ∞         # Turn feature on\n"
430*2d1272b8SAndroid Build Coastguard Worker     "      \"kern[5:]\"    1         5         ∞         # Turn feature on, partial\n"
431*2d1272b8SAndroid Build Coastguard Worker     "      \"kern[:5]\"    1         0         5         # Turn feature on, partial\n"
432*2d1272b8SAndroid Build Coastguard Worker     "      \"kern[3:5]\"   1         3         5         # Turn feature on, range\n"
433*2d1272b8SAndroid Build Coastguard Worker     "      \"kern[3]\"     1         3         3+1       # Turn feature on, single char\n"
434*2d1272b8SAndroid Build Coastguard Worker     "\n"
435*2d1272b8SAndroid Build Coastguard Worker     "    Mixing it all:\n"
436*2d1272b8SAndroid Build Coastguard Worker     "\n"
437*2d1272b8SAndroid Build Coastguard Worker     "      \"aalt[3:5]=2\" 2         3         5         # Turn 2nd alternate on for range";
438*2d1272b8SAndroid Build Coastguard Worker 
439*2d1272b8SAndroid Build Coastguard Worker   GOptionEntry entries2[] =
440*2d1272b8SAndroid Build Coastguard Worker   {
441*2d1272b8SAndroid Build Coastguard Worker     {"features",	0, 0, G_OPTION_ARG_CALLBACK,	(gpointer) &parse_features,	features_help,	"list"},
442*2d1272b8SAndroid Build Coastguard Worker     {nullptr}
443*2d1272b8SAndroid Build Coastguard Worker   };
444*2d1272b8SAndroid Build Coastguard Worker   parser->add_group (entries2,
445*2d1272b8SAndroid Build Coastguard Worker 		     "features",
446*2d1272b8SAndroid Build Coastguard Worker 		     "Features options:",
447*2d1272b8SAndroid Build Coastguard Worker 		     "Options for font features used",
448*2d1272b8SAndroid Build Coastguard Worker 		     this);
449*2d1272b8SAndroid Build Coastguard Worker }
450*2d1272b8SAndroid Build Coastguard Worker 
451*2d1272b8SAndroid Build Coastguard Worker #endif
452