1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2015 Mozilla Foundation.
3*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2015 Google, Inc.
4*2d1272b8SAndroid Build Coastguard Worker *
5*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library.
6*2d1272b8SAndroid Build Coastguard Worker *
7*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without
8*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this
9*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the
10*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in
11*2d1272b8SAndroid Build Coastguard Worker * all copies of this software.
12*2d1272b8SAndroid Build Coastguard Worker *
13*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17*2d1272b8SAndroid Build Coastguard Worker * DAMAGE.
18*2d1272b8SAndroid Build Coastguard Worker *
19*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24*2d1272b8SAndroid Build Coastguard Worker *
25*2d1272b8SAndroid Build Coastguard Worker * Mozilla Author(s): Jonathan Kew
26*2d1272b8SAndroid Build Coastguard Worker * Google Author(s): Behdad Esfahbod
27*2d1272b8SAndroid Build Coastguard Worker */
28*2d1272b8SAndroid Build Coastguard Worker
29*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
30*2d1272b8SAndroid Build Coastguard Worker
31*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPE
32*2d1272b8SAndroid Build Coastguard Worker
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-use-machine.hh"
34*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-use-table.hh"
35*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-arabic.hh"
36*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-arabic-joining-list.hh"
37*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-vowel-constraints.hh"
38*2d1272b8SAndroid Build Coastguard Worker
39*2d1272b8SAndroid Build Coastguard Worker
40*2d1272b8SAndroid Build Coastguard Worker /*
41*2d1272b8SAndroid Build Coastguard Worker * Universal Shaping Engine.
42*2d1272b8SAndroid Build Coastguard Worker * https://docs.microsoft.com/en-us/typography/script-development/use
43*2d1272b8SAndroid Build Coastguard Worker */
44*2d1272b8SAndroid Build Coastguard Worker
45*2d1272b8SAndroid Build Coastguard Worker static const hb_tag_t
46*2d1272b8SAndroid Build Coastguard Worker use_basic_features[] =
47*2d1272b8SAndroid Build Coastguard Worker {
48*2d1272b8SAndroid Build Coastguard Worker /*
49*2d1272b8SAndroid Build Coastguard Worker * Basic features.
50*2d1272b8SAndroid Build Coastguard Worker * These features are applied all at once, before reordering, constrained
51*2d1272b8SAndroid Build Coastguard Worker * to the syllable.
52*2d1272b8SAndroid Build Coastguard Worker */
53*2d1272b8SAndroid Build Coastguard Worker HB_TAG('r','k','r','f'),
54*2d1272b8SAndroid Build Coastguard Worker HB_TAG('a','b','v','f'),
55*2d1272b8SAndroid Build Coastguard Worker HB_TAG('b','l','w','f'),
56*2d1272b8SAndroid Build Coastguard Worker HB_TAG('h','a','l','f'),
57*2d1272b8SAndroid Build Coastguard Worker HB_TAG('p','s','t','f'),
58*2d1272b8SAndroid Build Coastguard Worker HB_TAG('v','a','t','u'),
59*2d1272b8SAndroid Build Coastguard Worker HB_TAG('c','j','c','t'),
60*2d1272b8SAndroid Build Coastguard Worker };
61*2d1272b8SAndroid Build Coastguard Worker static const hb_tag_t
62*2d1272b8SAndroid Build Coastguard Worker use_topographical_features[] =
63*2d1272b8SAndroid Build Coastguard Worker {
64*2d1272b8SAndroid Build Coastguard Worker HB_TAG('i','s','o','l'),
65*2d1272b8SAndroid Build Coastguard Worker HB_TAG('i','n','i','t'),
66*2d1272b8SAndroid Build Coastguard Worker HB_TAG('m','e','d','i'),
67*2d1272b8SAndroid Build Coastguard Worker HB_TAG('f','i','n','a'),
68*2d1272b8SAndroid Build Coastguard Worker };
69*2d1272b8SAndroid Build Coastguard Worker /* Same order as use_topographical_features. */
70*2d1272b8SAndroid Build Coastguard Worker enum joining_form_t {
71*2d1272b8SAndroid Build Coastguard Worker JOINING_FORM_ISOL,
72*2d1272b8SAndroid Build Coastguard Worker JOINING_FORM_INIT,
73*2d1272b8SAndroid Build Coastguard Worker JOINING_FORM_MEDI,
74*2d1272b8SAndroid Build Coastguard Worker JOINING_FORM_FINA,
75*2d1272b8SAndroid Build Coastguard Worker _JOINING_FORM_NONE
76*2d1272b8SAndroid Build Coastguard Worker };
77*2d1272b8SAndroid Build Coastguard Worker static const hb_tag_t
78*2d1272b8SAndroid Build Coastguard Worker use_other_features[] =
79*2d1272b8SAndroid Build Coastguard Worker {
80*2d1272b8SAndroid Build Coastguard Worker /*
81*2d1272b8SAndroid Build Coastguard Worker * Other features.
82*2d1272b8SAndroid Build Coastguard Worker * These features are applied all at once, after reordering and
83*2d1272b8SAndroid Build Coastguard Worker * clearing syllables.
84*2d1272b8SAndroid Build Coastguard Worker */
85*2d1272b8SAndroid Build Coastguard Worker HB_TAG('a','b','v','s'),
86*2d1272b8SAndroid Build Coastguard Worker HB_TAG('b','l','w','s'),
87*2d1272b8SAndroid Build Coastguard Worker HB_TAG('h','a','l','n'),
88*2d1272b8SAndroid Build Coastguard Worker HB_TAG('p','r','e','s'),
89*2d1272b8SAndroid Build Coastguard Worker HB_TAG('p','s','t','s'),
90*2d1272b8SAndroid Build Coastguard Worker };
91*2d1272b8SAndroid Build Coastguard Worker
92*2d1272b8SAndroid Build Coastguard Worker static bool
93*2d1272b8SAndroid Build Coastguard Worker setup_syllables_use (const hb_ot_shape_plan_t *plan,
94*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font,
95*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer);
96*2d1272b8SAndroid Build Coastguard Worker static bool
97*2d1272b8SAndroid Build Coastguard Worker record_rphf_use (const hb_ot_shape_plan_t *plan,
98*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font,
99*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer);
100*2d1272b8SAndroid Build Coastguard Worker static bool
101*2d1272b8SAndroid Build Coastguard Worker record_pref_use (const hb_ot_shape_plan_t *plan,
102*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font,
103*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer);
104*2d1272b8SAndroid Build Coastguard Worker static bool
105*2d1272b8SAndroid Build Coastguard Worker reorder_use (const hb_ot_shape_plan_t *plan,
106*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font,
107*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer);
108*2d1272b8SAndroid Build Coastguard Worker
109*2d1272b8SAndroid Build Coastguard Worker static void
collect_features_use(hb_ot_shape_planner_t * plan)110*2d1272b8SAndroid Build Coastguard Worker collect_features_use (hb_ot_shape_planner_t *plan)
111*2d1272b8SAndroid Build Coastguard Worker {
112*2d1272b8SAndroid Build Coastguard Worker hb_ot_map_builder_t *map = &plan->map;
113*2d1272b8SAndroid Build Coastguard Worker
114*2d1272b8SAndroid Build Coastguard Worker /* Do this before any lookups have been applied. */
115*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (setup_syllables_use);
116*2d1272b8SAndroid Build Coastguard Worker
117*2d1272b8SAndroid Build Coastguard Worker /* "Default glyph pre-processing group" */
118*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
119*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
120*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (HB_TAG('n','u','k','t'), F_PER_SYLLABLE);
121*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
122*2d1272b8SAndroid Build Coastguard Worker
123*2d1272b8SAndroid Build Coastguard Worker /* "Reordering group" */
124*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (_hb_clear_substitution_flags);
125*2d1272b8SAndroid Build Coastguard Worker map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
126*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (record_rphf_use);
127*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (_hb_clear_substitution_flags);
128*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ | F_PER_SYLLABLE);
129*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (record_pref_use);
130*2d1272b8SAndroid Build Coastguard Worker
131*2d1272b8SAndroid Build Coastguard Worker /* "Orthographic unit shaping group" */
132*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
133*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
134*2d1272b8SAndroid Build Coastguard Worker
135*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (reorder_use);
136*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
137*2d1272b8SAndroid Build Coastguard Worker
138*2d1272b8SAndroid Build Coastguard Worker /* "Topographical features" */
139*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
140*2d1272b8SAndroid Build Coastguard Worker map->add_feature (use_topographical_features[i]);
141*2d1272b8SAndroid Build Coastguard Worker map->add_gsub_pause (nullptr);
142*2d1272b8SAndroid Build Coastguard Worker
143*2d1272b8SAndroid Build Coastguard Worker /* "Standard typographic presentation" */
144*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < ARRAY_LENGTH (use_other_features); i++)
145*2d1272b8SAndroid Build Coastguard Worker map->enable_feature (use_other_features[i], F_MANUAL_ZWJ);
146*2d1272b8SAndroid Build Coastguard Worker }
147*2d1272b8SAndroid Build Coastguard Worker
148*2d1272b8SAndroid Build Coastguard Worker struct use_shape_plan_t
149*2d1272b8SAndroid Build Coastguard Worker {
150*2d1272b8SAndroid Build Coastguard Worker hb_mask_t rphf_mask;
151*2d1272b8SAndroid Build Coastguard Worker
152*2d1272b8SAndroid Build Coastguard Worker arabic_shape_plan_t *arabic_plan;
153*2d1272b8SAndroid Build Coastguard Worker };
154*2d1272b8SAndroid Build Coastguard Worker
155*2d1272b8SAndroid Build Coastguard Worker static void *
data_create_use(const hb_ot_shape_plan_t * plan)156*2d1272b8SAndroid Build Coastguard Worker data_create_use (const hb_ot_shape_plan_t *plan)
157*2d1272b8SAndroid Build Coastguard Worker {
158*2d1272b8SAndroid Build Coastguard Worker use_shape_plan_t *use_plan = (use_shape_plan_t *) hb_calloc (1, sizeof (use_shape_plan_t));
159*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!use_plan))
160*2d1272b8SAndroid Build Coastguard Worker return nullptr;
161*2d1272b8SAndroid Build Coastguard Worker
162*2d1272b8SAndroid Build Coastguard Worker use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));
163*2d1272b8SAndroid Build Coastguard Worker
164*2d1272b8SAndroid Build Coastguard Worker if (has_arabic_joining (plan->props.script))
165*2d1272b8SAndroid Build Coastguard Worker {
166*2d1272b8SAndroid Build Coastguard Worker use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
167*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!use_plan->arabic_plan))
168*2d1272b8SAndroid Build Coastguard Worker {
169*2d1272b8SAndroid Build Coastguard Worker hb_free (use_plan);
170*2d1272b8SAndroid Build Coastguard Worker return nullptr;
171*2d1272b8SAndroid Build Coastguard Worker }
172*2d1272b8SAndroid Build Coastguard Worker }
173*2d1272b8SAndroid Build Coastguard Worker
174*2d1272b8SAndroid Build Coastguard Worker return use_plan;
175*2d1272b8SAndroid Build Coastguard Worker }
176*2d1272b8SAndroid Build Coastguard Worker
177*2d1272b8SAndroid Build Coastguard Worker static void
data_destroy_use(void * data)178*2d1272b8SAndroid Build Coastguard Worker data_destroy_use (void *data)
179*2d1272b8SAndroid Build Coastguard Worker {
180*2d1272b8SAndroid Build Coastguard Worker use_shape_plan_t *use_plan = (use_shape_plan_t *) data;
181*2d1272b8SAndroid Build Coastguard Worker
182*2d1272b8SAndroid Build Coastguard Worker if (use_plan->arabic_plan)
183*2d1272b8SAndroid Build Coastguard Worker data_destroy_arabic (use_plan->arabic_plan);
184*2d1272b8SAndroid Build Coastguard Worker
185*2d1272b8SAndroid Build Coastguard Worker hb_free (data);
186*2d1272b8SAndroid Build Coastguard Worker }
187*2d1272b8SAndroid Build Coastguard Worker
188*2d1272b8SAndroid Build Coastguard Worker static void
setup_masks_use(const hb_ot_shape_plan_t * plan,hb_buffer_t * buffer,hb_font_t * font HB_UNUSED)189*2d1272b8SAndroid Build Coastguard Worker setup_masks_use (const hb_ot_shape_plan_t *plan,
190*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer,
191*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font HB_UNUSED)
192*2d1272b8SAndroid Build Coastguard Worker {
193*2d1272b8SAndroid Build Coastguard Worker const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
194*2d1272b8SAndroid Build Coastguard Worker
195*2d1272b8SAndroid Build Coastguard Worker /* Do this before allocating use_category(). */
196*2d1272b8SAndroid Build Coastguard Worker if (use_plan->arabic_plan)
197*2d1272b8SAndroid Build Coastguard Worker {
198*2d1272b8SAndroid Build Coastguard Worker setup_masks_arabic_plan (use_plan->arabic_plan, buffer, plan->props.script);
199*2d1272b8SAndroid Build Coastguard Worker }
200*2d1272b8SAndroid Build Coastguard Worker
201*2d1272b8SAndroid Build Coastguard Worker HB_BUFFER_ALLOCATE_VAR (buffer, use_category);
202*2d1272b8SAndroid Build Coastguard Worker
203*2d1272b8SAndroid Build Coastguard Worker /* We cannot setup masks here. We save information about characters
204*2d1272b8SAndroid Build Coastguard Worker * and setup masks later on in a pause-callback. */
205*2d1272b8SAndroid Build Coastguard Worker
206*2d1272b8SAndroid Build Coastguard Worker unsigned int count = buffer->len;
207*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info;
208*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++)
209*2d1272b8SAndroid Build Coastguard Worker info[i].use_category() = hb_use_get_category (info[i].codepoint);
210*2d1272b8SAndroid Build Coastguard Worker }
211*2d1272b8SAndroid Build Coastguard Worker
212*2d1272b8SAndroid Build Coastguard Worker static void
setup_rphf_mask(const hb_ot_shape_plan_t * plan,hb_buffer_t * buffer)213*2d1272b8SAndroid Build Coastguard Worker setup_rphf_mask (const hb_ot_shape_plan_t *plan,
214*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer)
215*2d1272b8SAndroid Build Coastguard Worker {
216*2d1272b8SAndroid Build Coastguard Worker const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
217*2d1272b8SAndroid Build Coastguard Worker
218*2d1272b8SAndroid Build Coastguard Worker hb_mask_t mask = use_plan->rphf_mask;
219*2d1272b8SAndroid Build Coastguard Worker if (!mask) return;
220*2d1272b8SAndroid Build Coastguard Worker
221*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info;
222*2d1272b8SAndroid Build Coastguard Worker
223*2d1272b8SAndroid Build Coastguard Worker foreach_syllable (buffer, start, end)
224*2d1272b8SAndroid Build Coastguard Worker {
225*2d1272b8SAndroid Build Coastguard Worker unsigned int limit = info[start].use_category() == USE(R) ? 1 : hb_min (3u, end - start);
226*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = start; i < start + limit; i++)
227*2d1272b8SAndroid Build Coastguard Worker info[i].mask |= mask;
228*2d1272b8SAndroid Build Coastguard Worker }
229*2d1272b8SAndroid Build Coastguard Worker }
230*2d1272b8SAndroid Build Coastguard Worker
231*2d1272b8SAndroid Build Coastguard Worker static void
setup_topographical_masks(const hb_ot_shape_plan_t * plan,hb_buffer_t * buffer)232*2d1272b8SAndroid Build Coastguard Worker setup_topographical_masks (const hb_ot_shape_plan_t *plan,
233*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer)
234*2d1272b8SAndroid Build Coastguard Worker {
235*2d1272b8SAndroid Build Coastguard Worker const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
236*2d1272b8SAndroid Build Coastguard Worker if (use_plan->arabic_plan)
237*2d1272b8SAndroid Build Coastguard Worker return;
238*2d1272b8SAndroid Build Coastguard Worker
239*2d1272b8SAndroid Build Coastguard Worker static_assert ((JOINING_FORM_INIT < 4 && JOINING_FORM_ISOL < 4 && JOINING_FORM_MEDI < 4 && JOINING_FORM_FINA < 4), "");
240*2d1272b8SAndroid Build Coastguard Worker hb_mask_t masks[4], all_masks = 0;
241*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < 4; i++)
242*2d1272b8SAndroid Build Coastguard Worker {
243*2d1272b8SAndroid Build Coastguard Worker masks[i] = plan->map.get_1_mask (use_topographical_features[i]);
244*2d1272b8SAndroid Build Coastguard Worker if (masks[i] == plan->map.get_global_mask ())
245*2d1272b8SAndroid Build Coastguard Worker masks[i] = 0;
246*2d1272b8SAndroid Build Coastguard Worker all_masks |= masks[i];
247*2d1272b8SAndroid Build Coastguard Worker }
248*2d1272b8SAndroid Build Coastguard Worker if (!all_masks)
249*2d1272b8SAndroid Build Coastguard Worker return;
250*2d1272b8SAndroid Build Coastguard Worker hb_mask_t other_masks = ~all_masks;
251*2d1272b8SAndroid Build Coastguard Worker
252*2d1272b8SAndroid Build Coastguard Worker unsigned int last_start = 0;
253*2d1272b8SAndroid Build Coastguard Worker joining_form_t last_form = _JOINING_FORM_NONE;
254*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info;
255*2d1272b8SAndroid Build Coastguard Worker foreach_syllable (buffer, start, end)
256*2d1272b8SAndroid Build Coastguard Worker {
257*2d1272b8SAndroid Build Coastguard Worker use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
258*2d1272b8SAndroid Build Coastguard Worker switch (syllable_type)
259*2d1272b8SAndroid Build Coastguard Worker {
260*2d1272b8SAndroid Build Coastguard Worker case use_hieroglyph_cluster:
261*2d1272b8SAndroid Build Coastguard Worker case use_non_cluster:
262*2d1272b8SAndroid Build Coastguard Worker /* These don't join. Nothing to do. */
263*2d1272b8SAndroid Build Coastguard Worker last_form = _JOINING_FORM_NONE;
264*2d1272b8SAndroid Build Coastguard Worker break;
265*2d1272b8SAndroid Build Coastguard Worker
266*2d1272b8SAndroid Build Coastguard Worker case use_virama_terminated_cluster:
267*2d1272b8SAndroid Build Coastguard Worker case use_sakot_terminated_cluster:
268*2d1272b8SAndroid Build Coastguard Worker case use_standard_cluster:
269*2d1272b8SAndroid Build Coastguard Worker case use_number_joiner_terminated_cluster:
270*2d1272b8SAndroid Build Coastguard Worker case use_numeral_cluster:
271*2d1272b8SAndroid Build Coastguard Worker case use_symbol_cluster:
272*2d1272b8SAndroid Build Coastguard Worker case use_broken_cluster:
273*2d1272b8SAndroid Build Coastguard Worker
274*2d1272b8SAndroid Build Coastguard Worker bool join = last_form == JOINING_FORM_FINA || last_form == JOINING_FORM_ISOL;
275*2d1272b8SAndroid Build Coastguard Worker
276*2d1272b8SAndroid Build Coastguard Worker if (join)
277*2d1272b8SAndroid Build Coastguard Worker {
278*2d1272b8SAndroid Build Coastguard Worker /* Fixup previous syllable's form. */
279*2d1272b8SAndroid Build Coastguard Worker last_form = last_form == JOINING_FORM_FINA ? JOINING_FORM_MEDI : JOINING_FORM_INIT;
280*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = last_start; i < start; i++)
281*2d1272b8SAndroid Build Coastguard Worker info[i].mask = (info[i].mask & other_masks) | masks[last_form];
282*2d1272b8SAndroid Build Coastguard Worker }
283*2d1272b8SAndroid Build Coastguard Worker
284*2d1272b8SAndroid Build Coastguard Worker /* Form for this syllable. */
285*2d1272b8SAndroid Build Coastguard Worker last_form = join ? JOINING_FORM_FINA : JOINING_FORM_ISOL;
286*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = start; i < end; i++)
287*2d1272b8SAndroid Build Coastguard Worker info[i].mask = (info[i].mask & other_masks) | masks[last_form];
288*2d1272b8SAndroid Build Coastguard Worker
289*2d1272b8SAndroid Build Coastguard Worker break;
290*2d1272b8SAndroid Build Coastguard Worker }
291*2d1272b8SAndroid Build Coastguard Worker
292*2d1272b8SAndroid Build Coastguard Worker last_start = start;
293*2d1272b8SAndroid Build Coastguard Worker }
294*2d1272b8SAndroid Build Coastguard Worker }
295*2d1272b8SAndroid Build Coastguard Worker
296*2d1272b8SAndroid Build Coastguard Worker static bool
setup_syllables_use(const hb_ot_shape_plan_t * plan,hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)297*2d1272b8SAndroid Build Coastguard Worker setup_syllables_use (const hb_ot_shape_plan_t *plan,
298*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font HB_UNUSED,
299*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer)
300*2d1272b8SAndroid Build Coastguard Worker {
301*2d1272b8SAndroid Build Coastguard Worker HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
302*2d1272b8SAndroid Build Coastguard Worker find_syllables_use (buffer);
303*2d1272b8SAndroid Build Coastguard Worker foreach_syllable (buffer, start, end)
304*2d1272b8SAndroid Build Coastguard Worker buffer->unsafe_to_break (start, end);
305*2d1272b8SAndroid Build Coastguard Worker setup_rphf_mask (plan, buffer);
306*2d1272b8SAndroid Build Coastguard Worker setup_topographical_masks (plan, buffer);
307*2d1272b8SAndroid Build Coastguard Worker return false;
308*2d1272b8SAndroid Build Coastguard Worker }
309*2d1272b8SAndroid Build Coastguard Worker
310*2d1272b8SAndroid Build Coastguard Worker static bool
record_rphf_use(const hb_ot_shape_plan_t * plan,hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)311*2d1272b8SAndroid Build Coastguard Worker record_rphf_use (const hb_ot_shape_plan_t *plan,
312*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font HB_UNUSED,
313*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer)
314*2d1272b8SAndroid Build Coastguard Worker {
315*2d1272b8SAndroid Build Coastguard Worker const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
316*2d1272b8SAndroid Build Coastguard Worker
317*2d1272b8SAndroid Build Coastguard Worker hb_mask_t mask = use_plan->rphf_mask;
318*2d1272b8SAndroid Build Coastguard Worker if (!mask) return false;
319*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info;
320*2d1272b8SAndroid Build Coastguard Worker
321*2d1272b8SAndroid Build Coastguard Worker foreach_syllable (buffer, start, end)
322*2d1272b8SAndroid Build Coastguard Worker {
323*2d1272b8SAndroid Build Coastguard Worker /* Mark a substituted repha as USE(R). */
324*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
325*2d1272b8SAndroid Build Coastguard Worker if (_hb_glyph_info_substituted (&info[i]))
326*2d1272b8SAndroid Build Coastguard Worker {
327*2d1272b8SAndroid Build Coastguard Worker info[i].use_category() = USE(R);
328*2d1272b8SAndroid Build Coastguard Worker break;
329*2d1272b8SAndroid Build Coastguard Worker }
330*2d1272b8SAndroid Build Coastguard Worker }
331*2d1272b8SAndroid Build Coastguard Worker return false;
332*2d1272b8SAndroid Build Coastguard Worker }
333*2d1272b8SAndroid Build Coastguard Worker
334*2d1272b8SAndroid Build Coastguard Worker static bool
record_pref_use(const hb_ot_shape_plan_t * plan HB_UNUSED,hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)335*2d1272b8SAndroid Build Coastguard Worker record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
336*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font HB_UNUSED,
337*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer)
338*2d1272b8SAndroid Build Coastguard Worker {
339*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info;
340*2d1272b8SAndroid Build Coastguard Worker
341*2d1272b8SAndroid Build Coastguard Worker foreach_syllable (buffer, start, end)
342*2d1272b8SAndroid Build Coastguard Worker {
343*2d1272b8SAndroid Build Coastguard Worker /* Mark a substituted pref as VPre, as they behave the same way. */
344*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = start; i < end; i++)
345*2d1272b8SAndroid Build Coastguard Worker if (_hb_glyph_info_substituted (&info[i]))
346*2d1272b8SAndroid Build Coastguard Worker {
347*2d1272b8SAndroid Build Coastguard Worker info[i].use_category() = USE(VPre);
348*2d1272b8SAndroid Build Coastguard Worker break;
349*2d1272b8SAndroid Build Coastguard Worker }
350*2d1272b8SAndroid Build Coastguard Worker }
351*2d1272b8SAndroid Build Coastguard Worker return false;
352*2d1272b8SAndroid Build Coastguard Worker }
353*2d1272b8SAndroid Build Coastguard Worker
354*2d1272b8SAndroid Build Coastguard Worker static inline bool
is_halant_use(const hb_glyph_info_t & info)355*2d1272b8SAndroid Build Coastguard Worker is_halant_use (const hb_glyph_info_t &info)
356*2d1272b8SAndroid Build Coastguard Worker {
357*2d1272b8SAndroid Build Coastguard Worker return (info.use_category() == USE(H) || info.use_category() == USE(HVM) || info.use_category() == USE(IS)) &&
358*2d1272b8SAndroid Build Coastguard Worker !_hb_glyph_info_ligated (&info);
359*2d1272b8SAndroid Build Coastguard Worker }
360*2d1272b8SAndroid Build Coastguard Worker
361*2d1272b8SAndroid Build Coastguard Worker static void
reorder_syllable_use(hb_buffer_t * buffer,unsigned int start,unsigned int end)362*2d1272b8SAndroid Build Coastguard Worker reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
363*2d1272b8SAndroid Build Coastguard Worker {
364*2d1272b8SAndroid Build Coastguard Worker use_syllable_type_t syllable_type = (use_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
365*2d1272b8SAndroid Build Coastguard Worker /* Only a few syllable types need reordering. */
366*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!(FLAG_UNSAFE (syllable_type) &
367*2d1272b8SAndroid Build Coastguard Worker (FLAG (use_virama_terminated_cluster) |
368*2d1272b8SAndroid Build Coastguard Worker FLAG (use_sakot_terminated_cluster) |
369*2d1272b8SAndroid Build Coastguard Worker FLAG (use_standard_cluster) |
370*2d1272b8SAndroid Build Coastguard Worker FLAG (use_symbol_cluster) |
371*2d1272b8SAndroid Build Coastguard Worker FLAG (use_broken_cluster) |
372*2d1272b8SAndroid Build Coastguard Worker 0))))
373*2d1272b8SAndroid Build Coastguard Worker return;
374*2d1272b8SAndroid Build Coastguard Worker
375*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info;
376*2d1272b8SAndroid Build Coastguard Worker
377*2d1272b8SAndroid Build Coastguard Worker #define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
378*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(FBlw)) | \
379*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(FPst)) | \
380*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(FMAbv)) | \
381*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(FMBlw)) | \
382*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(FMPst)) | \
383*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(MAbv)) | \
384*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(MBlw)) | \
385*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(MPst)) | \
386*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(MPre)) | \
387*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VAbv)) | \
388*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VBlw)) | \
389*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VPst)) | \
390*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VPre)) | \
391*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VMAbv)) | \
392*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VMBlw)) | \
393*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VMPst)) | \
394*2d1272b8SAndroid Build Coastguard Worker FLAG64 (USE(VMPre)))
395*2d1272b8SAndroid Build Coastguard Worker
396*2d1272b8SAndroid Build Coastguard Worker /* Move things forward. */
397*2d1272b8SAndroid Build Coastguard Worker if (info[start].use_category() == USE(R) && end - start > 1)
398*2d1272b8SAndroid Build Coastguard Worker {
399*2d1272b8SAndroid Build Coastguard Worker /* Got a repha. Reorder it towards the end, but before the first post-base
400*2d1272b8SAndroid Build Coastguard Worker * glyph. */
401*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = start + 1; i < end; i++)
402*2d1272b8SAndroid Build Coastguard Worker {
403*2d1272b8SAndroid Build Coastguard Worker bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) ||
404*2d1272b8SAndroid Build Coastguard Worker is_halant_use (info[i]);
405*2d1272b8SAndroid Build Coastguard Worker if (is_post_base_glyph || i == end - 1)
406*2d1272b8SAndroid Build Coastguard Worker {
407*2d1272b8SAndroid Build Coastguard Worker /* If we hit a post-base glyph, move before it; otherwise move to the
408*2d1272b8SAndroid Build Coastguard Worker * end. Shift things in between backward. */
409*2d1272b8SAndroid Build Coastguard Worker
410*2d1272b8SAndroid Build Coastguard Worker if (is_post_base_glyph)
411*2d1272b8SAndroid Build Coastguard Worker i--;
412*2d1272b8SAndroid Build Coastguard Worker
413*2d1272b8SAndroid Build Coastguard Worker buffer->merge_clusters (start, i + 1);
414*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t t = info[start];
415*2d1272b8SAndroid Build Coastguard Worker memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0]));
416*2d1272b8SAndroid Build Coastguard Worker info[i] = t;
417*2d1272b8SAndroid Build Coastguard Worker
418*2d1272b8SAndroid Build Coastguard Worker break;
419*2d1272b8SAndroid Build Coastguard Worker }
420*2d1272b8SAndroid Build Coastguard Worker }
421*2d1272b8SAndroid Build Coastguard Worker }
422*2d1272b8SAndroid Build Coastguard Worker
423*2d1272b8SAndroid Build Coastguard Worker /* Move things back. */
424*2d1272b8SAndroid Build Coastguard Worker unsigned int j = start;
425*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = start; i < end; i++)
426*2d1272b8SAndroid Build Coastguard Worker {
427*2d1272b8SAndroid Build Coastguard Worker uint32_t flag = FLAG_UNSAFE (info[i].use_category());
428*2d1272b8SAndroid Build Coastguard Worker if (is_halant_use (info[i]))
429*2d1272b8SAndroid Build Coastguard Worker {
430*2d1272b8SAndroid Build Coastguard Worker /* If we hit a halant, move after it; otherwise move to the beginning, and
431*2d1272b8SAndroid Build Coastguard Worker * shift things in between forward. */
432*2d1272b8SAndroid Build Coastguard Worker j = i + 1;
433*2d1272b8SAndroid Build Coastguard Worker }
434*2d1272b8SAndroid Build Coastguard Worker else if (((flag) & (FLAG (USE(VPre)) | FLAG (USE(VMPre)))) &&
435*2d1272b8SAndroid Build Coastguard Worker /* Only move the first component of a MultipleSubst. */
436*2d1272b8SAndroid Build Coastguard Worker 0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
437*2d1272b8SAndroid Build Coastguard Worker j < i)
438*2d1272b8SAndroid Build Coastguard Worker {
439*2d1272b8SAndroid Build Coastguard Worker buffer->merge_clusters (j, i + 1);
440*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t t = info[i];
441*2d1272b8SAndroid Build Coastguard Worker memmove (&info[j + 1], &info[j], (i - j) * sizeof (info[0]));
442*2d1272b8SAndroid Build Coastguard Worker info[j] = t;
443*2d1272b8SAndroid Build Coastguard Worker }
444*2d1272b8SAndroid Build Coastguard Worker }
445*2d1272b8SAndroid Build Coastguard Worker }
446*2d1272b8SAndroid Build Coastguard Worker
447*2d1272b8SAndroid Build Coastguard Worker static bool
reorder_use(const hb_ot_shape_plan_t * plan,hb_font_t * font,hb_buffer_t * buffer)448*2d1272b8SAndroid Build Coastguard Worker reorder_use (const hb_ot_shape_plan_t *plan,
449*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font,
450*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer)
451*2d1272b8SAndroid Build Coastguard Worker {
452*2d1272b8SAndroid Build Coastguard Worker bool ret = false;
453*2d1272b8SAndroid Build Coastguard Worker if (buffer->message (font, "start reordering USE"))
454*2d1272b8SAndroid Build Coastguard Worker {
455*2d1272b8SAndroid Build Coastguard Worker if (hb_syllabic_insert_dotted_circles (font, buffer,
456*2d1272b8SAndroid Build Coastguard Worker use_broken_cluster,
457*2d1272b8SAndroid Build Coastguard Worker USE(B),
458*2d1272b8SAndroid Build Coastguard Worker USE(R)))
459*2d1272b8SAndroid Build Coastguard Worker ret = true;
460*2d1272b8SAndroid Build Coastguard Worker
461*2d1272b8SAndroid Build Coastguard Worker foreach_syllable (buffer, start, end)
462*2d1272b8SAndroid Build Coastguard Worker reorder_syllable_use (buffer, start, end);
463*2d1272b8SAndroid Build Coastguard Worker
464*2d1272b8SAndroid Build Coastguard Worker (void) buffer->message (font, "end reordering USE");
465*2d1272b8SAndroid Build Coastguard Worker }
466*2d1272b8SAndroid Build Coastguard Worker
467*2d1272b8SAndroid Build Coastguard Worker HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
468*2d1272b8SAndroid Build Coastguard Worker
469*2d1272b8SAndroid Build Coastguard Worker return ret;
470*2d1272b8SAndroid Build Coastguard Worker }
471*2d1272b8SAndroid Build Coastguard Worker
472*2d1272b8SAndroid Build Coastguard Worker
473*2d1272b8SAndroid Build Coastguard Worker static void
preprocess_text_use(const hb_ot_shape_plan_t * plan,hb_buffer_t * buffer,hb_font_t * font)474*2d1272b8SAndroid Build Coastguard Worker preprocess_text_use (const hb_ot_shape_plan_t *plan,
475*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer,
476*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font)
477*2d1272b8SAndroid Build Coastguard Worker {
478*2d1272b8SAndroid Build Coastguard Worker _hb_preprocess_text_vowel_constraints (plan, buffer, font);
479*2d1272b8SAndroid Build Coastguard Worker }
480*2d1272b8SAndroid Build Coastguard Worker
481*2d1272b8SAndroid Build Coastguard Worker static bool
compose_use(const hb_ot_shape_normalize_context_t * c,hb_codepoint_t a,hb_codepoint_t b,hb_codepoint_t * ab)482*2d1272b8SAndroid Build Coastguard Worker compose_use (const hb_ot_shape_normalize_context_t *c,
483*2d1272b8SAndroid Build Coastguard Worker hb_codepoint_t a,
484*2d1272b8SAndroid Build Coastguard Worker hb_codepoint_t b,
485*2d1272b8SAndroid Build Coastguard Worker hb_codepoint_t *ab)
486*2d1272b8SAndroid Build Coastguard Worker {
487*2d1272b8SAndroid Build Coastguard Worker /* Avoid recomposing split matras. */
488*2d1272b8SAndroid Build Coastguard Worker if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
489*2d1272b8SAndroid Build Coastguard Worker return false;
490*2d1272b8SAndroid Build Coastguard Worker
491*2d1272b8SAndroid Build Coastguard Worker return (bool)c->unicode->compose (a, b, ab);
492*2d1272b8SAndroid Build Coastguard Worker }
493*2d1272b8SAndroid Build Coastguard Worker
494*2d1272b8SAndroid Build Coastguard Worker
495*2d1272b8SAndroid Build Coastguard Worker const hb_ot_shaper_t _hb_ot_shaper_use =
496*2d1272b8SAndroid Build Coastguard Worker {
497*2d1272b8SAndroid Build Coastguard Worker collect_features_use,
498*2d1272b8SAndroid Build Coastguard Worker nullptr, /* override_features */
499*2d1272b8SAndroid Build Coastguard Worker data_create_use,
500*2d1272b8SAndroid Build Coastguard Worker data_destroy_use,
501*2d1272b8SAndroid Build Coastguard Worker preprocess_text_use,
502*2d1272b8SAndroid Build Coastguard Worker nullptr, /* postprocess_glyphs */
503*2d1272b8SAndroid Build Coastguard Worker nullptr, /* decompose */
504*2d1272b8SAndroid Build Coastguard Worker compose_use,
505*2d1272b8SAndroid Build Coastguard Worker setup_masks_use,
506*2d1272b8SAndroid Build Coastguard Worker nullptr, /* reorder_marks */
507*2d1272b8SAndroid Build Coastguard Worker HB_TAG_NONE, /* gpos_tag */
508*2d1272b8SAndroid Build Coastguard Worker HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
509*2d1272b8SAndroid Build Coastguard Worker HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
510*2d1272b8SAndroid Build Coastguard Worker false, /* fallback_position */
511*2d1272b8SAndroid Build Coastguard Worker };
512*2d1272b8SAndroid Build Coastguard Worker
513*2d1272b8SAndroid Build Coastguard Worker
514*2d1272b8SAndroid Build Coastguard Worker #endif
515