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