gfx/graphite2/src/Bidi.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /*  GRAPHITE2 LICENSING
     3     Copyright 2011, SIL International
     4     All rights reserved.
     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.
    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.
    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.
    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"
    32 using namespace graphite2;
    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
    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
    61         ON = N
    62 };
    64 enum DirMask {
    65         WSflag = (1 << 7),     // keep track of WS for eos handling
    66         WSMask = ~(1 << 7)
    67 };
    69 inline uint8    BaseClass(Slot *s)   { return s->getBidiClass() & WSMask; }
    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.
    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);
    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 }
   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 }
   128 enum maxs
   129 {
   130     MAX_LEVEL = 125,
   131 };
   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
   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;
   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;
   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;
   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             }
   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 }
   323 // === RESOLVE WEAK TYPES ================================================
   325 enum bidi_state // possible states
   326 {
   327         xa,             //      arabic letter
   328         xr,             //      right leter
   329         xl,             //      left letter
   331         ao,             //      arabic lett. foll by ON
   332         ro,             //      right lett. foll by ON
   333         lo,             //      left lett. foll by ON
   335         rt,             //      ET following R
   336         lt,             //      ET following L
   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
   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
   350         ret,            //      ET following re
   351         let,            //      ET following le
   352 } ;
   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            */ },
   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  */ },
   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         */ },
   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 */ },
   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     */ },
   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        */ },
   384 };
   386 enum bidi_action // possible actions
   387 {
   388         // primitives
   389         IX = 0x100,                     // increment
   390         XX = 0xF,                       // no-op
   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
   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 };
   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               */ },
   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     */ },
   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            */ },
   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    */ },
   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        */ },
   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 };
   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; }
   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 };
   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 }
   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 }
   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;
   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;
   506         case NSM :
   507             if (s == start)
   508             {
   509                 cls = EmbeddingDirection(sos);
   510                 s->setBidiClass(cls);
   511             }
   512             break;
   513         }
   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     }
   530     cls = EmbeddingDirection(eos);
   531     int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
   532     if (clsRun != XX)
   533         SetThisDeferredRunClass(sLast, sRun, clsRun);
   534 }
   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);
   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 }
   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 }
   614 int GetResolvedNeutrals(int action)
   615 {
   616         return action & 0xF;
   617 }
   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 } ;
   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 };
   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
   639 {       In, En, Rn, Rn, Rn, },  // rn   N preceded by right
   640 {       In, Ln, En, En, LnL, }, // ln   N preceded by left
   642 {       In,  0,  0,  0,  L, },  // a   AN preceded by left
   643 {       In, En, Rn, Rn, En, },  // na   N  preceded by a
   644 } ;
   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
   652 {       rn, l,  r,      r,      r, },           // rn  N preceded by right
   653 {       ln, l,  r,      a,      l, },           // ln  N preceded by left
   655 {       na, l,  r,      a,      l, },           // a  AN preceded by left
   656 {       na, l,  r,      a,      l, },           // na  N preceded by la
   657 } ;
   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;
   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;
   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 }
   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
   709 };
   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 }
   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 }
   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 }
   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 }
   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 }
   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 }

mercurial