PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / trunk
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin vtrunk
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
← All changes | mpdf/classes/sea.php +383 -349 1.8.3trunk View file →
@@ -1,349 +1,383 @@
1 -<?php
2 -
3 -
4 -class SEA {
5 -
6 -// South East Asian shaper
7 -
8 -// sea_category
9 -const OT_X = 0;
10 -const OT_C = 1;
11 -const OT_IV = 2; # Independent Vowel
12 -const OT_T = 3; # Tone Marks
13 -const OT_H = 4; # Halant
14 -const OT_A = 10; # Anusvara
15 -const OT_GB = 12; # Generic Base (OT_DOTTEDCIRCLE in Indic)
16 -const OT_CM = 17; # Consonant Medial
17 -const OT_MR = 22; # Medial Ra
18 -const OT_VAbv = 26;
19 -const OT_VBlw = 27;
20 -const OT_VPre = 28;
21 -const OT_VPst = 29;
22 -// ? From Indic categories
23 -const OT_ZWNJ = 5;
24 -const OT_ZWJ = 6;
25 -const OT_M = 7;
26 -const OT_SM = 8;
27 -const OT_VD = 9;
28 -const OT_NBSP = 11;
29 -const OT_RS = 13;
30 -const OT_Coeng = 14;
31 -const OT_Repha = 15;
32 -const OT_Ra = 16;
33 -
34 -// Based on sea_category used to make string to find syllables
35 -// OT_ to string character (using e.g. OT_C from INDIC) hb-ot-shape-complex-sea-private.hh
36 -public static $sea_category_char = array(
37 -'x',
38 -'C',
39 -'V',
40 -'T',
41 -'H',
42 -'x',
43 -'x',
44 -'x',
45 -'x',
46 -'x',
47 -'A',
48 -'x',
49 -'G',
50 -'x',
51 -'x',
52 -'x',
53 -'x',
54 -'M',
55 -'x',
56 -'x',
57 -'x',
58 -'x',
59 -'R',
60 -'x',
61 -'x',
62 -'x',
63 -'a',
64 -'b',
65 -'p',
66 -'t',
67 -);
68 -
69 -
70 -/* Visual positions in a syllable from left to right. */
71 -// sea_position
72 -const POS_START = 0;
73 -
74 -const POS_RA_TO_BECOME_REPH = 1;
75 -const POS_PRE_M = 2;
76 -const POS_PRE_C = 3;
77 -
78 -const POS_BASE_C = 4;
79 -const POS_AFTER_MAIN = 5;
80 -
81 -const POS_ABOVE_C = 6;
82 -
83 -const POS_BEFORE_SUB = 7;
84 -const POS_BELOW_C = 8;
85 -const POS_AFTER_SUB = 9;
86 -
87 -const POS_BEFORE_POST = 10;
88 -const POS_POST_C = 11;
89 -const POS_AFTER_POST = 12;
90 -
91 -const POS_FINAL_C = 13;
92 -const POS_SMVD = 14;
93 -
94 -const POS_END = 15;
95 -
96 -
97 -
98 -public static function set_sea_properties(&$info, $scriptblock ) {
99 - $u = $info['uni'];
100 - $type = self::sea_get_categories($u);
101 - $cat = ($type & 0x7F);
102 - $pos = ($type >> 8);
103 -
104 - /*
105 - * Re-assign category
106 - */
107 - // Medial Ra
108 - if ($u == 0x1A55 || $u == 0xAA34) { $cat = self::OT_MR; }
109 -
110 - /*
111 - * Re-assign position.
112 - */
113 - if ($cat == self::OT_M) { // definitely "OT_M" in HarfBuzz - although this does not seem to have been defined ? should be OT_MR
114 - switch ($pos) {
115 - case self::POS_PRE_C: $cat = self::OT_VPre; break;
116 - case self::POS_ABOVE_C: $cat = self::OT_VAbv; break;
117 - case self::POS_BELOW_C: $cat = self::OT_VBlw; break;
118 - case self::POS_POST_C: $cat = self::OT_VPst; break;
119 - }
120 - }
121 -
122 - $info['sea_category'] = $cat;
123 - $info['sea_position'] = $pos;
124 -}
125 -
126 -// syllable_type
127 -const CONSONANT_SYLLABLE = 0;
128 -const BROKEN_CLUSTER = 1;
129 -const NON_SEA_CLUSTER = 2;
130 -
131 -
132 -
133 -public static function set_syllables(&$o, $s, &$broken_syllables) {
134 - $ptr = 0;
135 - $syllable_serial = 1;
136 - $broken_syllables = false;
137 - while($ptr < strlen($s)) {
138 - $match = '';
139 - $syllable_length = 1;
140 - $syllable_type = self::NON_SEA_CLUSTER ;
141 -
142 - // CONSONANT_SYLLABLE Consonant syllable
143 - if (preg_match('/^(C|V|G)(p|a|b|t|HC|M|R|T|A)*/', substr($s,$ptr), $ma)) {
144 - $syllable_length = strlen($ma[0]);
145 - $syllable_type = self::CONSONANT_SYLLABLE ;
146 - }
147 - // BROKEN_CLUSTER syllable
148 - else if (preg_match('/^(p|a|b|t|HC|M|R|T|A)+/', substr($s,$ptr), $ma)) {
149 - $syllable_length = strlen($ma[0]);
150 - $syllable_type = self::BROKEN_CLUSTER ;
151 - $broken_syllables = true;
152 - }
153 -
154 - for ($i = $ptr; $i < $ptr+$syllable_length; $i++) { $o[$i]['syllable'] = ($syllable_serial << 4) | $syllable_type; }
155 - $ptr += $syllable_length ;
156 - $syllable_serial++;
157 - if ($syllable_serial == 16) $syllable_serial = 1;
158 - }
159 -}
160 -
161 -public static function initial_reordering(&$info, $GSUBdata, $broken_syllables, $scriptblock, $dottedcircle) {
162 -
163 - if ($broken_syllables && $dottedcircle) { self::insert_dotted_circles ($info, $dottedcircle); }
164 -
165 - $count = count($info);
166 - if (!$count) return;
167 - $last = 0;
168 - $last_syllable = $info[0]['syllable'];
169 - for ($i = 1; $i < $count; $i++) {
170 - if ($last_syllable != $info[$i]['syllable']) {
171 - self::initial_reordering_syllable ($info, $GSUBdata, $scriptblock, $last, $i);
172 - $last = $i;
173 - $last_syllable = $info[$last]['syllable'];
174 - }
175 - }
176 - self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
177 -}
178 -
179 -public static function insert_dotted_circles(&$info, $dottedcircle) {
180 - $idx = 0;
181 - $last_syllable = 0;
182 - while ($idx < count($info)) {
183 - $syllable = $info[$idx]['syllable'];
184 - $syllable_type = ($syllable & 0x0F);
185 - if ($last_syllable != $syllable && $syllable_type == self::BROKEN_CLUSTER) {
186 - $last_syllable = $syllable;
187 - $dottedcircle[0]['syllable'] = $info[$idx]['syllable'];
188 - array_splice($info, $idx, 0, $dottedcircle);
189 - }
190 - else
191 - $idx++;
192 - }
193 -}
194 -
195 -
196 -
197 -
198 -public static function initial_reordering_syllable (&$info, $GSUBdata, $scriptblock, $start, $end) {
199 - /* broken_cluster: We already inserted dotted-circles, so just call the standalone_cluster. */
200 -
201 - $syllable_type = ($info[$start]['syllable'] & 0x0F);
202 - if ($syllable_type==self::NON_SEA_CLUSTER ) { return; }
203 - if ($syllable_type==self::BROKEN_CLUSTER) {
204 - /* For dotted-circle, this is what Uniscribe does:
205 - * If dotted-circle is the last glyph, it just does nothing. */
206 - if ($info[$end - 1]['sea_category'] == self::OT_GB) {
207 - return;
208 - }
209 - }
210 -
211 - $base = $start;
212 - $i = $start;
213 - for (; $i < $base; $i++)
214 - $info[$i]['sea_position'] = self::POS_PRE_C;
215 - if ($i < $end) {
216 - $info[$i]['sea_position'] = self::POS_BASE_C;
217 - $i++;
218 - }
219 - for (; $i < $end; $i++) {
220 - if ($info[$i]['sea_category'] == self::OT_MR) { /* Pre-base reordering */
221 - $info[$i]['sea_position'] = self::POS_PRE_C;
222 - continue;
223 - }
224 - if ($info[$i]['sea_category'] == self::OT_VPre) { /* Left matra */
225 - $info[$i]['sea_position'] = self::POS_PRE_M;
226 - continue;
227 - }
228 - $info[$i]['sea_position'] = self::POS_AFTER_MAIN;
229 - }
230 -
231 - /* Sit tight, rock 'n roll! */
232 - self::bubble_sort ($info, $start, $end - $start);
233 -
234 -}
235 -
236 -public static function final_reordering (&$info, $GSUBdata, $scriptblock) {
237 - $count = count($info);
238 - if (!$count) return;
239 - $last = 0;
240 - $last_syllable = $info[0]['syllable'];
241 - for ($i = 1; $i < $count; $i++) {
242 - if ($last_syllable != $info[$i]['syllable']) {
243 - self::final_reordering_syllable ($info, $GSUBdata, $scriptblock, $last, $i);
244 - $last = $i;
245 - $last_syllable = $info[$last]['syllable'];
246 - }
247 - }
248 - self::final_reordering_syllable ($info, $GSUBdata, $scriptblock, $last, $count);
249 -
250 -}
251 -
252 -public static function final_reordering_syllable (&$info, $GSUBdata, $scriptblock, $start, $end) {
253 - /*
254 - * Nothing to do here at present!
255 - */
256 -
257 -}
258 -
259 -
260 -
261 -
262 -public static $sea_table = array(
263 -
264 - /* New Tai Lue (1980..19DF) */
265 -
266 - /* 1980 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
267 - /* 1988 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
268 - /* 1990 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
269 - /* 1998 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
270 - /* 19A0 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
271 - /* 19A8 */ 3841, 3841, 3841, 3841, 3840, 3840, 3840, 3840,
272 - /* 19B0 */ 2823, 2823, 2823, 2823, 2823, 775, 775, 775,
273 - /* 19B8 */ 2823, 2823, 775, 2823, 2823, 2823, 2823, 2823,
274 - /* 19C0 */ 2823, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
275 - /* 19C8 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
276 - /* 19D0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
277 - /* 19D8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
278 -
279 - /* Tai Tham (1A20..1AAF) */
280 -
281 - /* 1A20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
282 - /* 1A28 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
283 - /* 1A30 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
284 - /* 1A38 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
285 - /* 1A40 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
286 - /* 1A48 */ 3841, 3841, 3841, 3841, 3841, 3842, 3842, 3842,
287 - /* 1A50 */3842, 3842, 3842, 3841, 3841, 3857, 3857, 3857,
288 - /* 1A58 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3840,
289 - /* 1A60 */ 3844, 2823, 1543, 2823, 2823, 1543, 1543, 1543,
290 - /* 1A68 */ 1543, 2055, 2055, 1543, 2055, 2823, 775, 775,
291 - /* 1A70 */ 775, 775, 775, 1543, 1543, 3843, 3843, 3843,
292 - /* 1A78 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
293 - /* 1A80 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
294 - /* 1A88 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
295 - /* 1A90 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
296 - /* 1A98 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
297 - /* 1AA0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
298 - /* 1AA8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
299 -
300 - /* Cham (AA00..AA5F) */
301 -
302 - /* AA00 */ 3842, 3842, 3842, 3842, 3842, 3842, 3841, 3841,
303 - /* AA08 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
304 - /* AA10 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
305 - /* AA18 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
306 - /* AA20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
307 - /* AA28 */ 3841, 1543, 1543, 1543, 1543, 2055, 1543, 775,
308 - /* AA30 */ 775, 1543, 2055, 3857, 3857, 3857, 3857, 3840,
309 - /* AA38 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
310 - /* AA40 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
311 - /* AA48 */ 3857, 3857, 3857, 3857, 3857, 3857, 3840, 3840,
312 - /* AA50 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
313 - /* AA58 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
314 -
315 -);
316 -
317 -
318 -
319 -public static function sea_get_categories ($u) {
320 - if (0x1980 <= $u && $u <= 0x19DF) return self::$sea_table[$u - 0x1980]; // offset 0 for New Tai Lue
321 - if (0x1A20 <= $u && $u <= 0x1AAF) return self::$sea_table[$u - 0x1A20 + 96]; // offset for Tai Tham
322 - if (0xAA00 <= $u && $u <= 0xAA5F) return self::$sea_table[$u - 0xAA00 + 96 + 144]; // Cham
323 - if ($u == 0x00A0) return 3851; // (ISC_CP | (IMC_x << 8))
324 - if ($u == 0x25CC) return 3851; // (ISC_CP | (IMC_x << 8))
325 - return 3840; // (ISC_x | (IMC_x << 8))
326 -}
327 -
328 -
329 -public static function bubble_sort(&$arr, $start, $len) {
330 - if ($len<2) { return;}
331 - $k = $start+$len-2;
332 - while ($k >= $start) {
333 - for ($j=$start; $j<=$k; $j++) {
334 - if ($arr[$j]['sea_position'] > $arr[$j + 1]['sea_position']) {
335 - $t = $arr[$j];
336 - $arr[$j] = $arr[$j + 1];
337 - $arr[$j + 1] = $t;
338 - }
339 - }
340 - $k--;
341 - }
342 -}
343 -
344 -
345 -
346 -
347 -} // end Class
348 -
349 -?>
1 +<?php
2 +
3 +class SEA
4 +{
5 + // South East Asian shaper
6 + // sea_category
7 + const OT_X = 0;
8 +
9 + const OT_C = 1;
10 +
11 + const OT_IV = 2; # Independent Vowel
12 +
13 + const OT_T = 3; # Tone Marks
14 +
15 + const OT_H = 4; # Halant
16 +
17 + const OT_A = 10; # Anusvara
18 +
19 + const OT_GB = 12; # Generic Base (OT_DOTTEDCIRCLE in Indic)
20 +
21 + const OT_CM = 17; # Consonant Medial
22 +
23 + const OT_MR = 22; # Medial Ra
24 +
25 + const OT_VAbv = 26;
26 +
27 + const OT_VBlw = 27;
28 +
29 + const OT_VPre = 28;
30 +
31 + const OT_VPst = 29;
32 +
33 + // ? From Indic categories
34 + const OT_ZWNJ = 5;
35 +
36 + const OT_ZWJ = 6;
37 +
38 + const OT_M = 7;
39 +
40 + const OT_SM = 8;
41 +
42 + const OT_VD = 9;
43 +
44 + const OT_NBSP = 11;
45 +
46 + const OT_RS = 13;
47 +
48 + const OT_Coeng = 14;
49 +
50 + const OT_Repha = 15;
51 +
52 + const OT_Ra = 16;
53 +
54 + // Based on sea_category used to make string to find syllables
55 + // OT_ to string character (using e.g. OT_C from INDIC) hb-ot-shape-complex-sea-private.hh
56 + public static $sea_category_char = array(
57 + 'x',
58 + 'C',
59 + 'V',
60 + 'T',
61 + 'H',
62 + 'x',
63 + 'x',
64 + 'x',
65 + 'x',
66 + 'x',
67 + 'A',
68 + 'x',
69 + 'G',
70 + 'x',
71 + 'x',
72 + 'x',
73 + 'x',
74 + 'M',
75 + 'x',
76 + 'x',
77 + 'x',
78 + 'x',
79 + 'R',
80 + 'x',
81 + 'x',
82 + 'x',
83 + 'a',
84 + 'b',
85 + 'p',
86 + 't',
87 + );
88 +
89 + /* Visual positions in a syllable from left to right. */
90 + // sea_position
91 + const POS_START = 0;
92 +
93 + const POS_RA_TO_BECOME_REPH = 1;
94 +
95 + const POS_PRE_M = 2;
96 +
97 + const POS_PRE_C = 3;
98 +
99 + const POS_BASE_C = 4;
100 +
101 + const POS_AFTER_MAIN = 5;
102 +
103 + const POS_ABOVE_C = 6;
104 +
105 + const POS_BEFORE_SUB = 7;
106 +
107 + const POS_BELOW_C = 8;
108 +
109 + const POS_AFTER_SUB = 9;
110 +
111 + const POS_BEFORE_POST = 10;
112 +
113 + const POS_POST_C = 11;
114 +
115 + const POS_AFTER_POST = 12;
116 +
117 + const POS_FINAL_C = 13;
118 +
119 + const POS_SMVD = 14;
120 +
121 + const POS_END = 15;
122 +
123 + public static function set_sea_properties(&$info, $scriptblock)
124 + {
125 + $u = $info['uni'];
126 + $type = self::sea_get_categories($u);
127 + $cat = ($type & 0x7F);
128 + $pos = ($type >> 8);
129 +
130 + /*
131 + * Re-assign category
132 + */
133 + // Medial Ra
134 + if ($u == 0x1A55 || $u == 0xAA34) {
135 + $cat = self::OT_MR;
136 + }
137 +
138 + /*
139 + * Re-assign position.
140 + */
141 + if ($cat == self::OT_M) { // definitely "OT_M" in HarfBuzz - although this does not seem to have been defined ? should be OT_MR
142 + switch ($pos) {
143 + case self::POS_PRE_C: $cat = self::OT_VPre;
144 + break;
145 + case self::POS_ABOVE_C: $cat = self::OT_VAbv;
146 + break;
147 + case self::POS_BELOW_C: $cat = self::OT_VBlw;
148 + break;
149 + case self::POS_POST_C: $cat = self::OT_VPst;
150 + break;
151 + }
152 + }
153 +
154 + $info['sea_category'] = $cat;
155 + $info['sea_position'] = $pos;
156 + }
157 +
158 + // syllable_type
159 + const CONSONANT_SYLLABLE = 0;
160 +
161 + const BROKEN_CLUSTER = 1;
162 +
163 + const NON_SEA_CLUSTER = 2;
164 +
165 + public static function set_syllables(&$o, $s, &$broken_syllables)
166 + {
167 + $ptr = 0;
168 + $syllable_serial = 1;
169 + $broken_syllables = false;
170 + while ($ptr < strlen($s)) {
171 + $match = '';
172 + $syllable_length = 1;
173 + $syllable_type = self::NON_SEA_CLUSTER;
174 +
175 + // CONSONANT_SYLLABLE Consonant syllable
176 + if (preg_match('/^(C|V|G)(p|a|b|t|HC|M|R|T|A)*/', substr($s, $ptr), $ma)) {
177 + $syllable_length = strlen($ma[0]);
178 + $syllable_type = self::CONSONANT_SYLLABLE;
179 + }
180 + // BROKEN_CLUSTER syllable
181 + else if (preg_match('/^(p|a|b|t|HC|M|R|T|A)+/', substr($s, $ptr), $ma)) {
182 + $syllable_length = strlen($ma[0]);
183 + $syllable_type = self::BROKEN_CLUSTER;
184 + $broken_syllables = true;
185 + }
186 +
187 + for ($i = $ptr; $i < $ptr + $syllable_length; $i++) {
188 + $o[$i]['syllable'] = ($syllable_serial << 4) | $syllable_type;
189 + }
190 + $ptr += $syllable_length;
191 + $syllable_serial++;
192 + if ($syllable_serial == 16)
193 + $syllable_serial = 1;
194 + }
195 + }
196 +
197 + public static function initial_reordering(&$info, $GSUBdata, $broken_syllables, $scriptblock, $dottedcircle)
198 + {
199 +
200 + if ($broken_syllables && $dottedcircle) {
201 + self::insert_dotted_circles($info, $dottedcircle);
202 + }
203 +
204 + $count = count($info);
205 + if (!$count)
206 + return;
207 + $last = 0;
208 + $last_syllable = $info[0]['syllable'];
209 + for ($i = 1; $i < $count; $i++) {
210 + if ($last_syllable != $info[$i]['syllable']) {
211 + self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $i);
212 + $last = $i;
213 + $last_syllable = $info[$last]['syllable'];
214 + }
215 + }
216 + self::initial_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
217 + }
218 +
219 + public static function insert_dotted_circles(&$info, $dottedcircle)
220 + {
221 + $idx = 0;
222 + $last_syllable = 0;
223 + while ($idx < count($info)) {
224 + $syllable = $info[$idx]['syllable'];
225 + $syllable_type = ($syllable & 0x0F);
226 + if ($last_syllable != $syllable && $syllable_type == self::BROKEN_CLUSTER) {
227 + $last_syllable = $syllable;
228 + $dottedcircle[0]['syllable'] = $info[$idx]['syllable'];
229 + array_splice($info, $idx, 0, $dottedcircle);
230 + } else
231 + $idx++;
232 + }
233 + }
234 +
235 + public static function initial_reordering_syllable(&$info, $GSUBdata, $scriptblock, $start, $end)
236 + {
237 + /* broken_cluster: We already inserted dotted-circles, so just call the standalone_cluster. */
238 +
239 + $syllable_type = ($info[$start]['syllable'] & 0x0F);
240 + if ($syllable_type == self::NON_SEA_CLUSTER) {
241 + return;
242 + }
243 + if ($syllable_type == self::BROKEN_CLUSTER) {
244 + /* For dotted-circle, this is what Uniscribe does:
245 + * If dotted-circle is the last glyph, it just does nothing. */
246 + if ($info[$end - 1]['sea_category'] == self::OT_GB) {
247 + return;
248 + }
249 + }
250 +
251 + $base = $start;
252 + $i = $start;
253 + for (; $i < $base; $i++)
254 + $info[$i]['sea_position'] = self::POS_PRE_C;
255 + if ($i < $end) {
256 + $info[$i]['sea_position'] = self::POS_BASE_C;
257 + $i++;
258 + }
259 + for (; $i < $end; $i++) {
260 + if (isset($info[$i]['sea_category']) && $info[$i]['sea_category'] == self::OT_MR) { /* Pre-base reordering */
261 + $info[$i]['sea_position'] = self::POS_PRE_C;
262 + continue;
263 + }
264 + if (isset($info[$i]['sea_category']) && $info[$i]['sea_category'] == self::OT_VPre) { /* Left matra */
265 + $info[$i]['sea_position'] = self::POS_PRE_M;
266 + continue;
267 + }
268 + $info[$i]['sea_position'] = self::POS_AFTER_MAIN;
269 + }
270 +
271 + /* Sit tight, rock 'n roll! */
272 + self::bubble_sort($info, $start, $end - $start);
273 + }
274 +
275 + public static function final_reordering(&$info, $GSUBdata, $scriptblock)
276 + {
277 + $count = count($info);
278 + if (!$count)
279 + return;
280 + $last = 0;
281 + $last_syllable = $info[0]['syllable'];
282 + for ($i = 1; $i < $count; $i++) {
283 + if ($last_syllable != $info[$i]['syllable']) {
284 + self::final_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $i);
285 + $last = $i;
286 + $last_syllable = $info[$last]['syllable'];
287 + }
288 + }
289 + self::final_reordering_syllable($info, $GSUBdata, $scriptblock, $last, $count);
290 + }
291 +
292 + public static function final_reordering_syllable(&$info, $GSUBdata, $scriptblock, $start, $end)
293 + {
294 + /*
295 + * Nothing to do here at present!
296 + */
297 + }
298 +
299 + public static $sea_table = array(
300 + /* New Tai Lue (1980..19DF) */
301 +
302 + /* 1980 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
303 + /* 1988 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
304 + /* 1990 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
305 + /* 1998 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
306 + /* 19A0 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
307 + /* 19A8 */ 3841, 3841, 3841, 3841, 3840, 3840, 3840, 3840,
308 + /* 19B0 */ 2823, 2823, 2823, 2823, 2823, 775, 775, 775,
309 + /* 19B8 */ 2823, 2823, 775, 2823, 2823, 2823, 2823, 2823,
310 + /* 19C0 */ 2823, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
311 + /* 19C8 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
312 + /* 19D0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
313 + /* 19D8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
314 + /* Tai Tham (1A20..1AAF) */
315 +
316 + /* 1A20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
317 + /* 1A28 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
318 + /* 1A30 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
319 + /* 1A38 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
320 + /* 1A40 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
321 + /* 1A48 */ 3841, 3841, 3841, 3841, 3841, 3842, 3842, 3842,
322 + /* 1A50 */ 3842, 3842, 3842, 3841, 3841, 3857, 3857, 3857,
323 + /* 1A58 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3840,
324 + /* 1A60 */ 3844, 2823, 1543, 2823, 2823, 1543, 1543, 1543,
325 + /* 1A68 */ 1543, 2055, 2055, 1543, 2055, 2823, 775, 775,
326 + /* 1A70 */ 775, 775, 775, 1543, 1543, 3843, 3843, 3843,
327 + /* 1A78 */ 3843, 3843, 3840, 3840, 3840, 3840, 3840, 3840,
328 + /* 1A80 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
329 + /* 1A88 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
330 + /* 1A90 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
331 + /* 1A98 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
332 + /* 1AA0 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
333 + /* 1AA8 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
334 + /* Cham (AA00..AA5F) */
335 +
336 + /* AA00 */ 3842, 3842, 3842, 3842, 3842, 3842, 3841, 3841,
337 + /* AA08 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
338 + /* AA10 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
339 + /* AA18 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
340 + /* AA20 */ 3841, 3841, 3841, 3841, 3841, 3841, 3841, 3841,
341 + /* AA28 */ 3841, 1543, 1543, 1543, 1543, 2055, 1543, 775,
342 + /* AA30 */ 775, 1543, 2055, 3857, 3857, 3857, 3857, 3840,
343 + /* AA38 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
344 + /* AA40 */ 3857, 3857, 3857, 3857, 3857, 3857, 3857, 3857,
345 + /* AA48 */ 3857, 3857, 3857, 3857, 3857, 3857, 3840, 3840,
346 + /* AA50 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
347 + /* AA58 */ 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840,
348 + );
349 +
350 + public static function sea_get_categories($u)
351 + {
352 + if (0x1980 <= $u && $u <= 0x19DF)
353 + return self::$sea_table[$u - 0x1980]; // offset 0 for New Tai Lue
354 + if (0x1A20 <= $u && $u <= 0x1AAF)
355 + return self::$sea_table[$u - 0x1A20 + 96]; // offset for Tai Tham
356 + if (0xAA00 <= $u && $u <= 0xAA5F)
357 + return self::$sea_table[$u - 0xAA00 + 96 + 144]; // Cham
358 + if ($u == 0x00A0)
359 + return 3851; // (ISC_CP | (IMC_x << 8))
360 + if ($u == 0x25CC)
361 + return 3851; // (ISC_CP | (IMC_x << 8))
362 + return 3840; // (ISC_x | (IMC_x << 8))
363 + }
364 +
365 + public static function bubble_sort(&$arr, $start, $len)
366 + {
367 + if ($len < 2) {
368 + return;
369 + }
370 + $k = $start + $len - 2;
371 + while ($k >= $start) {
372 + for ($j = $start; $j <= $k; $j++) {
373 + if ($arr[$j]['sea_position'] > $arr[$j + 1]['sea_position']) {
374 + $t = $arr[$j];
375 + $arr[$j] = $arr[$j + 1];
376 + $arr[$j + 1] = $t;
377 + }
378 + }
379 + $k--;
380 + }
381 + }
382 +
383 +}