gfx/graphite2/src/Bidi.cpp

changeset 0
6474c204b198
     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 +}

mercurial