composer package updates
[openemr.git] / vendor / mpdf / mpdf / src / Shaper / Sea.php
blob8bc7a6bd1cd1ed9aa8adb027c3016753474e94c1
1 <?php
3 namespace Mpdf\Shaper;
5 class Sea
7 // South East Asian shaper
8 // sea_category
9 const OT_X = 0;
11 const OT_C = 1;
13 const OT_IV = 2; # Independent Vowel
15 const OT_T = 3; # Tone Marks
17 const OT_H = 4; # Halant
19 const OT_A = 10; # Anusvara
21 const OT_GB = 12; # Generic Base (OT_DOTTEDCIRCLE in Indic)
23 const OT_CM = 17; # Consonant Medial
25 const OT_MR = 22; # Medial Ra
27 const OT_VABV = 26;
29 const OT_VBLW = 27;
31 const OT_VPRE = 28;
33 const OT_VPST = 29;
35 // ? From Indic categories
36 const OT_ZWNJ = 5;
38 const OT_ZWJ = 6;
40 const OT_M = 7;
42 const OT_SM = 8;
44 const OT_VD = 9;
46 const OT_NBSP = 11;
48 const OT_RS = 13;
50 const OT_COENG = 14;
52 const OT_REPHA = 15;
54 const OT_RA = 16;
56 /* Visual positions in a syllable from left to right. */
57 // sea_position
58 const POS_START = 0;
60 const POS_RA_TO_BECOME_REPH = 1;
62 const POS_PRE_M = 2;
64 const POS_PRE_C = 3;
66 const POS_BASE_C = 4;
68 const POS_AFTER_MAIN = 5;
70 const POS_ABOVE_C = 6;
72 const POS_BEFORE_SUB = 7;
74 const POS_BELOW_C = 8;
76 const POS_AFTER_SUB = 9;
78 const POS_BEFORE_POST = 10;
80 const POS_POST_C = 11;
82 const POS_AFTER_POST = 12;
84 const POS_FINAL_C = 13;
86 const POS_SMVD = 14;
88 const POS_END = 15;
90 // Based on sea_category used to make string to find syllables
91 // OT_ to string character (using e.g. OT_C from INDIC) hb-ot-shape-complex-sea-private.hh
92 public static $sea_category_char = [
93 'x',
94 'C',
95 'V',
96 'T',
97 'H',
98 'x',
99 'x',
100 'x',
101 'x',
102 'x',
103 'A',
104 'x',
105 'G',
106 'x',
107 'x',
108 'x',
109 'x',
110 'M',
111 'x',
112 'x',
113 'x',
114 'x',
115 'R',
116 'x',
117 'x',
118 'x',
119 'a',
120 'b',
121 'p',
122 't',
125 public static function set_sea_properties(&$info, $scriptblock)
127 $u = $info['uni'];
128 $type = self::sea_get_categories($u);
129 $cat = ($type & 0x7F);
130 $pos = ($type >> 8);
133 * Re-assign category
135 // Medial Ra
136 if ($u == 0x1A55 || $u == 0xAA34) {
137 $cat = self::OT_MR;
141 * Re-assign position.
143 if ($cat == self::OT_M) { // definitely "OT_M" in HarfBuzz - although this does not seem to have been defined ? should be OT_MR
144 switch ($pos) {
145 case self::POS_PRE_C:
146 $cat = self::OT_VPRE;
147 break;
148 case self::POS_ABOVE_C:
149 $cat = self::OT_VABV;
150 break;
151 case self::POS_BELOW_C:
152 $cat = self::OT_VBLW;
153 break;
154 case self::POS_POST_C:
155 $cat = self::OT_VPST;
156 break;
160 $info['sea_category'] = $cat;
161 $info['sea_position'] = $pos;
164 // syllable_type
165 const CONSONANT_SYLLABLE = 0;
167 const BROKEN_CLUSTER = 1;
169 const NON_SEA_CLUSTER = 2;
171 public static function set_syllables(&$o, $s, &$broken_syllables)
173 $ptr = 0;
174 $syllable_serial = 1;
175 $broken_syllables = false;
176 while ($ptr < strlen($s)) {
177 $match = '';
178 $syllable_length = 1;
179 $syllable_type = self::NON_SEA_CLUSTER;
181 // CONSONANT_SYLLABLE Consonant syllable
182 if (preg_match('/^(C|V|G)(p|a|b|t|HC|M|R|T|A)*/', substr($s, $ptr), $ma)) {
183 $syllable_length = strlen($ma[0]);
184 $syllable_type = self::CONSONANT_SYLLABLE;
185 } // BROKEN_CLUSTER syllable
186 else if (preg_match('/^(p|a|b|t|HC|M|R|T|A)+/', substr($s, $ptr), $ma)) {
187 $syllable_length = strlen($ma[0]);
188 $syllable_type = self::BROKEN_CLUSTER;
189 $broken_syllables = true;
192 for ($i = $ptr; $i < $ptr + $syllable_length; $i++) {
193 $o[$i]['syllable'] = ($syllable_serial << 4) | $syllable_type;
195 $ptr += $syllable_length;
196 $syllable_serial++;
197 if ($syllable_serial == 16) {
198 $syllable_serial = 1;
203 public static function initial_reordering(&$info, $GSUBdata, $broken_syllables, $scriptblock, $dottedcircle)
206 if ($broken_syllables && $dottedcircle) {
207 self::insert_dotted_circles($info, $dottedcircle);
210 $count = count($info);
211 if (!$count) {
212 return;
214 $last = 0;
215 $last_syllable = $info[0]['syllable'];
216 for ($i = 1; $i < $count; $i++) {
217 if ($last_syllable != $info[$i]['syllable']) {
218 self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $i);
219 $last = $i;
220 $last_syllable = $info[$last]['syllable'];
223 self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
226 public static function insert_dotted_circles(&$info, $dottedcircle)
228 $idx = 0;
229 $last_syllable = 0;
230 while ($idx < count($info)) {
231 $syllable = $info[$idx]['syllable'];
232 $syllable_type = ($syllable & 0x0F);
233 if ($last_syllable != $syllable && $syllable_type == self::BROKEN_CLUSTER) {
234 $last_syllable = $syllable;
235 $dottedcircle[0]['syllable'] = $info[$idx]['syllable'];
236 array_splice($info, $idx, 0, $dottedcircle);
237 } else {
238 $idx++;
243 public static function initial_reordering_syllable(&$info, $GSUBdata, $scriptblock, $start, $end)
245 /* broken_cluster: We already inserted dotted-circles, so just call the standalone_cluster. */
247 $syllable_type = ($info[$start]['syllable'] & 0x0F);
248 if ($syllable_type == self::NON_SEA_CLUSTER) {
249 return;
251 if ($syllable_type == self::BROKEN_CLUSTER) {
252 /* For dotted-circle, this is what Uniscribe does:
253 * If dotted-circle is the last glyph, it just does nothing. */
254 if ($info[$end - 1]['sea_category'] == self::OT_GB) {
255 return;
259 $base = $start;
260 $i = $start;
261 for (; $i < $base; $i++) {
262 $info[$i]['sea_position'] = self::POS_PRE_C;
264 if ($i < $end) {
265 $info[$i]['sea_position'] = self::POS_BASE_C;
266 $i++;
268 for (; $i < $end; $i++) {
269 if (isset($info[$i]['sea_category']) && $info[$i]['sea_category'] == self::OT_MR) { /* Pre-base reordering */
270 $info[$i]['sea_position'] = self::POS_PRE_C;
271 continue;
273 if (isset($info[$i]['sea_category']) && $info[$i]['sea_category'] == self::OT_VPRE) { /* Left matra */
274 $info[$i]['sea_position'] = self::POS_PRE_M;
275 continue;
277 $info[$i]['sea_position'] = self::POS_AFTER_MAIN;
280 /* Sit tight, rock 'n roll! */
281 self::bubble_sort($info, $start, $end - $start);
284 public static function final_reordering(&$info, $GSUBdata, $scriptblock)
286 $count = count($info);
287 if (!$count) {
288 return;
290 $last = 0;
291 $last_syllable = $info[0]['syllable'];
292 for ($i = 1; $i < $count; $i++) {
293 if ($last_syllable != $info[$i]['syllable']) {
294 self::final_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $i);
295 $last = $i;
296 $last_syllable = $info[$last]['syllable'];
299 self::final_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
302 public static function final_reordering_syllable(&$info, $GSUBdata, $scriptblock, $start, $end)
305 * Nothing to do here at present!
309 public static $sea_table = [
310 /* New Tai Lue (1980..19DF) */
312 /* 1980 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
313 /* 1988 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
314 /* 1990 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
315 /* 1998 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
316 /* 19A0 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
317 /* 19A8 */ 3841, 3841, 3841, 3841, 3840, 3840, 3840, 3840,
318 /* 19B0 */ 2823, 2823, 2823, 2823, 2823, 775, 775, 775,
319 /* 19B8 */ 2823, 2823, 775, 2823, 2823, 2823, 2823, 2823,
320 /* 19C0 */ 2823, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
321 /* 19C8 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
322 /* 19D0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
323 /* 19D8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
324 /* Tai Tham (1A20..1AAF) */
326 /* 1A20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
327 /* 1A28 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
328 /* 1A30 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
329 /* 1A38 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
330 /* 1A40 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
331 /* 1A48 */ 3841, 3841, 3841, 3841, 3841, 3842, 3842, 3842,
332 /* 1A50 */ 3842, 3842, 3842, 3841, 3841, 3857, 3857, 3857,
333 /* 1A58 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3840,
334 /* 1A60 */ 3844, 2823, 1543, 2823, 2823, 1543, 1543, 1543,
335 /* 1A68 */ 1543, 2055, 2055, 1543, 2055, 2823, 775, 775,
336 /* 1A70 */ 775, 775, 775, 1543, 1543, 3843, 3843, 3843,
337 /* 1A78 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
338 /* 1A80 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
339 /* 1A88 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
340 /* 1A90 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
341 /* 1A98 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
342 /* 1AA0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
343 /* 1AA8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
344 /* Cham (AA00..AA5F) */
346 /* AA00 */ 3842, 3842, 3842, 3842, 3842, 3842, 3841, 3841,
347 /* AA08 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
348 /* AA10 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
349 /* AA18 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
350 /* AA20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
351 /* AA28 */ 3841, 1543, 1543, 1543, 1543, 2055, 1543, 775,
352 /* AA30 */ 775, 1543, 2055, 3857, 3857, 3857, 3857, 3840,
353 /* AA38 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
354 /* AA40 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
355 /* AA48 */ 3857, 3857, 3857, 3857, 3857, 3857, 3840, 3840,
356 /* AA50 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
357 /* AA58 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
360 public static function sea_get_categories($u)
362 if (0x1980 <= $u && $u <= 0x19DF) {
363 return self::$sea_table[$u - 0x1980]; // offset 0 for New Tai Lue
365 if (0x1A20 <= $u && $u <= 0x1AAF) {
366 return self::$sea_table[$u - 0x1A20 + 96]; // offset for Tai Tham
368 if (0xAA00 <= $u && $u <= 0xAA5F) {
369 return self::$sea_table[$u - 0xAA00 + 96 + 144]; // Cham
371 if ($u == 0x00A0) {
372 return 3851; // (ISC_CP | (IMC_x << 8))
374 if ($u == 0x25CC) {
375 return 3851; // (ISC_CP | (IMC_x << 8))
377 return 3840; // (ISC_x | (IMC_x << 8))
380 public static function bubble_sort(&$arr, $start, $len)
382 if ($len < 2) {
383 return;
385 $k = $start + $len - 2;
386 while ($k >= $start) {
387 for ($j = $start; $j <= $k; $j++) {
388 if ($arr[$j]['sea_position'] > $arr[$j + 1]['sea_position']) {
389 $t = $arr[$j];
390 $arr[$j] = $arr[$j + 1];
391 $arr[$j + 1] = $t;
394 $k--;