2 * Copyright © 2015 Mozilla Foundation.
3 * Copyright © 2015 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 * Mozilla Author(s): Jonathan Kew
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_SHAPER_USE_MACHINE_HH
30 #define HB_OT_SHAPER_USE_MACHINE_HH
34 #include "hb-ot-shaper-syllabic.hh"
36 /* buffer var allocations */
37 #define use_category() ot_shaper_var_u8_category()
39 #define USE(Cat) use_syllable_machine_ex_##Cat
41 enum use_syllable_type_t {
42 use_virama_terminated_cluster,
43 use_sakot_terminated_cluster,
45 use_number_joiner_terminated_cluster,
48 use_hieroglyph_cluster,
54 machine use_syllable_machine;
55 alphtype unsigned char;
62 # Categories used in the Universal Shaping Engine spec:
63 # https://docs.microsoft.com/en-us/typography/script-development/use
68 export N = 4; # BASE_NUM
69 export GB = 5; # BASE_OTHER
71 export SUB = 11; # CONS_SUB
72 export H = 12; # HALANT
74 export HN = 13; # HALANT_NUM
75 export ZWNJ = 14; # Zero width non-joiner
76 export WJ = 16; # Word joiner
77 export R = 18; # REPHA
78 export CS = 43; # CONS_WITH_STACKER
79 export IS = 44; # INVISIBLE_STACKER
80 export Sk = 48; # SAKOT
81 export G = 49; # HIEROGLYPH
82 export J = 50; # HIEROGLYPH_JOINER
83 export SB = 51; # HIEROGLYPH_SEGMENT_BEGIN
84 export SE = 52; # HIEROGLYPH_SEGMENT_END
85 export HVM = 53; # HALANT_OR_VOWEL_MODIFIER
86 export HM = 54; # HIEROGLYPH_MOD
87 export HR = 55; # HIEROGLYPH_MIRROR
89 export FAbv = 24; # CONS_FINAL_ABOVE
90 export FBlw = 25; # CONS_FINAL_BELOW
91 export FPst = 26; # CONS_FINAL_POST
92 export MAbv = 27; # CONS_MED_ABOVE
93 export MBlw = 28; # CONS_MED_BELOW
94 export MPst = 29; # CONS_MED_POST
95 export MPre = 30; # CONS_MED_PRE
96 export CMAbv = 31; # CONS_MOD_ABOVE
97 export CMBlw = 32; # CONS_MOD_BELOW
98 export VAbv = 33; # VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST
99 export VBlw = 34; # VOWEL_BELOW / VOWEL_BELOW_POST
100 export VPst = 35; # VOWEL_POST UIPC = Right
101 export VPre = 22; # VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST
102 export VMAbv = 37; # VOWEL_MOD_ABOVE
103 export VMBlw = 38; # VOWEL_MOD_BELOW
104 export VMPst = 39; # VOWEL_MOD_POST
105 export VMPre = 23; # VOWEL_MOD_PRE
106 export SMAbv = 41; # SYM_MOD_ABOVE
107 export SMBlw = 42; # SYM_MOD_BELOW
108 export FMAbv = 45; # CONS_FINAL_MOD UIPC = Top
109 export FMBlw = 46; # CONS_FINAL_MOD UIPC = Bottom
110 export FMPst = 47; # CONS_FINAL_MOD UIPC = Not_Applicable
113 h = H | HVM | IS | Sk;
115 consonant_modifiers = CMAbv* CMBlw* ((h B | SUB) CMAbv* CMBlw*)*;
116 medial_consonants = MPre? MAbv? MBlw? MPst?;
117 dependent_vowels = VPre* VAbv* VBlw* VPst* | H;
118 vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*;
119 final_consonants = FAbv* FBlw* FPst*;
120 final_modifiers = FMAbv* FMBlw* | FMPst?;
122 complex_syllable_start = (R | CS)? (B | GB);
123 complex_syllable_middle =
130 complex_syllable_tail =
131 complex_syllable_middle
135 number_joiner_terminated_cluster_tail = (HN N)* HN;
136 numeral_cluster_tail = (HN N)+;
137 symbol_cluster_tail = SMAbv+ SMBlw* | SMBlw+;
139 virama_terminated_cluster_tail =
143 virama_terminated_cluster =
144 complex_syllable_start
145 virama_terminated_cluster_tail
147 sakot_terminated_cluster_tail =
148 complex_syllable_middle
151 sakot_terminated_cluster =
152 complex_syllable_start
153 sakot_terminated_cluster_tail
156 complex_syllable_start
157 complex_syllable_tail
159 tail = complex_syllable_tail | sakot_terminated_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail;
162 (tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail)
165 number_joiner_terminated_cluster = N number_joiner_terminated_cluster_tail;
166 numeral_cluster = N numeral_cluster_tail?;
167 symbol_cluster = (O | GB | SB) tail?;
168 hieroglyph_cluster = SB* G HR? HM? SE* (J SB* (G HR? HM? SE*)?)*;
172 virama_terminated_cluster ZWNJ? => { found_syllable (use_virama_terminated_cluster); };
173 sakot_terminated_cluster ZWNJ? => { found_syllable (use_sakot_terminated_cluster); };
174 standard_cluster ZWNJ? => { found_syllable (use_standard_cluster); };
175 number_joiner_terminated_cluster ZWNJ? => { found_syllable (use_number_joiner_terminated_cluster); };
176 numeral_cluster ZWNJ? => { found_syllable (use_numeral_cluster); };
177 symbol_cluster ZWNJ? => { found_syllable (use_symbol_cluster); };
178 hieroglyph_cluster ZWNJ? => { found_syllable (use_hieroglyph_cluster); };
179 broken_cluster ZWNJ? => { found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; };
180 other => { found_syllable (use_non_cluster); };
186 #define found_syllable(syllable_type) \
188 if (0) fprintf (stderr, "syllable %u..%u %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \
189 for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \
190 info[i].syllable() = (syllable_serial << 4) | syllable_type; \
192 if (syllable_serial == 16) syllable_serial = 1; \
196 template <typename Iter>
197 struct machine_index_t :
198 hb_iter_with_fallback_t<machine_index_t<Iter>,
199 typename Iter::item_t>
201 machine_index_t (const Iter& it) : it (it) {}
202 machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>,
203 typename Iter::item_t> (),
204 it (o.it), is_null (o.is_null) {}
206 static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
207 static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
209 typename Iter::item_t __item__ () const { return *it; }
210 typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; }
211 unsigned __len__ () const { return it.len (); }
212 void __next__ () { ++it; }
213 void __forward__ (unsigned n) { it += n; }
214 void __prev__ () { --it; }
215 void __rewind__ (unsigned n) { it -= n; }
217 void operator = (unsigned n)
222 explicit operator bool () { return !is_null; }
224 void operator = (const machine_index_t& o)
227 unsigned index = (*it).first;
228 unsigned n = (*o.it).first;
229 if (index < n) it += n - index; else if (index > n) it -= index - n;
231 bool operator == (const machine_index_t& o) const
232 { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; }
233 bool operator != (const machine_index_t& o) const { return !(*this == o); }
237 bool is_null = false;
241 template <typename Iter,
242 hb_requires (hb_is_iterable (Iter))>
243 machine_index_t<hb_iter_type<Iter>>
244 operator () (Iter&& it) const
245 { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); }
247 HB_FUNCOBJ (machine_index);
252 not_ccs_default_ignorable (const hb_glyph_info_t &i)
253 { return i.use_category() != USE(CGJ); }
256 find_syllables_use (hb_buffer_t *buffer)
258 hb_glyph_info_t *info = buffer->info;
260 + hb_iter (info, buffer->len)
262 | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); },
264 | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
266 if (p.second.use_category() == USE(ZWNJ))
267 for (unsigned i = p.first + 1; i < buffer->len; ++i)
268 if (not_ccs_default_ignorable (info[i]))
269 return !_hb_glyph_info_is_unicode_mark (&info[i]);
275 auto pe = p + p.len ();
279 unsigned int act HB_UNUSED;
283 getkey (*p).second.second.use_category();
286 unsigned int syllable_serial = 1;
292 #undef found_syllable
294 #endif /* HB_OT_SHAPER_USE_MACHINE_HH */