|
1 /* GRAPHITE2 LICENSING |
|
2 |
|
3 Copyright 2011, SIL International |
|
4 All rights reserved. |
|
5 |
|
6 This library is free software; you can redistribute it and/or modify |
|
7 it under the terms of the GNU Lesser General Public License as published |
|
8 by the Free Software Foundation; either version 2.1 of License, or |
|
9 (at your option) any later version. |
|
10 |
|
11 This program is distributed in the hope that it will be useful, |
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 Lesser General Public License for more details. |
|
15 |
|
16 You should also have received a copy of the GNU Lesser General Public |
|
17 License along with this library in the file named "LICENSE". |
|
18 If not, write to the Free Software Foundation, 51 Franklin Street, |
|
19 suite 500, Boston, MA 02110-1335, USA or visit their web page on the |
|
20 internet at http://www.fsf.org/licenses/lgpl.html. |
|
21 |
|
22 Alternatively, the contents of this file may be used under the terms of the |
|
23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public |
|
24 License, as published by the Free Software Foundation, either version 2 |
|
25 of the License or (at your option) any later version. |
|
26 */ |
|
27 #include "inc/Main.h" |
|
28 #include "inc/Slot.h" |
|
29 #include "inc/Segment.h" |
|
30 #include "inc/Bidi.h" |
|
31 |
|
32 using namespace graphite2; |
|
33 |
|
34 enum DirCode { // Hungarian: dirc |
|
35 Unk = -1, |
|
36 N = 0, // other neutrals (default) - ON |
|
37 L = 1, // left-to-right, strong - L |
|
38 R = 2, // right-to-left, strong - R |
|
39 AL = 3, // Arabic letter, right-to-left, strong, AR |
|
40 EN = 4, // European number, left-to-right, weak - EN |
|
41 EUS = 5, // European separator, left-to-right, weak - ES |
|
42 ET = 6, // European number terminator, left-to-right, weak - ET |
|
43 AN = 7, // Arabic number, left-to-right, weak - AN |
|
44 CUS = 8, // Common number separator, left-to-right, weak - CS |
|
45 WS = 9, // white space, neutral - WS |
|
46 BN = 10, // boundary neutral - BN |
|
47 |
|
48 LRO = 11, // LTR override |
|
49 RLO = 12, // RTL override |
|
50 LRE = 13, // LTR embedding |
|
51 RLE = 14, // RTL embedding |
|
52 PDF = 15, // pop directional format |
|
53 NSM = 16, // non-space mark |
|
54 LRI = 17, // LRI isolate |
|
55 RLI = 18, // RLI isolate |
|
56 FSI = 19, // FSI isolate |
|
57 PDI = 20, // pop isolate |
|
58 OPP = 21, // opening paired parenthesis |
|
59 CPP = 22, // closing paired parenthesis |
|
60 |
|
61 ON = N |
|
62 }; |
|
63 |
|
64 enum DirMask { |
|
65 WSflag = (1 << 7), // keep track of WS for eos handling |
|
66 WSMask = ~(1 << 7) |
|
67 }; |
|
68 |
|
69 inline uint8 BaseClass(Slot *s) { return s->getBidiClass() & WSMask; } |
|
70 |
|
71 unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 }; |
|
72 // Algorithms based on Unicode reference standard code. Thanks Asmus Freitag. |
|
73 |
|
74 void resolveWeak(Slot *start, int sos, int eos); |
|
75 void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos); |
|
76 void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack); |
|
77 |
|
78 inline int calc_base_level(Slot *s) |
|
79 { |
|
80 int count = 0; |
|
81 for ( ; s; s = s->next()) |
|
82 { |
|
83 int cls = s->getBidiClass(); |
|
84 if (count) |
|
85 { |
|
86 switch(cls) |
|
87 { |
|
88 case LRI : |
|
89 case RLI : |
|
90 case FSI : |
|
91 ++count; |
|
92 break; |
|
93 case PDI : |
|
94 --count; |
|
95 } |
|
96 } |
|
97 else |
|
98 { |
|
99 switch(cls) |
|
100 { |
|
101 case L : |
|
102 return 0; |
|
103 case R : |
|
104 case AL : |
|
105 return 1; |
|
106 case LRI : |
|
107 case RLI : |
|
108 case FSI : |
|
109 ++count; |
|
110 } |
|
111 } |
|
112 } |
|
113 return 0; |
|
114 } |
|
115 |
|
116 // inline or not? |
|
117 void do_resolves(Slot *start, int level, int sos, int eos, int &bmask, Segment *seg, uint8 aMirror, BracketPairStack &stack) |
|
118 { |
|
119 if (bmask & 0x1F1178) |
|
120 resolveWeak(start, sos, eos); |
|
121 if (bmask & 0x200000) |
|
122 processParens(start, seg, aMirror, level, stack); |
|
123 if (bmask & 0x7E0361) |
|
124 resolveNeutrals(start, level, sos, eos); |
|
125 bmask = 0; |
|
126 } |
|
127 |
|
128 enum maxs |
|
129 { |
|
130 MAX_LEVEL = 125, |
|
131 }; |
|
132 |
|
133 // returns where we are up to in processing |
|
134 Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &bstack) |
|
135 { |
|
136 int bmask = 0; |
|
137 Slot *s = start; |
|
138 Slot *slast = start; |
|
139 Slot *scurr = 0; |
|
140 Slot *stemp; |
|
141 int lnextLevel = nextLevel; |
|
142 int newLevel; |
|
143 int empty = 1; |
|
144 for ( ; s; s = s ? s->next() : s) |
|
145 { |
|
146 int cls = s->getBidiClass(); |
|
147 bmask |= (1 << cls); |
|
148 s->setBidiLevel(level); |
|
149 // we keep s->prev() pointing backwards for PDI repeating |
|
150 |
|
151 switch (cls) |
|
152 { |
|
153 case BN : |
|
154 if (slast == s) slast = s->next(); // ignore if at front of text |
|
155 continue; |
|
156 case LRE : |
|
157 case LRO : |
|
158 case RLE : |
|
159 case RLO : |
|
160 switch (cls) |
|
161 { |
|
162 case LRE : |
|
163 case LRO : |
|
164 newLevel = level + (level & 1 ? 1 : 2); |
|
165 break; |
|
166 case RLE : |
|
167 case RLO : |
|
168 newLevel = level + (level & 1 ? 2 : 1); |
|
169 break; |
|
170 } |
|
171 s->setBidiClass(BN); |
|
172 if (isolerr || newLevel > MAX_LEVEL || embederr) |
|
173 { |
|
174 if (!isolerr) ++embederr; |
|
175 break; |
|
176 } |
|
177 stemp = scurr; |
|
178 if (scurr) |
|
179 scurr->prev(0); // don't include control in string |
|
180 lnextLevel = newLevel; |
|
181 scurr = s; |
|
182 s->setBidiLevel(newLevel); // to make it vanish |
|
183 // recurse for the new subsequence. A sequence only contains text at the same level |
|
184 s = process_bidi(s->next(), newLevel, level, lnextLevel, cls < LRE, 0, cisol, isolerr, embederr, 0, seg, aMirror, bstack); |
|
185 // s points at PDF or end of sequence |
|
186 // try to keep extending the run and not process it until we have to |
|
187 if (lnextLevel != level || !s) // if the subsequence really had something in it, or we are at the end of the run |
|
188 { |
|
189 if (slast != scurr) // process the run now, don't try to extend it |
|
190 { |
|
191 // process text preceeding embedding |
|
192 do_resolves(slast, level, (prelevel > level ? prelevel : level) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack); |
|
193 empty = 0; |
|
194 nextLevel = level; |
|
195 } |
|
196 else if (lnextLevel != level) // the subsequence had something |
|
197 { |
|
198 empty = 0; // so we aren't empty either |
|
199 nextLevel = lnextLevel; // but since we really are empty, pass back our level from the subsequence |
|
200 } |
|
201 if (s) // if still more to process |
|
202 { |
|
203 prelevel = lnextLevel; // future text starts out with sos of the higher subsequence |
|
204 lnextLevel = level; // and eos is our level |
|
205 } |
|
206 slast = s ? s->next() : s; |
|
207 } |
|
208 else if (stemp) |
|
209 stemp->prev(s); |
|
210 break; |
|
211 |
|
212 case PDF : |
|
213 s->setBidiClass(BN); |
|
214 s->prev(0); // unstitch us since we skip final stitching code when we return |
|
215 if (isol || isolerr || init) // boundary error conditions |
|
216 break; |
|
217 if (embederr) |
|
218 { |
|
219 --embederr; |
|
220 break; |
|
221 } |
|
222 if (slast != s) |
|
223 { |
|
224 scurr->prev(0); // if slast, then scurr. Terminate before here |
|
225 do_resolves(slast, level, level & 1, level & 1, bmask, seg, aMirror, bstack); |
|
226 empty = 0; |
|
227 } |
|
228 if (empty) |
|
229 { |
|
230 nextLevel = prelevel; // no contents? set our level to that of parent |
|
231 s->setBidiLevel(prelevel); |
|
232 } |
|
233 return s; |
|
234 |
|
235 case FSI : |
|
236 case LRI : |
|
237 case RLI : |
|
238 switch (cls) |
|
239 { |
|
240 case FSI : |
|
241 if (calc_base_level(s->next())) |
|
242 newLevel = level + (level & 1 ? 2 : 1); |
|
243 else |
|
244 newLevel = level + (level & 1 ? 1 : 2); |
|
245 break; |
|
246 case LRI : |
|
247 newLevel = level + (level & 1 ? 1 : 2); |
|
248 break; |
|
249 case RLI : |
|
250 newLevel = level + (level & 1 ? 2 : 1); |
|
251 break; |
|
252 } |
|
253 if (newLevel > MAX_LEVEL || isolerr) |
|
254 { |
|
255 ++isolerr; |
|
256 s->setBidiClass(ON | WSflag); |
|
257 break; |
|
258 } |
|
259 ++cisol; |
|
260 if (scurr) scurr->prev(s); |
|
261 scurr = s; // include FSI |
|
262 lnextLevel = newLevel; |
|
263 // recurse for the new sub sequence |
|
264 s = process_bidi(s->next(), newLevel, newLevel, lnextLevel, 0, 1, cisol, isolerr, embederr, 0, seg, aMirror, bstack); |
|
265 // s points at PDI |
|
266 if (s) |
|
267 { |
|
268 bmask |= 1 << BaseClass(s); // include the PDI in the mask |
|
269 s->setBidiLevel(level); // reset its level to our level |
|
270 } |
|
271 lnextLevel = level; |
|
272 break; |
|
273 |
|
274 case PDI : |
|
275 if (isolerr) |
|
276 { |
|
277 --isolerr; |
|
278 s->setBidiClass(ON | WSflag); |
|
279 break; |
|
280 } |
|
281 if (init || !cisol) |
|
282 { |
|
283 s->setBidiClass(ON | WSflag); |
|
284 break; |
|
285 } |
|
286 embederr = 0; |
|
287 if (!isol) // we are in an embedded subsequence, we have to return through all those |
|
288 { |
|
289 if (empty) // if empty, reset the level to tell embedded parent |
|
290 nextLevel = prelevel; |
|
291 return s->prev(); // keep working up the stack pointing at this PDI until we get to an isolate entry |
|
292 } |
|
293 else // we are terminating an isolate sequence |
|
294 { |
|
295 if (slast != s) // process any remaining content in this subseqence |
|
296 { |
|
297 scurr->prev(0); |
|
298 do_resolves(slast, level, prelevel & 1, level & 1, bmask, seg, aMirror, bstack); |
|
299 } |
|
300 --cisol; // pop the isol sequence from the stack |
|
301 return s; |
|
302 } |
|
303 |
|
304 default : |
|
305 if (dirover) |
|
306 s->setBidiClass((level & 1 ? R : L) | (WSflag * (cls == WS))); |
|
307 } |
|
308 if (s) s->prev(0); // unstitch us |
|
309 if (scurr) // stitch in text for processing |
|
310 scurr->prev(s); |
|
311 scurr = s; // add us to text to process |
|
312 } |
|
313 if (slast != s) |
|
314 { |
|
315 do_resolves(slast, level, (level > prelevel ? level : prelevel) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack); |
|
316 empty = 0; |
|
317 } |
|
318 if (empty || isol) |
|
319 nextLevel = prelevel; |
|
320 return s; |
|
321 } |
|
322 |
|
323 // === RESOLVE WEAK TYPES ================================================ |
|
324 |
|
325 enum bidi_state // possible states |
|
326 { |
|
327 xa, // arabic letter |
|
328 xr, // right leter |
|
329 xl, // left letter |
|
330 |
|
331 ao, // arabic lett. foll by ON |
|
332 ro, // right lett. foll by ON |
|
333 lo, // left lett. foll by ON |
|
334 |
|
335 rt, // ET following R |
|
336 lt, // ET following L |
|
337 |
|
338 cn, // EN, AN following AL |
|
339 ra, // arabic number foll R |
|
340 re, // european number foll R |
|
341 la, // arabic number foll L |
|
342 le, // european number foll L |
|
343 |
|
344 ac, // CS following cn |
|
345 rc, // CS following ra |
|
346 rs, // CS,ES following re |
|
347 lc, // CS following la |
|
348 ls, // CS,ES following le |
|
349 |
|
350 ret, // ET following re |
|
351 let, // ET following le |
|
352 } ; |
|
353 |
|
354 const bidi_state stateWeak[][10] = |
|
355 { |
|
356 // N, L, R, AN, EN, AL,NSM, CS, ES, ET, |
|
357 { /*xa*/ ao, xl, xr, cn, cn, xa, xa, ao, ao, ao, /* arabic letter */ }, |
|
358 { /*xr*/ ro, xl, xr, ra, re, xa, xr, ro, ro, rt, /* right letter */ }, |
|
359 { /*xl*/ lo, xl, xr, la, le, xa, xl, lo, lo, lt, /* left letter */ }, |
|
360 |
|
361 { /*ao*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* arabic lett. foll by ON*/ }, |
|
362 { /*ro*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* right lett. foll by ON */ }, |
|
363 { /*lo*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* left lett. foll by ON */ }, |
|
364 |
|
365 { /*rt*/ ro, xl, xr, ra, re, xa, rt, ro, ro, rt, /* ET following R */ }, |
|
366 { /*lt*/ lo, xl, xr, la, le, xa, lt, lo, lo, lt, /* ET following L */ }, |
|
367 |
|
368 { /*cn*/ ao, xl, xr, cn, cn, xa, cn, ac, ao, ao, /* EN, AN following AL */ }, |
|
369 { /*ra*/ ro, xl, xr, ra, re, xa, ra, rc, ro, rt, /* arabic number foll R */ }, |
|
370 { /*re*/ ro, xl, xr, ra, re, xa, re, rs, rs,ret, /* european number foll R */ }, |
|
371 { /*la*/ lo, xl, xr, la, le, xa, la, lc, lo, lt, /* arabic number foll L */ }, |
|
372 { /*le*/ lo, xl, xr, la, le, xa, le, ls, ls,let, /* european number foll L */ }, |
|
373 |
|
374 { /*ac*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* CS following cn */ }, |
|
375 { /*rc*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS following ra */ }, |
|
376 { /*rs*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS,ES following re */ }, |
|
377 { /*lc*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS following la */ }, |
|
378 { /*ls*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS,ES following le */ }, |
|
379 |
|
380 { /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re */ }, |
|
381 { /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le */ }, |
|
382 |
|
383 |
|
384 }; |
|
385 |
|
386 enum bidi_action // possible actions |
|
387 { |
|
388 // primitives |
|
389 IX = 0x100, // increment |
|
390 XX = 0xF, // no-op |
|
391 |
|
392 // actions |
|
393 xxx = (XX << 4) + XX, // no-op |
|
394 xIx = IX + xxx, // increment run |
|
395 xxN = (XX << 4) + ON, // set current to N |
|
396 xxE = (XX << 4) + EN, // set current to EN |
|
397 xxA = (XX << 4) + AN, // set current to AN |
|
398 xxR = (XX << 4) + R, // set current to R |
|
399 xxL = (XX << 4) + L, // set current to L |
|
400 Nxx = (ON << 4) + 0xF, // set run to neutral |
|
401 Axx = (AN << 4) + 0xF, // set run to AN |
|
402 ExE = (EN << 4) + EN, // set run to EN, set current to EN |
|
403 NIx = (ON << 4) + 0xF + IX, // set run to N, increment |
|
404 NxN = (ON << 4) + ON, // set run to N, set current to N |
|
405 NxR = (ON << 4) + R, // set run to N, set current to R |
|
406 NxE = (ON << 4) + EN, // set run to N, set current to EN |
|
407 |
|
408 AxA = (AN << 4) + AN, // set run to AN, set current to AN |
|
409 NxL = (ON << 4) + L, // set run to N, set current to L |
|
410 LxL = (L << 4) + L, // set run to L, set current to L |
|
411 }; |
|
412 |
|
413 |
|
414 const bidi_action actionWeak[][10] = |
|
415 { |
|
416 // N,.. L, R, AN, EN, AL, NSM, CS,..ES, ET, |
|
417 { /*xa*/ xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN, /* arabic letter */ }, |
|
418 { /*xr*/ xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx, /* right leter */ }, |
|
419 { /*xl*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx, /* left letter */ }, |
|
420 |
|
421 { /*ao*/ xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN, /* arabic lett. foll by ON */ }, |
|
422 { /*ro*/ xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx, /* right lett. foll by ON */ }, |
|
423 { /*lo*/ xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx, /* left lett. foll by ON */ }, |
|
424 |
|
425 { /*rt*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx, /* ET following R */ }, |
|
426 { /*lt*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx, /* ET following L */ }, |
|
427 |
|
428 { /*cn*/ xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN, /* EN, AN following AL */ }, |
|
429 { /*ra*/ xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx, /* arabic number foll R */ }, |
|
430 { /*re*/ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE, /* european number foll R */ }, |
|
431 { /*la*/ xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx, /* arabic number foll L */ }, |
|
432 { /*le*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL, /* european number foll L */ }, |
|
433 |
|
434 { /*ac*/ Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN, /* CS following cn */ }, |
|
435 { /*rc*/ Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx, /* CS following ra */ }, |
|
436 { /*rs*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx, /* CS,ES following re */ }, |
|
437 { /*lc*/ Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx, /* CS following la */ }, |
|
438 { /*ls*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx, /* CS,ES following le */ }, |
|
439 |
|
440 { /*ret*/xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE, /* ET following re */ }, |
|
441 { /*let*/xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL, /* ET following le */ }, |
|
442 }; |
|
443 |
|
444 inline uint8 GetDeferredType(bidi_action a) { return (a >> 4) & 0xF; } |
|
445 inline uint8 GetResolvedType(bidi_action a) { return a & 0xF; } |
|
446 inline DirCode EmbeddingDirection(int l) { return l & 1 ? R : L; } |
|
447 |
|
448 // Neutrals |
|
449 enum neutral_action |
|
450 { |
|
451 // action to resolve previous input |
|
452 nL = L, // resolve EN to L |
|
453 En = 3 << 4, // resolve neutrals run to embedding level direction |
|
454 Rn = R << 4, // resolve neutrals run to strong right |
|
455 Ln = L << 4, // resolved neutrals run to strong left |
|
456 In = (1<<8), // increment count of deferred neutrals |
|
457 LnL = (1<<4)+L, // set run and EN to L |
|
458 }; |
|
459 |
|
460 // ->prev() here means ->next() |
|
461 void SetDeferredRunClass(Slot *s, Slot *sRun, int nval) |
|
462 { |
|
463 if (!sRun || s == sRun) return; |
|
464 for (Slot *p = sRun; p != s; p = p->prev()) |
|
465 if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag); |
|
466 else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag)); |
|
467 } |
|
468 |
|
469 void SetThisDeferredRunClass(Slot *s, Slot *sRun, int nval) |
|
470 { |
|
471 if (!sRun) return; |
|
472 for (Slot *p = sRun, *e = s->prev(); p != e; p = p->prev()) |
|
473 if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag); |
|
474 else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag)); |
|
475 } |
|
476 |
|
477 void resolveWeak(Slot *start, int sos, int eos) |
|
478 { |
|
479 int state = (sos & 1) ? xr : xl; |
|
480 int cls; |
|
481 Slot *s = start; |
|
482 Slot *sRun = NULL; |
|
483 Slot *sLast = s; |
|
484 |
|
485 for ( ; s; s = s->prev()) |
|
486 { |
|
487 sLast = s; |
|
488 cls = BaseClass(s); |
|
489 switch (cls) |
|
490 { |
|
491 case BN : |
|
492 if (s == start) start = s->prev(); // skip initial BNs for NSM resolving |
|
493 continue; |
|
494 case LRI : |
|
495 case RLI : |
|
496 case FSI : |
|
497 case PDI : |
|
498 { |
|
499 Slot *snext = s->prev(); |
|
500 if (snext && snext->getBidiClass() == NSM) |
|
501 snext->setBidiClass(ON); |
|
502 s->setBidiClass(ON | WSflag); |
|
503 } |
|
504 break; |
|
505 |
|
506 case NSM : |
|
507 if (s == start) |
|
508 { |
|
509 cls = EmbeddingDirection(sos); |
|
510 s->setBidiClass(cls); |
|
511 } |
|
512 break; |
|
513 } |
|
514 |
|
515 bidi_action action = actionWeak[state][bidi_class_map[cls]]; |
|
516 int clsRun = GetDeferredType(action); |
|
517 if (clsRun != XX) |
|
518 { |
|
519 SetDeferredRunClass(s, sRun, clsRun); |
|
520 sRun = NULL; |
|
521 } |
|
522 int clsNew = GetResolvedType(action); |
|
523 if (clsNew != XX) |
|
524 s->setBidiClass(clsNew); |
|
525 if (!sRun && (IX & action)) |
|
526 sRun = s; |
|
527 state = stateWeak[state][bidi_class_map[cls]]; |
|
528 } |
|
529 |
|
530 cls = EmbeddingDirection(eos); |
|
531 int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]); |
|
532 if (clsRun != XX) |
|
533 SetThisDeferredRunClass(sLast, sRun, clsRun); |
|
534 } |
|
535 |
|
536 void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack) |
|
537 { |
|
538 uint8 mask = 0; |
|
539 int8 lastDir = -1; |
|
540 BracketPair *p; |
|
541 for ( ; s; s = s->prev()) // walk the sequence |
|
542 { |
|
543 uint16 ogid = seg->glyphAttr(s->gid(), aMirror); |
|
544 int cls = BaseClass(s); |
|
545 |
|
546 switch(cls) |
|
547 { |
|
548 case OPP : |
|
549 stack.orin(mask); |
|
550 stack.push(ogid, s, lastDir, lastDir != CPP); |
|
551 mask = 0; |
|
552 lastDir = OPP; |
|
553 break; |
|
554 case CPP : |
|
555 stack.orin(mask); |
|
556 p = stack.scan(s->gid()); |
|
557 if (!p) break; |
|
558 mask = 0; |
|
559 stack.close(p, s); |
|
560 lastDir = CPP; |
|
561 break; |
|
562 case L : |
|
563 lastDir = L; |
|
564 mask |= 1; |
|
565 break; |
|
566 case R : |
|
567 case AL : |
|
568 case AN : |
|
569 case EN : |
|
570 lastDir = R; |
|
571 mask |= 2; |
|
572 } |
|
573 } |
|
574 for (p = stack.start(); p; p =p->next()) // walk the stack |
|
575 { |
|
576 if (p->close() && p->mask()) |
|
577 { |
|
578 int dir = (level & 1) + 1; |
|
579 if (p->mask() & dir) |
|
580 { } |
|
581 else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding |
|
582 { |
|
583 int ldir = p->before(); |
|
584 if ((p->before() == OPP || p->before() == CPP) && p->prev()) |
|
585 { |
|
586 for (BracketPair *q = p->prev(); q; q = q->prev()) |
|
587 { |
|
588 ldir = q->open()->getBidiClass(); |
|
589 if (ldir < 3) break; |
|
590 ldir = q->before(); |
|
591 if (ldir < 3) break; |
|
592 } |
|
593 if (ldir > 2) ldir = 0; |
|
594 } |
|
595 if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L) |
|
596 dir = (~level & 1) + 1; |
|
597 } |
|
598 p->open()->setBidiClass(dir); |
|
599 p->close()->setBidiClass(dir); |
|
600 } |
|
601 } |
|
602 stack.clear(); |
|
603 } |
|
604 |
|
605 int GetDeferredNeutrals(int action, int level) |
|
606 { |
|
607 action = (action >> 4) & 0xF; |
|
608 if (action == (En >> 4)) |
|
609 return EmbeddingDirection(level); |
|
610 else |
|
611 return action; |
|
612 } |
|
613 |
|
614 int GetResolvedNeutrals(int action) |
|
615 { |
|
616 return action & 0xF; |
|
617 } |
|
618 |
|
619 // state values |
|
620 enum neutral_state |
|
621 { |
|
622 // new temporary class |
|
623 r, // R and characters resolved to R |
|
624 l, // L and characters resolved to L |
|
625 rn, // N preceded by right |
|
626 ln, // N preceded by left |
|
627 a, // AN preceded by left (the abbrev 'la' is used up above) |
|
628 na, // N preceeded by a |
|
629 } ; |
|
630 |
|
631 const uint8 neutral_class_map[] = { 0, 1, 2, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
|
632 |
|
633 const int actionNeutrals[][5] = |
|
634 { |
|
635 // cls= N, L, R, AN, EN, state = |
|
636 { In, 0, 0, 0, 0, }, // r right |
|
637 { In, 0, 0, 0, L, }, // l left |
|
638 |
|
639 { In, En, Rn, Rn, Rn, }, // rn N preceded by right |
|
640 { In, Ln, En, En, LnL, }, // ln N preceded by left |
|
641 |
|
642 { In, 0, 0, 0, L, }, // a AN preceded by left |
|
643 { In, En, Rn, Rn, En, }, // na N preceded by a |
|
644 } ; |
|
645 |
|
646 const int stateNeutrals[][5] = |
|
647 { |
|
648 // cls= N, L, R, AN, EN state = |
|
649 { rn, l, r, r, r, }, // r right |
|
650 { ln, l, r, a, l, }, // l left |
|
651 |
|
652 { rn, l, r, r, r, }, // rn N preceded by right |
|
653 { ln, l, r, a, l, }, // ln N preceded by left |
|
654 |
|
655 { na, l, r, a, l, }, // a AN preceded by left |
|
656 { na, l, r, a, l, }, // na N preceded by la |
|
657 } ; |
|
658 |
|
659 void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos) |
|
660 { |
|
661 int state = (sos & 1) ? r : l; |
|
662 int cls; |
|
663 Slot *sRun = NULL; |
|
664 Slot *sLast = s; |
|
665 int level = baseLevel; |
|
666 |
|
667 for ( ; s; s = s->prev()) |
|
668 { |
|
669 sLast = s; |
|
670 cls = BaseClass(s); |
|
671 switch (cls) |
|
672 { |
|
673 case BN : |
|
674 continue; |
|
675 case LRI : |
|
676 case RLI : |
|
677 case FSI : |
|
678 s->setBidiClass(BN | WSflag); |
|
679 continue; |
|
680 |
|
681 default : |
|
682 int action = actionNeutrals[state][neutral_class_map[cls]]; |
|
683 int clsRun = GetDeferredNeutrals(action, level); |
|
684 if (clsRun != N) |
|
685 { |
|
686 SetDeferredRunClass(s, sRun, clsRun); |
|
687 sRun = NULL; |
|
688 } |
|
689 int clsNew = GetResolvedNeutrals(action); |
|
690 if (clsNew != N) |
|
691 s->setBidiClass(clsNew); |
|
692 if (!sRun && (action & In)) |
|
693 sRun = s; |
|
694 state = stateNeutrals[state][neutral_class_map[cls]]; |
|
695 } |
|
696 } |
|
697 cls = EmbeddingDirection(eos); |
|
698 int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level); |
|
699 if (clsRun != N) |
|
700 SetThisDeferredRunClass(sLast, sRun, clsRun); |
|
701 } |
|
702 |
|
703 const int addLevel[][4] = |
|
704 { |
|
705 // cls = L, R, AN, EN level = |
|
706 /* even */ { 0, 1, 2, 2, }, // EVEN |
|
707 /* odd */ { 1, 0, 1, 1, }, // ODD |
|
708 |
|
709 }; |
|
710 |
|
711 void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror) |
|
712 { |
|
713 bool rtl = seg->dir() & 1; |
|
714 int level = rtl; |
|
715 Slot *slast = 0; |
|
716 for ( ; s; s = s->next()) |
|
717 { |
|
718 int cls = BaseClass(s); |
|
719 s->prev(slast); // restitch the prev() side of the doubly linked list |
|
720 slast = s; |
|
721 if (cls == AN) |
|
722 cls = AL; // use AL value as the index for AN, no property change |
|
723 if (cls < 5 && cls > 0) |
|
724 { |
|
725 level = s->getBidiLevel(); |
|
726 level += addLevel[level & 1][cls - 1]; |
|
727 s->setBidiLevel(level); |
|
728 } |
|
729 if (aMirror) |
|
730 { |
|
731 int hasChar = seg->glyphAttr(s->gid(), aMirror + 1); |
|
732 if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar)) |
|
733 || ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) ) |
|
734 { |
|
735 unsigned short g = seg->glyphAttr(s->gid(), aMirror); |
|
736 if (g) s->setGlyph(seg, g); |
|
737 } |
|
738 } |
|
739 } |
|
740 } |
|
741 |
|
742 void resolveWhitespace(int baseLevel, Slot *s) |
|
743 { |
|
744 for ( ; s; s = s->prev()) |
|
745 { |
|
746 int8 cls = s->getBidiClass(); |
|
747 if (cls == WS || cls & WSflag) |
|
748 s->setBidiLevel(baseLevel); |
|
749 else if (cls != BN) |
|
750 break; |
|
751 } |
|
752 } |
|
753 |
|
754 |
|
755 /* |
|
756 Stitch two spans together to make another span (with ends tied together). |
|
757 If the level is odd then swap the order of the two spans |
|
758 */ |
|
759 inline |
|
760 Slot * join(int level, Slot * a, Slot * b) |
|
761 { |
|
762 if (!a) return b; |
|
763 if (level & 1) { Slot * const t = a; a = b; b = t; } |
|
764 Slot * const t = b->prev(); |
|
765 a->prev()->next(b); b->prev(a->prev()); // splice middle |
|
766 t->next(a); a->prev(t); // splice ends |
|
767 return a; |
|
768 } |
|
769 |
|
770 /* |
|
771 Given the first slot in a run of slots with the same bidi level, turn the run |
|
772 into it's own little doubly linked list ring (a span) with the two ends joined together. |
|
773 If the run is rtl then reverse its direction. |
|
774 Returns the first slot after the span |
|
775 */ |
|
776 Slot * span(Slot * & cs, const bool rtl) |
|
777 { |
|
778 Slot * r = cs, * re = cs; cs = cs->next(); |
|
779 if (rtl) |
|
780 { |
|
781 Slot * t = r->next(); r->next(r->prev()); r->prev(t); |
|
782 for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->prev()) |
|
783 { |
|
784 re = cs; |
|
785 t = cs->next(); cs->next(cs->prev()); cs->prev(t); |
|
786 } |
|
787 r->next(re); |
|
788 re->prev(r); |
|
789 r = re; |
|
790 } |
|
791 else |
|
792 { |
|
793 for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->next()) |
|
794 re = cs; |
|
795 r->prev(re); |
|
796 re->next(r); |
|
797 } |
|
798 if (cs) cs->prev(0); |
|
799 return r; |
|
800 } |
|
801 |
|
802 inline int getlevel(const Slot *cs, const int level) |
|
803 { |
|
804 while (cs && cs->getBidiClass() == BN) |
|
805 { cs = cs->next(); } |
|
806 if (cs) |
|
807 return cs->getBidiLevel(); |
|
808 else |
|
809 return level; |
|
810 } |
|
811 |
|
812 Slot *resolveOrder(Slot * & cs, const bool reordered, const int level) |
|
813 { |
|
814 Slot * r = 0; |
|
815 int ls; |
|
816 while (cs && level <= (ls = getlevel(cs, level) - reordered)) |
|
817 { |
|
818 r = join(level, r, level < ls |
|
819 ? resolveOrder(/* updates */cs, reordered, level+1) // find span of heighest level |
|
820 : span(/* updates */cs, level & 1)); |
|
821 } |
|
822 return r; |
|
823 } |