1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/graphite2/src/Bidi.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,823 @@ 1.4 +/* GRAPHITE2 LICENSING 1.5 + 1.6 + Copyright 2011, SIL International 1.7 + All rights reserved. 1.8 + 1.9 + This library is free software; you can redistribute it and/or modify 1.10 + it under the terms of the GNU Lesser General Public License as published 1.11 + by the Free Software Foundation; either version 2.1 of License, or 1.12 + (at your option) any later version. 1.13 + 1.14 + This program is distributed in the hope that it will be useful, 1.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + Lesser General Public License for more details. 1.18 + 1.19 + You should also have received a copy of the GNU Lesser General Public 1.20 + License along with this library in the file named "LICENSE". 1.21 + If not, write to the Free Software Foundation, 51 Franklin Street, 1.22 + suite 500, Boston, MA 02110-1335, USA or visit their web page on the 1.23 + internet at http://www.fsf.org/licenses/lgpl.html. 1.24 + 1.25 +Alternatively, the contents of this file may be used under the terms of the 1.26 +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 1.27 +License, as published by the Free Software Foundation, either version 2 1.28 +of the License or (at your option) any later version. 1.29 +*/ 1.30 +#include "inc/Main.h" 1.31 +#include "inc/Slot.h" 1.32 +#include "inc/Segment.h" 1.33 +#include "inc/Bidi.h" 1.34 + 1.35 +using namespace graphite2; 1.36 + 1.37 +enum DirCode { // Hungarian: dirc 1.38 + Unk = -1, 1.39 + N = 0, // other neutrals (default) - ON 1.40 + L = 1, // left-to-right, strong - L 1.41 + R = 2, // right-to-left, strong - R 1.42 + AL = 3, // Arabic letter, right-to-left, strong, AR 1.43 + EN = 4, // European number, left-to-right, weak - EN 1.44 + EUS = 5, // European separator, left-to-right, weak - ES 1.45 + ET = 6, // European number terminator, left-to-right, weak - ET 1.46 + AN = 7, // Arabic number, left-to-right, weak - AN 1.47 + CUS = 8, // Common number separator, left-to-right, weak - CS 1.48 + WS = 9, // white space, neutral - WS 1.49 + BN = 10, // boundary neutral - BN 1.50 + 1.51 + LRO = 11, // LTR override 1.52 + RLO = 12, // RTL override 1.53 + LRE = 13, // LTR embedding 1.54 + RLE = 14, // RTL embedding 1.55 + PDF = 15, // pop directional format 1.56 + NSM = 16, // non-space mark 1.57 + LRI = 17, // LRI isolate 1.58 + RLI = 18, // RLI isolate 1.59 + FSI = 19, // FSI isolate 1.60 + PDI = 20, // pop isolate 1.61 + OPP = 21, // opening paired parenthesis 1.62 + CPP = 22, // closing paired parenthesis 1.63 + 1.64 + ON = N 1.65 +}; 1.66 + 1.67 +enum DirMask { 1.68 + WSflag = (1 << 7), // keep track of WS for eos handling 1.69 + WSMask = ~(1 << 7) 1.70 +}; 1.71 + 1.72 +inline uint8 BaseClass(Slot *s) { return s->getBidiClass() & WSMask; } 1.73 + 1.74 +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 }; 1.75 +// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag. 1.76 + 1.77 +void resolveWeak(Slot *start, int sos, int eos); 1.78 +void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos); 1.79 +void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack); 1.80 + 1.81 +inline int calc_base_level(Slot *s) 1.82 +{ 1.83 + int count = 0; 1.84 + for ( ; s; s = s->next()) 1.85 + { 1.86 + int cls = s->getBidiClass(); 1.87 + if (count) 1.88 + { 1.89 + switch(cls) 1.90 + { 1.91 + case LRI : 1.92 + case RLI : 1.93 + case FSI : 1.94 + ++count; 1.95 + break; 1.96 + case PDI : 1.97 + --count; 1.98 + } 1.99 + } 1.100 + else 1.101 + { 1.102 + switch(cls) 1.103 + { 1.104 + case L : 1.105 + return 0; 1.106 + case R : 1.107 + case AL : 1.108 + return 1; 1.109 + case LRI : 1.110 + case RLI : 1.111 + case FSI : 1.112 + ++count; 1.113 + } 1.114 + } 1.115 + } 1.116 + return 0; 1.117 +} 1.118 + 1.119 +// inline or not? 1.120 +void do_resolves(Slot *start, int level, int sos, int eos, int &bmask, Segment *seg, uint8 aMirror, BracketPairStack &stack) 1.121 +{ 1.122 + if (bmask & 0x1F1178) 1.123 + resolveWeak(start, sos, eos); 1.124 + if (bmask & 0x200000) 1.125 + processParens(start, seg, aMirror, level, stack); 1.126 + if (bmask & 0x7E0361) 1.127 + resolveNeutrals(start, level, sos, eos); 1.128 + bmask = 0; 1.129 +} 1.130 + 1.131 +enum maxs 1.132 +{ 1.133 + MAX_LEVEL = 125, 1.134 +}; 1.135 + 1.136 +// returns where we are up to in processing 1.137 +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) 1.138 +{ 1.139 + int bmask = 0; 1.140 + Slot *s = start; 1.141 + Slot *slast = start; 1.142 + Slot *scurr = 0; 1.143 + Slot *stemp; 1.144 + int lnextLevel = nextLevel; 1.145 + int newLevel; 1.146 + int empty = 1; 1.147 + for ( ; s; s = s ? s->next() : s) 1.148 + { 1.149 + int cls = s->getBidiClass(); 1.150 + bmask |= (1 << cls); 1.151 + s->setBidiLevel(level); 1.152 + // we keep s->prev() pointing backwards for PDI repeating 1.153 + 1.154 + switch (cls) 1.155 + { 1.156 + case BN : 1.157 + if (slast == s) slast = s->next(); // ignore if at front of text 1.158 + continue; 1.159 + case LRE : 1.160 + case LRO : 1.161 + case RLE : 1.162 + case RLO : 1.163 + switch (cls) 1.164 + { 1.165 + case LRE : 1.166 + case LRO : 1.167 + newLevel = level + (level & 1 ? 1 : 2); 1.168 + break; 1.169 + case RLE : 1.170 + case RLO : 1.171 + newLevel = level + (level & 1 ? 2 : 1); 1.172 + break; 1.173 + } 1.174 + s->setBidiClass(BN); 1.175 + if (isolerr || newLevel > MAX_LEVEL || embederr) 1.176 + { 1.177 + if (!isolerr) ++embederr; 1.178 + break; 1.179 + } 1.180 + stemp = scurr; 1.181 + if (scurr) 1.182 + scurr->prev(0); // don't include control in string 1.183 + lnextLevel = newLevel; 1.184 + scurr = s; 1.185 + s->setBidiLevel(newLevel); // to make it vanish 1.186 + // recurse for the new subsequence. A sequence only contains text at the same level 1.187 + s = process_bidi(s->next(), newLevel, level, lnextLevel, cls < LRE, 0, cisol, isolerr, embederr, 0, seg, aMirror, bstack); 1.188 + // s points at PDF or end of sequence 1.189 + // try to keep extending the run and not process it until we have to 1.190 + if (lnextLevel != level || !s) // if the subsequence really had something in it, or we are at the end of the run 1.191 + { 1.192 + if (slast != scurr) // process the run now, don't try to extend it 1.193 + { 1.194 + // process text preceeding embedding 1.195 + do_resolves(slast, level, (prelevel > level ? prelevel : level) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack); 1.196 + empty = 0; 1.197 + nextLevel = level; 1.198 + } 1.199 + else if (lnextLevel != level) // the subsequence had something 1.200 + { 1.201 + empty = 0; // so we aren't empty either 1.202 + nextLevel = lnextLevel; // but since we really are empty, pass back our level from the subsequence 1.203 + } 1.204 + if (s) // if still more to process 1.205 + { 1.206 + prelevel = lnextLevel; // future text starts out with sos of the higher subsequence 1.207 + lnextLevel = level; // and eos is our level 1.208 + } 1.209 + slast = s ? s->next() : s; 1.210 + } 1.211 + else if (stemp) 1.212 + stemp->prev(s); 1.213 + break; 1.214 + 1.215 + case PDF : 1.216 + s->setBidiClass(BN); 1.217 + s->prev(0); // unstitch us since we skip final stitching code when we return 1.218 + if (isol || isolerr || init) // boundary error conditions 1.219 + break; 1.220 + if (embederr) 1.221 + { 1.222 + --embederr; 1.223 + break; 1.224 + } 1.225 + if (slast != s) 1.226 + { 1.227 + scurr->prev(0); // if slast, then scurr. Terminate before here 1.228 + do_resolves(slast, level, level & 1, level & 1, bmask, seg, aMirror, bstack); 1.229 + empty = 0; 1.230 + } 1.231 + if (empty) 1.232 + { 1.233 + nextLevel = prelevel; // no contents? set our level to that of parent 1.234 + s->setBidiLevel(prelevel); 1.235 + } 1.236 + return s; 1.237 + 1.238 + case FSI : 1.239 + case LRI : 1.240 + case RLI : 1.241 + switch (cls) 1.242 + { 1.243 + case FSI : 1.244 + if (calc_base_level(s->next())) 1.245 + newLevel = level + (level & 1 ? 2 : 1); 1.246 + else 1.247 + newLevel = level + (level & 1 ? 1 : 2); 1.248 + break; 1.249 + case LRI : 1.250 + newLevel = level + (level & 1 ? 1 : 2); 1.251 + break; 1.252 + case RLI : 1.253 + newLevel = level + (level & 1 ? 2 : 1); 1.254 + break; 1.255 + } 1.256 + if (newLevel > MAX_LEVEL || isolerr) 1.257 + { 1.258 + ++isolerr; 1.259 + s->setBidiClass(ON | WSflag); 1.260 + break; 1.261 + } 1.262 + ++cisol; 1.263 + if (scurr) scurr->prev(s); 1.264 + scurr = s; // include FSI 1.265 + lnextLevel = newLevel; 1.266 + // recurse for the new sub sequence 1.267 + s = process_bidi(s->next(), newLevel, newLevel, lnextLevel, 0, 1, cisol, isolerr, embederr, 0, seg, aMirror, bstack); 1.268 + // s points at PDI 1.269 + if (s) 1.270 + { 1.271 + bmask |= 1 << BaseClass(s); // include the PDI in the mask 1.272 + s->setBidiLevel(level); // reset its level to our level 1.273 + } 1.274 + lnextLevel = level; 1.275 + break; 1.276 + 1.277 + case PDI : 1.278 + if (isolerr) 1.279 + { 1.280 + --isolerr; 1.281 + s->setBidiClass(ON | WSflag); 1.282 + break; 1.283 + } 1.284 + if (init || !cisol) 1.285 + { 1.286 + s->setBidiClass(ON | WSflag); 1.287 + break; 1.288 + } 1.289 + embederr = 0; 1.290 + if (!isol) // we are in an embedded subsequence, we have to return through all those 1.291 + { 1.292 + if (empty) // if empty, reset the level to tell embedded parent 1.293 + nextLevel = prelevel; 1.294 + return s->prev(); // keep working up the stack pointing at this PDI until we get to an isolate entry 1.295 + } 1.296 + else // we are terminating an isolate sequence 1.297 + { 1.298 + if (slast != s) // process any remaining content in this subseqence 1.299 + { 1.300 + scurr->prev(0); 1.301 + do_resolves(slast, level, prelevel & 1, level & 1, bmask, seg, aMirror, bstack); 1.302 + } 1.303 + --cisol; // pop the isol sequence from the stack 1.304 + return s; 1.305 + } 1.306 + 1.307 + default : 1.308 + if (dirover) 1.309 + s->setBidiClass((level & 1 ? R : L) | (WSflag * (cls == WS))); 1.310 + } 1.311 + if (s) s->prev(0); // unstitch us 1.312 + if (scurr) // stitch in text for processing 1.313 + scurr->prev(s); 1.314 + scurr = s; // add us to text to process 1.315 + } 1.316 + if (slast != s) 1.317 + { 1.318 + do_resolves(slast, level, (level > prelevel ? level : prelevel) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack); 1.319 + empty = 0; 1.320 + } 1.321 + if (empty || isol) 1.322 + nextLevel = prelevel; 1.323 + return s; 1.324 +} 1.325 + 1.326 +// === RESOLVE WEAK TYPES ================================================ 1.327 + 1.328 +enum bidi_state // possible states 1.329 +{ 1.330 + xa, // arabic letter 1.331 + xr, // right leter 1.332 + xl, // left letter 1.333 + 1.334 + ao, // arabic lett. foll by ON 1.335 + ro, // right lett. foll by ON 1.336 + lo, // left lett. foll by ON 1.337 + 1.338 + rt, // ET following R 1.339 + lt, // ET following L 1.340 + 1.341 + cn, // EN, AN following AL 1.342 + ra, // arabic number foll R 1.343 + re, // european number foll R 1.344 + la, // arabic number foll L 1.345 + le, // european number foll L 1.346 + 1.347 + ac, // CS following cn 1.348 + rc, // CS following ra 1.349 + rs, // CS,ES following re 1.350 + lc, // CS following la 1.351 + ls, // CS,ES following le 1.352 + 1.353 + ret, // ET following re 1.354 + let, // ET following le 1.355 +} ; 1.356 + 1.357 +const bidi_state stateWeak[][10] = 1.358 +{ 1.359 + // N, L, R, AN, EN, AL,NSM, CS, ES, ET, 1.360 +{ /*xa*/ ao, xl, xr, cn, cn, xa, xa, ao, ao, ao, /* arabic letter */ }, 1.361 +{ /*xr*/ ro, xl, xr, ra, re, xa, xr, ro, ro, rt, /* right letter */ }, 1.362 +{ /*xl*/ lo, xl, xr, la, le, xa, xl, lo, lo, lt, /* left letter */ }, 1.363 + 1.364 +{ /*ao*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* arabic lett. foll by ON*/ }, 1.365 +{ /*ro*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* right lett. foll by ON */ }, 1.366 +{ /*lo*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* left lett. foll by ON */ }, 1.367 + 1.368 +{ /*rt*/ ro, xl, xr, ra, re, xa, rt, ro, ro, rt, /* ET following R */ }, 1.369 +{ /*lt*/ lo, xl, xr, la, le, xa, lt, lo, lo, lt, /* ET following L */ }, 1.370 + 1.371 +{ /*cn*/ ao, xl, xr, cn, cn, xa, cn, ac, ao, ao, /* EN, AN following AL */ }, 1.372 +{ /*ra*/ ro, xl, xr, ra, re, xa, ra, rc, ro, rt, /* arabic number foll R */ }, 1.373 +{ /*re*/ ro, xl, xr, ra, re, xa, re, rs, rs,ret, /* european number foll R */ }, 1.374 +{ /*la*/ lo, xl, xr, la, le, xa, la, lc, lo, lt, /* arabic number foll L */ }, 1.375 +{ /*le*/ lo, xl, xr, la, le, xa, le, ls, ls,let, /* european number foll L */ }, 1.376 + 1.377 +{ /*ac*/ ao, xl, xr, cn, cn, xa, ao, ao, ao, ao, /* CS following cn */ }, 1.378 +{ /*rc*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS following ra */ }, 1.379 +{ /*rs*/ ro, xl, xr, ra, re, xa, ro, ro, ro, rt, /* CS,ES following re */ }, 1.380 +{ /*lc*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS following la */ }, 1.381 +{ /*ls*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS,ES following le */ }, 1.382 + 1.383 +{ /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re */ }, 1.384 +{ /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le */ }, 1.385 + 1.386 + 1.387 +}; 1.388 + 1.389 +enum bidi_action // possible actions 1.390 +{ 1.391 + // primitives 1.392 + IX = 0x100, // increment 1.393 + XX = 0xF, // no-op 1.394 + 1.395 + // actions 1.396 + xxx = (XX << 4) + XX, // no-op 1.397 + xIx = IX + xxx, // increment run 1.398 + xxN = (XX << 4) + ON, // set current to N 1.399 + xxE = (XX << 4) + EN, // set current to EN 1.400 + xxA = (XX << 4) + AN, // set current to AN 1.401 + xxR = (XX << 4) + R, // set current to R 1.402 + xxL = (XX << 4) + L, // set current to L 1.403 + Nxx = (ON << 4) + 0xF, // set run to neutral 1.404 + Axx = (AN << 4) + 0xF, // set run to AN 1.405 + ExE = (EN << 4) + EN, // set run to EN, set current to EN 1.406 + NIx = (ON << 4) + 0xF + IX, // set run to N, increment 1.407 + NxN = (ON << 4) + ON, // set run to N, set current to N 1.408 + NxR = (ON << 4) + R, // set run to N, set current to R 1.409 + NxE = (ON << 4) + EN, // set run to N, set current to EN 1.410 + 1.411 + AxA = (AN << 4) + AN, // set run to AN, set current to AN 1.412 + NxL = (ON << 4) + L, // set run to N, set current to L 1.413 + LxL = (L << 4) + L, // set run to L, set current to L 1.414 +}; 1.415 + 1.416 + 1.417 +const bidi_action actionWeak[][10] = 1.418 +{ 1.419 + // N,.. L, R, AN, EN, AL, NSM, CS,..ES, ET, 1.420 +{ /*xa*/ xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN, /* arabic letter */ }, 1.421 +{ /*xr*/ xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx, /* right leter */ }, 1.422 +{ /*xl*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx, /* left letter */ }, 1.423 + 1.424 +{ /*ao*/ xxx, xxx, xxx, xxx, xxA, xxR, xxN, xxN, xxN, xxN, /* arabic lett. foll by ON */ }, 1.425 +{ /*ro*/ xxx, xxx, xxx, xxx, xxE, xxR, xxN, xxN, xxN, xIx, /* right lett. foll by ON */ }, 1.426 +{ /*lo*/ xxx, xxx, xxx, xxx, xxL, xxR, xxN, xxN, xxN, xIx, /* left lett. foll by ON */ }, 1.427 + 1.428 +{ /*rt*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, xIx, NxN, NxN, xIx, /* ET following R */ }, 1.429 +{ /*lt*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, xIx, NxN, NxN, xIx, /* ET following L */ }, 1.430 + 1.431 +{ /*cn*/ xxx, xxx, xxx, xxx, xxA, xxR, xxA, xIx, xxN, xxN, /* EN, AN following AL */ }, 1.432 +{ /*ra*/ xxx, xxx, xxx, xxx, xxE, xxR, xxA, xIx, xxN, xIx, /* arabic number foll R */ }, 1.433 +{ /*re*/ xxx, xxx, xxx, xxx, xxE, xxR, xxE, xIx, xIx, xxE, /* european number foll R */ }, 1.434 +{ /*la*/ xxx, xxx, xxx, xxx, xxL, xxR, xxA, xIx, xxN, xIx, /* arabic number foll L */ }, 1.435 +{ /*le*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xIx, xIx, xxL, /* european number foll L */ }, 1.436 + 1.437 +{ /*ac*/ Nxx, Nxx, Nxx, Axx, AxA, NxR, NxN, NxN, NxN, NxN, /* CS following cn */ }, 1.438 +{ /*rc*/ Nxx, Nxx, Nxx, Axx, NxE, NxR, NxN, NxN, NxN, NIx, /* CS following ra */ }, 1.439 +{ /*rs*/ Nxx, Nxx, Nxx, Nxx, ExE, NxR, NxN, NxN, NxN, NIx, /* CS,ES following re */ }, 1.440 +{ /*lc*/ Nxx, Nxx, Nxx, Axx, NxL, NxR, NxN, NxN, NxN, NIx, /* CS following la */ }, 1.441 +{ /*ls*/ Nxx, Nxx, Nxx, Nxx, LxL, NxR, NxN, NxN, NxN, NIx, /* CS,ES following le */ }, 1.442 + 1.443 +{ /*ret*/xxx, xxx, xxx, xxx, xxE, xxR, xxE, xxN, xxN, xxE, /* ET following re */ }, 1.444 +{ /*let*/xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xxL, /* ET following le */ }, 1.445 +}; 1.446 + 1.447 +inline uint8 GetDeferredType(bidi_action a) { return (a >> 4) & 0xF; } 1.448 +inline uint8 GetResolvedType(bidi_action a) { return a & 0xF; } 1.449 +inline DirCode EmbeddingDirection(int l) { return l & 1 ? R : L; } 1.450 + 1.451 +// Neutrals 1.452 +enum neutral_action 1.453 +{ 1.454 + // action to resolve previous input 1.455 + nL = L, // resolve EN to L 1.456 + En = 3 << 4, // resolve neutrals run to embedding level direction 1.457 + Rn = R << 4, // resolve neutrals run to strong right 1.458 + Ln = L << 4, // resolved neutrals run to strong left 1.459 + In = (1<<8), // increment count of deferred neutrals 1.460 + LnL = (1<<4)+L, // set run and EN to L 1.461 +}; 1.462 + 1.463 +// ->prev() here means ->next() 1.464 +void SetDeferredRunClass(Slot *s, Slot *sRun, int nval) 1.465 +{ 1.466 + if (!sRun || s == sRun) return; 1.467 + for (Slot *p = sRun; p != s; p = p->prev()) 1.468 + if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag); 1.469 + else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag)); 1.470 +} 1.471 + 1.472 +void SetThisDeferredRunClass(Slot *s, Slot *sRun, int nval) 1.473 +{ 1.474 + if (!sRun) return; 1.475 + for (Slot *p = sRun, *e = s->prev(); p != e; p = p->prev()) 1.476 + if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag); 1.477 + else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag)); 1.478 +} 1.479 + 1.480 +void resolveWeak(Slot *start, int sos, int eos) 1.481 +{ 1.482 + int state = (sos & 1) ? xr : xl; 1.483 + int cls; 1.484 + Slot *s = start; 1.485 + Slot *sRun = NULL; 1.486 + Slot *sLast = s; 1.487 + 1.488 + for ( ; s; s = s->prev()) 1.489 + { 1.490 + sLast = s; 1.491 + cls = BaseClass(s); 1.492 + switch (cls) 1.493 + { 1.494 + case BN : 1.495 + if (s == start) start = s->prev(); // skip initial BNs for NSM resolving 1.496 + continue; 1.497 + case LRI : 1.498 + case RLI : 1.499 + case FSI : 1.500 + case PDI : 1.501 + { 1.502 + Slot *snext = s->prev(); 1.503 + if (snext && snext->getBidiClass() == NSM) 1.504 + snext->setBidiClass(ON); 1.505 + s->setBidiClass(ON | WSflag); 1.506 + } 1.507 + break; 1.508 + 1.509 + case NSM : 1.510 + if (s == start) 1.511 + { 1.512 + cls = EmbeddingDirection(sos); 1.513 + s->setBidiClass(cls); 1.514 + } 1.515 + break; 1.516 + } 1.517 + 1.518 + bidi_action action = actionWeak[state][bidi_class_map[cls]]; 1.519 + int clsRun = GetDeferredType(action); 1.520 + if (clsRun != XX) 1.521 + { 1.522 + SetDeferredRunClass(s, sRun, clsRun); 1.523 + sRun = NULL; 1.524 + } 1.525 + int clsNew = GetResolvedType(action); 1.526 + if (clsNew != XX) 1.527 + s->setBidiClass(clsNew); 1.528 + if (!sRun && (IX & action)) 1.529 + sRun = s; 1.530 + state = stateWeak[state][bidi_class_map[cls]]; 1.531 + } 1.532 + 1.533 + cls = EmbeddingDirection(eos); 1.534 + int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]); 1.535 + if (clsRun != XX) 1.536 + SetThisDeferredRunClass(sLast, sRun, clsRun); 1.537 +} 1.538 + 1.539 +void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack) 1.540 +{ 1.541 + uint8 mask = 0; 1.542 + int8 lastDir = -1; 1.543 + BracketPair *p; 1.544 + for ( ; s; s = s->prev()) // walk the sequence 1.545 + { 1.546 + uint16 ogid = seg->glyphAttr(s->gid(), aMirror); 1.547 + int cls = BaseClass(s); 1.548 + 1.549 + switch(cls) 1.550 + { 1.551 + case OPP : 1.552 + stack.orin(mask); 1.553 + stack.push(ogid, s, lastDir, lastDir != CPP); 1.554 + mask = 0; 1.555 + lastDir = OPP; 1.556 + break; 1.557 + case CPP : 1.558 + stack.orin(mask); 1.559 + p = stack.scan(s->gid()); 1.560 + if (!p) break; 1.561 + mask = 0; 1.562 + stack.close(p, s); 1.563 + lastDir = CPP; 1.564 + break; 1.565 + case L : 1.566 + lastDir = L; 1.567 + mask |= 1; 1.568 + break; 1.569 + case R : 1.570 + case AL : 1.571 + case AN : 1.572 + case EN : 1.573 + lastDir = R; 1.574 + mask |= 2; 1.575 + } 1.576 + } 1.577 + for (p = stack.start(); p; p =p->next()) // walk the stack 1.578 + { 1.579 + if (p->close() && p->mask()) 1.580 + { 1.581 + int dir = (level & 1) + 1; 1.582 + if (p->mask() & dir) 1.583 + { } 1.584 + else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding 1.585 + { 1.586 + int ldir = p->before(); 1.587 + if ((p->before() == OPP || p->before() == CPP) && p->prev()) 1.588 + { 1.589 + for (BracketPair *q = p->prev(); q; q = q->prev()) 1.590 + { 1.591 + ldir = q->open()->getBidiClass(); 1.592 + if (ldir < 3) break; 1.593 + ldir = q->before(); 1.594 + if (ldir < 3) break; 1.595 + } 1.596 + if (ldir > 2) ldir = 0; 1.597 + } 1.598 + if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L) 1.599 + dir = (~level & 1) + 1; 1.600 + } 1.601 + p->open()->setBidiClass(dir); 1.602 + p->close()->setBidiClass(dir); 1.603 + } 1.604 + } 1.605 + stack.clear(); 1.606 +} 1.607 + 1.608 +int GetDeferredNeutrals(int action, int level) 1.609 +{ 1.610 + action = (action >> 4) & 0xF; 1.611 + if (action == (En >> 4)) 1.612 + return EmbeddingDirection(level); 1.613 + else 1.614 + return action; 1.615 +} 1.616 + 1.617 +int GetResolvedNeutrals(int action) 1.618 +{ 1.619 + return action & 0xF; 1.620 +} 1.621 + 1.622 +// state values 1.623 +enum neutral_state 1.624 +{ 1.625 + // new temporary class 1.626 + r, // R and characters resolved to R 1.627 + l, // L and characters resolved to L 1.628 + rn, // N preceded by right 1.629 + ln, // N preceded by left 1.630 + a, // AN preceded by left (the abbrev 'la' is used up above) 1.631 + na, // N preceeded by a 1.632 +} ; 1.633 + 1.634 +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 }; 1.635 + 1.636 +const int actionNeutrals[][5] = 1.637 +{ 1.638 +// cls= N, L, R, AN, EN, state = 1.639 +{ In, 0, 0, 0, 0, }, // r right 1.640 +{ In, 0, 0, 0, L, }, // l left 1.641 + 1.642 +{ In, En, Rn, Rn, Rn, }, // rn N preceded by right 1.643 +{ In, Ln, En, En, LnL, }, // ln N preceded by left 1.644 + 1.645 +{ In, 0, 0, 0, L, }, // a AN preceded by left 1.646 +{ In, En, Rn, Rn, En, }, // na N preceded by a 1.647 +} ; 1.648 + 1.649 +const int stateNeutrals[][5] = 1.650 +{ 1.651 +// cls= N, L, R, AN, EN state = 1.652 +{ rn, l, r, r, r, }, // r right 1.653 +{ ln, l, r, a, l, }, // l left 1.654 + 1.655 +{ rn, l, r, r, r, }, // rn N preceded by right 1.656 +{ ln, l, r, a, l, }, // ln N preceded by left 1.657 + 1.658 +{ na, l, r, a, l, }, // a AN preceded by left 1.659 +{ na, l, r, a, l, }, // na N preceded by la 1.660 +} ; 1.661 + 1.662 +void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos) 1.663 +{ 1.664 + int state = (sos & 1) ? r : l; 1.665 + int cls; 1.666 + Slot *sRun = NULL; 1.667 + Slot *sLast = s; 1.668 + int level = baseLevel; 1.669 + 1.670 + for ( ; s; s = s->prev()) 1.671 + { 1.672 + sLast = s; 1.673 + cls = BaseClass(s); 1.674 + switch (cls) 1.675 + { 1.676 + case BN : 1.677 + continue; 1.678 + case LRI : 1.679 + case RLI : 1.680 + case FSI : 1.681 + s->setBidiClass(BN | WSflag); 1.682 + continue; 1.683 + 1.684 + default : 1.685 + int action = actionNeutrals[state][neutral_class_map[cls]]; 1.686 + int clsRun = GetDeferredNeutrals(action, level); 1.687 + if (clsRun != N) 1.688 + { 1.689 + SetDeferredRunClass(s, sRun, clsRun); 1.690 + sRun = NULL; 1.691 + } 1.692 + int clsNew = GetResolvedNeutrals(action); 1.693 + if (clsNew != N) 1.694 + s->setBidiClass(clsNew); 1.695 + if (!sRun && (action & In)) 1.696 + sRun = s; 1.697 + state = stateNeutrals[state][neutral_class_map[cls]]; 1.698 + } 1.699 + } 1.700 + cls = EmbeddingDirection(eos); 1.701 + int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level); 1.702 + if (clsRun != N) 1.703 + SetThisDeferredRunClass(sLast, sRun, clsRun); 1.704 +} 1.705 + 1.706 +const int addLevel[][4] = 1.707 +{ 1.708 + // cls = L, R, AN, EN level = 1.709 +/* even */ { 0, 1, 2, 2, }, // EVEN 1.710 +/* odd */ { 1, 0, 1, 1, }, // ODD 1.711 + 1.712 +}; 1.713 + 1.714 +void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror) 1.715 +{ 1.716 + bool rtl = seg->dir() & 1; 1.717 + int level = rtl; 1.718 + Slot *slast = 0; 1.719 + for ( ; s; s = s->next()) 1.720 + { 1.721 + int cls = BaseClass(s); 1.722 + s->prev(slast); // restitch the prev() side of the doubly linked list 1.723 + slast = s; 1.724 + if (cls == AN) 1.725 + cls = AL; // use AL value as the index for AN, no property change 1.726 + if (cls < 5 && cls > 0) 1.727 + { 1.728 + level = s->getBidiLevel(); 1.729 + level += addLevel[level & 1][cls - 1]; 1.730 + s->setBidiLevel(level); 1.731 + } 1.732 + if (aMirror) 1.733 + { 1.734 + int hasChar = seg->glyphAttr(s->gid(), aMirror + 1); 1.735 + if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar)) 1.736 + || ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) ) 1.737 + { 1.738 + unsigned short g = seg->glyphAttr(s->gid(), aMirror); 1.739 + if (g) s->setGlyph(seg, g); 1.740 + } 1.741 + } 1.742 + } 1.743 +} 1.744 + 1.745 +void resolveWhitespace(int baseLevel, Slot *s) 1.746 +{ 1.747 + for ( ; s; s = s->prev()) 1.748 + { 1.749 + int8 cls = s->getBidiClass(); 1.750 + if (cls == WS || cls & WSflag) 1.751 + s->setBidiLevel(baseLevel); 1.752 + else if (cls != BN) 1.753 + break; 1.754 + } 1.755 +} 1.756 + 1.757 + 1.758 +/* 1.759 +Stitch two spans together to make another span (with ends tied together). 1.760 +If the level is odd then swap the order of the two spans 1.761 +*/ 1.762 +inline 1.763 +Slot * join(int level, Slot * a, Slot * b) 1.764 +{ 1.765 + if (!a) return b; 1.766 + if (level & 1) { Slot * const t = a; a = b; b = t; } 1.767 + Slot * const t = b->prev(); 1.768 + a->prev()->next(b); b->prev(a->prev()); // splice middle 1.769 + t->next(a); a->prev(t); // splice ends 1.770 + return a; 1.771 +} 1.772 + 1.773 +/* 1.774 +Given the first slot in a run of slots with the same bidi level, turn the run 1.775 +into it's own little doubly linked list ring (a span) with the two ends joined together. 1.776 +If the run is rtl then reverse its direction. 1.777 +Returns the first slot after the span 1.778 +*/ 1.779 +Slot * span(Slot * & cs, const bool rtl) 1.780 +{ 1.781 + Slot * r = cs, * re = cs; cs = cs->next(); 1.782 + if (rtl) 1.783 + { 1.784 + Slot * t = r->next(); r->next(r->prev()); r->prev(t); 1.785 + for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->prev()) 1.786 + { 1.787 + re = cs; 1.788 + t = cs->next(); cs->next(cs->prev()); cs->prev(t); 1.789 + } 1.790 + r->next(re); 1.791 + re->prev(r); 1.792 + r = re; 1.793 + } 1.794 + else 1.795 + { 1.796 + for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->next()) 1.797 + re = cs; 1.798 + r->prev(re); 1.799 + re->next(r); 1.800 + } 1.801 + if (cs) cs->prev(0); 1.802 + return r; 1.803 +} 1.804 + 1.805 +inline int getlevel(const Slot *cs, const int level) 1.806 +{ 1.807 + while (cs && cs->getBidiClass() == BN) 1.808 + { cs = cs->next(); } 1.809 + if (cs) 1.810 + return cs->getBidiLevel(); 1.811 + else 1.812 + return level; 1.813 +} 1.814 + 1.815 +Slot *resolveOrder(Slot * & cs, const bool reordered, const int level) 1.816 +{ 1.817 + Slot * r = 0; 1.818 + int ls; 1.819 + while (cs && level <= (ls = getlevel(cs, level) - reordered)) 1.820 + { 1.821 + r = join(level, r, level < ls 1.822 + ? resolveOrder(/* updates */cs, reordered, level+1) // find span of heighest level 1.823 + : span(/* updates */cs, level & 1)); 1.824 + } 1.825 + return r; 1.826 +}