Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / hb-ot-shaper-use-machine.rl
1 /*
2  * Copyright © 2015  Mozilla Foundation.
3  * Copyright © 2015  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
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.
12  *
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
17  * DAMAGE.
18  *
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.
24  *
25  * Mozilla Author(s): Jonathan Kew
26  * Google Author(s): Behdad Esfahbod
27  */
28
29 #ifndef HB_OT_SHAPER_USE_MACHINE_HH
30 #define HB_OT_SHAPER_USE_MACHINE_HH
31
32 #include "hb.hh"
33
34 #include "hb-ot-shaper-syllabic.hh"
35
36 /* buffer var allocations */
37 #define use_category() ot_shaper_var_u8_category()
38
39 #define USE(Cat) use_syllable_machine_ex_##Cat
40
41 enum use_syllable_type_t {
42   use_virama_terminated_cluster,
43   use_sakot_terminated_cluster,
44   use_standard_cluster,
45   use_number_joiner_terminated_cluster,
46   use_numeral_cluster,
47   use_symbol_cluster,
48   use_hieroglyph_cluster,
49   use_broken_cluster,
50   use_non_cluster,
51 };
52
53 %%{
54   machine use_syllable_machine;
55   alphtype unsigned char;
56   write exports;
57   write data;
58 }%%
59
60 %%{
61
62 # Categories used in the Universal Shaping Engine spec:
63 # https://docs.microsoft.com/en-us/typography/script-development/use
64
65 export O        = 0; # OTHER
66
67 export B        = 1; # BASE
68 export N        = 4; # BASE_NUM
69 export GB       = 5; # BASE_OTHER
70 export CGJ      = 6; # CGJ
71 export SUB      = 11; # CONS_SUB
72 export H        = 12; # HALANT
73
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
88
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
111
112
113 h = H | HVM | IS | Sk;
114
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?;
121
122 complex_syllable_start = (R | CS)? (B | GB);
123 complex_syllable_middle =
124         consonant_modifiers
125         medial_consonants
126         dependent_vowels
127         vowel_modifiers
128         (Sk B)*
129 ;
130 complex_syllable_tail =
131         complex_syllable_middle
132         final_consonants
133         final_modifiers
134 ;
135 number_joiner_terminated_cluster_tail = (HN N)* HN;
136 numeral_cluster_tail = (HN N)+;
137 symbol_cluster_tail = SMAbv+ SMBlw* | SMBlw+;
138
139 virama_terminated_cluster_tail =
140         consonant_modifiers
141         IS
142 ;
143 virama_terminated_cluster =
144         complex_syllable_start
145         virama_terminated_cluster_tail
146 ;
147 sakot_terminated_cluster_tail =
148         complex_syllable_middle
149         Sk
150 ;
151 sakot_terminated_cluster =
152         complex_syllable_start
153         sakot_terminated_cluster_tail
154 ;
155 standard_cluster =
156         complex_syllable_start
157         complex_syllable_tail
158 ;
159 tail = complex_syllable_tail | sakot_terminated_cluster_tail | symbol_cluster_tail | virama_terminated_cluster_tail;
160 broken_cluster =
161         R?
162         (tail | number_joiner_terminated_cluster_tail | numeral_cluster_tail)
163 ;
164
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*)?)*;
169 other = any;
170
171 main := |*
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); };
181 *|;
182
183
184 }%%
185
186 #define found_syllable(syllable_type) \
187   HB_STMT_START { \
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; \
191     syllable_serial++; \
192     if (syllable_serial == 16) syllable_serial = 1; \
193   } HB_STMT_END
194
195
196 template <typename Iter>
197 struct machine_index_t :
198   hb_iter_with_fallback_t<machine_index_t<Iter>,
199                           typename Iter::item_t>
200 {
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) {}
205
206   static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
207   static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
208
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; }
216
217   void operator = (unsigned n)
218   {
219     assert (n == 0);
220     is_null = true;
221   }
222   explicit operator bool () { return !is_null; }
223
224   void operator = (const machine_index_t& o)
225   {
226     is_null = o.is_null;
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;
230   }
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); }
234
235   private:
236   Iter it;
237   bool is_null = false;
238 };
239 struct
240 {
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)); }
246 }
247 HB_FUNCOBJ (machine_index);
248
249
250
251 static bool
252 not_ccs_default_ignorable (const hb_glyph_info_t &i)
253 { return i.use_category() != USE(CGJ); }
254
255 static inline void
256 find_syllables_use (hb_buffer_t *buffer)
257 {
258   hb_glyph_info_t *info = buffer->info;
259   auto p =
260     + hb_iter (info, buffer->len)
261     | hb_enumerate
262     | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); },
263                  hb_second)
264     | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p)
265                  {
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]);
270                    return true;
271                  })
272     | hb_enumerate
273     | machine_index
274     ;
275   auto pe = p + p.len ();
276   auto eof = +pe;
277   auto ts = +p;
278   auto te = +p;
279   unsigned int act HB_UNUSED;
280   int cs;
281   %%{
282     write init;
283     getkey (*p).second.second.use_category();
284   }%%
285
286   unsigned int syllable_serial = 1;
287   %%{
288     write exec;
289   }%%
290 }
291
292 #undef found_syllable
293
294 #endif /* HB_OT_SHAPER_USE_MACHINE_HH */