Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1999-2010, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *   file name:  ubidiln.c
      9 *   encoding:   US-ASCII
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 *
     13 *   created on: 1999aug06
     14 *   created by: Markus W. Scherer, updated by Matitiahu Allouche
     15 */
     16 
     17 #include "cmemory.h"
     18 #include "unicode/utypes.h"
     19 #include "unicode/ustring.h"
     20 #include "unicode/uchar.h"
     21 #include "unicode/ubidi.h"
     22 #include "ubidiimp.h"
     23 #include "uassert.h"
     24 
     25 /*
     26  * General remarks about the functions in this file:
     27  *
     28  * These functions deal with the aspects of potentially mixed-directional
     29  * text in a single paragraph or in a line of a single paragraph
     30  * which has already been processed according to
     31  * the Unicode 3.0 BiDi algorithm as defined in
     32  * http://www.unicode.org/unicode/reports/tr9/ , version 13,
     33  * also described in The Unicode Standard, Version 4.0.1 .
     34  *
     35  * This means that there is a UBiDi object with a levels
     36  * and a dirProps array.
     37  * paraLevel and direction are also set.
     38  * Only if the length of the text is zero, then levels==dirProps==NULL.
     39  *
     40  * The overall directionality of the paragraph
     41  * or line is used to bypass the reordering steps if possible.
     42  * Even purely RTL text does not need reordering there because
     43  * the ubidi_getLogical/VisualIndex() functions can compute the
     44  * index on the fly in such a case.
     45  *
     46  * The implementation of the access to same-level-runs and of the reordering
     47  * do attempt to provide better performance and less memory usage compared to
     48  * a direct implementation of especially rule (L2) with an array of
     49  * one (32-bit) integer per text character.
     50  *
     51  * Here, the levels array is scanned as soon as necessary, and a vector of
     52  * same-level-runs is created. Reordering then is done on this vector.
     53  * For each run of text positions that were resolved to the same level,
     54  * only 8 bytes are stored: the first text position of the run and the visual
     55  * position behind the run after reordering.
     56  * One sign bit is used to hold the directionality of the run.
     57  * This is inefficient if there are many very short runs. If the average run
     58  * length is <2, then this uses more memory.
     59  *
     60  * In a further attempt to save memory, the levels array is never changed
     61  * after all the resolution rules (Xn, Wn, Nn, In).
     62  * Many functions have to consider the field trailingWSStart:
     63  * if it is less than length, then there is an implicit trailing run
     64  * at the paraLevel,
     65  * which is not reflected in the levels array.
     66  * This allows a line UBiDi object to use the same levels array as
     67  * its paragraph parent object.
     68  *
     69  * When a UBiDi object is created for a line of a paragraph, then the
     70  * paragraph's levels and dirProps arrays are reused by way of setting
     71  * a pointer into them, not by copying. This again saves memory and forbids to
     72  * change the now shared levels for (L1).
     73  */
     74 
     75 /* handle trailing WS (L1) -------------------------------------------------- */
     76 
     77 /*
     78  * setTrailingWSStart() sets the start index for a trailing
     79  * run of WS in the line. This is necessary because we do not modify
     80  * the paragraph's levels array that we just point into.
     81  * Using trailingWSStart is another form of performing (L1).
     82  *
     83  * To make subsequent operations easier, we also include the run
     84  * before the WS if it is at the paraLevel - we merge the two here.
     85  *
     86  * This function is called only from ubidi_setLine(), so pBiDi->paraLevel is
     87  * set correctly for the line even when contextual multiple paragraphs.
     88  */
     89 static void
     90 setTrailingWSStart(UBiDi *pBiDi) {
     91     /* pBiDi->direction!=UBIDI_MIXED */
     92 
     93     const DirProp *dirProps=pBiDi->dirProps;
     94     UBiDiLevel *levels=pBiDi->levels;
     95     int32_t start=pBiDi->length;
     96     UBiDiLevel paraLevel=pBiDi->paraLevel;
     97 
     98     /* If the line is terminated by a block separator, all preceding WS etc...
     99        are already set to paragraph level.
    100        Setting trailingWSStart to pBidi->length will avoid changing the
    101        level of B chars from 0 to paraLevel in ubidi_getLevels when
    102        orderParagraphsLTR==TRUE.
    103      */
    104     if(NO_CONTEXT_RTL(dirProps[start-1])==B) {
    105         pBiDi->trailingWSStart=start;   /* currently == pBiDi->length */
    106         return;
    107     }
    108     /* go backwards across all WS, BN, explicit codes */
    109     while(start>0 && DIRPROP_FLAG_NC(dirProps[start-1])&MASK_WS) {
    110         --start;
    111     }
    112 
    113     /* if the WS run can be merged with the previous run then do so here */
    114     while(start>0 && levels[start-1]==paraLevel) {
    115         --start;
    116     }
    117 
    118     pBiDi->trailingWSStart=start;
    119 }
    120 
    121 /* ubidi_setLine ------------------------------------------------------------ */
    122 
    123 U_CAPI void U_EXPORT2
    124 ubidi_setLine(const UBiDi *pParaBiDi,
    125               int32_t start, int32_t limit,
    126               UBiDi *pLineBiDi,
    127               UErrorCode *pErrorCode) {
    128     int32_t length;
    129 
    130     /* check the argument values */
    131     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
    132     RETURN_VOID_IF_NOT_VALID_PARA(pParaBiDi, *pErrorCode);
    133     RETURN_VOID_IF_BAD_RANGE(start, 0, limit, *pErrorCode);
    134     RETURN_VOID_IF_BAD_RANGE(limit, 0, pParaBiDi->length+1, *pErrorCode);
    135     if(pLineBiDi==NULL) {
    136         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    137         return;
    138     }
    139     if(ubidi_getParagraph(pParaBiDi, start, NULL, NULL, NULL, pErrorCode) !=
    140        ubidi_getParagraph(pParaBiDi, limit-1, NULL, NULL, NULL, pErrorCode)) {
    141         /* the line crosses a paragraph boundary */
    142         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    143         return;
    144     }
    145 
    146     /* set the values in pLineBiDi from its pParaBiDi parent */
    147     pLineBiDi->pParaBiDi=NULL;          /* mark unfinished setLine */
    148     pLineBiDi->text=pParaBiDi->text+start;
    149     length=pLineBiDi->length=limit-start;
    150     pLineBiDi->resultLength=pLineBiDi->originalLength=length;
    151     pLineBiDi->paraLevel=GET_PARALEVEL(pParaBiDi, start);
    152     pLineBiDi->paraCount=pParaBiDi->paraCount;
    153     pLineBiDi->runs=NULL;
    154     pLineBiDi->flags=0;
    155     pLineBiDi->reorderingMode=pParaBiDi->reorderingMode;
    156     pLineBiDi->reorderingOptions=pParaBiDi->reorderingOptions;
    157     pLineBiDi->controlCount=0;
    158     if(pParaBiDi->controlCount>0) {
    159         int32_t j;
    160         for(j=start; j<limit; j++) {
    161             if(IS_BIDI_CONTROL_CHAR(pParaBiDi->text[j])) {
    162                 pLineBiDi->controlCount++;
    163             }
    164         }
    165         pLineBiDi->resultLength-=pLineBiDi->controlCount;
    166     }
    167 
    168     pLineBiDi->dirProps=pParaBiDi->dirProps+start;
    169     pLineBiDi->levels=pParaBiDi->levels+start;
    170     pLineBiDi->runCount=-1;
    171 
    172     if(pParaBiDi->direction!=UBIDI_MIXED) {
    173         /* the parent is already trivial */
    174         pLineBiDi->direction=pParaBiDi->direction;
    175 
    176         /*
    177          * The parent's levels are all either
    178          * implicitly or explicitly ==paraLevel;
    179          * do the same here.
    180          */
    181         if(pParaBiDi->trailingWSStart<=start) {
    182             pLineBiDi->trailingWSStart=0;
    183         } else if(pParaBiDi->trailingWSStart<limit) {
    184             pLineBiDi->trailingWSStart=pParaBiDi->trailingWSStart-start;
    185         } else {
    186             pLineBiDi->trailingWSStart=length;
    187         }
    188     } else {
    189         const UBiDiLevel *levels=pLineBiDi->levels;
    190         int32_t i, trailingWSStart;
    191         UBiDiLevel level;
    192 
    193         setTrailingWSStart(pLineBiDi);
    194         trailingWSStart=pLineBiDi->trailingWSStart;
    195 
    196         /* recalculate pLineBiDi->direction */
    197         if(trailingWSStart==0) {
    198             /* all levels are at paraLevel */
    199             pLineBiDi->direction=(UBiDiDirection)(pLineBiDi->paraLevel&1);
    200         } else {
    201             /* get the level of the first character */
    202             level=(UBiDiLevel)(levels[0]&1);
    203 
    204             /* if there is anything of a different level, then the line is mixed */
    205             if(trailingWSStart<length && (pLineBiDi->paraLevel&1)!=level) {
    206                 /* the trailing WS is at paraLevel, which differs from levels[0] */
    207                 pLineBiDi->direction=UBIDI_MIXED;
    208             } else {
    209                 /* see if levels[1..trailingWSStart-1] have the same direction as levels[0] and paraLevel */
    210                 i=1;
    211                 for(;;) {
    212                     if(i==trailingWSStart) {
    213                         /* the direction values match those in level */
    214                         pLineBiDi->direction=(UBiDiDirection)level;
    215                         break;
    216                     } else if((levels[i]&1)!=level) {
    217                         pLineBiDi->direction=UBIDI_MIXED;
    218                         break;
    219                     }
    220                     ++i;
    221                 }
    222             }
    223         }
    224 
    225         switch(pLineBiDi->direction) {
    226         case UBIDI_LTR:
    227             /* make sure paraLevel is even */
    228             pLineBiDi->paraLevel=(UBiDiLevel)((pLineBiDi->paraLevel+1)&~1);
    229 
    230             /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
    231             pLineBiDi->trailingWSStart=0;
    232             break;
    233         case UBIDI_RTL:
    234             /* make sure paraLevel is odd */
    235             pLineBiDi->paraLevel|=1;
    236 
    237             /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
    238             pLineBiDi->trailingWSStart=0;
    239             break;
    240         default:
    241             break;
    242         }
    243     }
    244     pLineBiDi->pParaBiDi=pParaBiDi;     /* mark successful setLine */
    245     return;
    246 }
    247 
    248 U_CAPI UBiDiLevel U_EXPORT2
    249 ubidi_getLevelAt(const UBiDi *pBiDi, int32_t charIndex) {
    250     /* return paraLevel if in the trailing WS run, otherwise the real level */
    251     if(!IS_VALID_PARA_OR_LINE(pBiDi) || charIndex<0 || pBiDi->length<=charIndex) {
    252         return 0;
    253     } else if(pBiDi->direction!=UBIDI_MIXED || charIndex>=pBiDi->trailingWSStart) {
    254         return GET_PARALEVEL(pBiDi, charIndex);
    255     } else {
    256         return pBiDi->levels[charIndex];
    257     }
    258 }
    259 
    260 U_CAPI const UBiDiLevel * U_EXPORT2
    261 ubidi_getLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
    262     int32_t start, length;
    263 
    264     RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, NULL);
    265     RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, NULL);
    266     if((length=pBiDi->length)<=0) {
    267         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    268         return NULL;
    269     }
    270     if((start=pBiDi->trailingWSStart)==length) {
    271         /* the current levels array reflects the WS run */
    272         return pBiDi->levels;
    273     }
    274 
    275     /*
    276      * After the previous if(), we know that the levels array
    277      * has an implicit trailing WS run and therefore does not fully
    278      * reflect itself all the levels.
    279      * This must be a UBiDi object for a line, and
    280      * we need to create a new levels array.
    281      */
    282     if(getLevelsMemory(pBiDi, length)) {
    283         UBiDiLevel *levels=pBiDi->levelsMemory;
    284 
    285         if(start>0 && levels!=pBiDi->levels) {
    286             uprv_memcpy(levels, pBiDi->levels, start);
    287         }
    288         /* pBiDi->paraLevel is ok even if contextual multiple paragraphs,
    289            since pBidi is a line object                                     */
    290         uprv_memset(levels+start, pBiDi->paraLevel, length-start);
    291 
    292         /* this new levels array is set for the line and reflects the WS run */
    293         pBiDi->trailingWSStart=length;
    294         return pBiDi->levels=levels;
    295     } else {
    296         /* out of memory */
    297         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    298         return NULL;
    299     }
    300 }
    301 
    302 U_CAPI void U_EXPORT2
    303 ubidi_getLogicalRun(const UBiDi *pBiDi, int32_t logicalPosition,
    304                     int32_t *pLogicalLimit, UBiDiLevel *pLevel) {
    305     UErrorCode errorCode;
    306     int32_t runCount, visualStart, logicalLimit, logicalFirst, i;
    307     Run iRun;
    308 
    309     errorCode=U_ZERO_ERROR;
    310     RETURN_VOID_IF_BAD_RANGE(logicalPosition, 0, pBiDi->length, errorCode);
    311     /* ubidi_countRuns will check VALID_PARA_OR_LINE */
    312     runCount=ubidi_countRuns((UBiDi *)pBiDi, &errorCode);
    313     if(U_FAILURE(errorCode)) {
    314         return;
    315     }
    316     /* this is done based on runs rather than on levels since levels have
    317        a special interpretation when UBIDI_REORDER_RUNS_ONLY
    318      */
    319     visualStart=logicalLimit=0;
    320     iRun=pBiDi->runs[0];
    321 
    322     for(i=0; i<runCount; i++) {
    323         iRun = pBiDi->runs[i];
    324         logicalFirst=GET_INDEX(iRun.logicalStart);
    325         logicalLimit=logicalFirst+iRun.visualLimit-visualStart;
    326         if((logicalPosition>=logicalFirst) &&
    327            (logicalPosition<logicalLimit)) {
    328             break;
    329         }
    330         visualStart = iRun.visualLimit;
    331     }
    332     if(pLogicalLimit) {
    333         *pLogicalLimit=logicalLimit;
    334     }
    335     if(pLevel) {
    336         if(pBiDi->reorderingMode==UBIDI_REORDER_RUNS_ONLY) {
    337             *pLevel=(UBiDiLevel)GET_ODD_BIT(iRun.logicalStart);
    338         }
    339         else if(pBiDi->direction!=UBIDI_MIXED || logicalPosition>=pBiDi->trailingWSStart) {
    340             *pLevel=GET_PARALEVEL(pBiDi, logicalPosition);
    341         } else {
    342         *pLevel=pBiDi->levels[logicalPosition];
    343         }
    344     }
    345 }
    346 
    347 /* runs API functions ------------------------------------------------------- */
    348 
    349 U_CAPI int32_t U_EXPORT2
    350 ubidi_countRuns(UBiDi *pBiDi, UErrorCode *pErrorCode) {
    351     RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
    352     RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
    353     ubidi_getRuns(pBiDi, pErrorCode);
    354     if(U_FAILURE(*pErrorCode)) {
    355         return -1;
    356     }
    357     return pBiDi->runCount;
    358 }
    359 
    360 U_CAPI UBiDiDirection U_EXPORT2
    361 ubidi_getVisualRun(UBiDi *pBiDi, int32_t runIndex,
    362                    int32_t *pLogicalStart, int32_t *pLength)
    363 {
    364     int32_t start;
    365     UErrorCode errorCode = U_ZERO_ERROR;
    366     RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, errorCode, UBIDI_LTR);
    367     ubidi_getRuns(pBiDi, &errorCode);
    368     if(U_FAILURE(errorCode)) {
    369         return UBIDI_LTR;
    370     }
    371     RETURN_IF_BAD_RANGE(runIndex, 0, pBiDi->runCount, errorCode, UBIDI_LTR);
    372 
    373     start=pBiDi->runs[runIndex].logicalStart;
    374     if(pLogicalStart!=NULL) {
    375         *pLogicalStart=GET_INDEX(start);
    376     }
    377     if(pLength!=NULL) {
    378         if(runIndex>0) {
    379             *pLength=pBiDi->runs[runIndex].visualLimit-
    380                      pBiDi->runs[runIndex-1].visualLimit;
    381         } else {
    382             *pLength=pBiDi->runs[0].visualLimit;
    383         }
    384     }
    385     return (UBiDiDirection)GET_ODD_BIT(start);
    386 }
    387 
    388 /* in trivial cases there is only one trivial run; called by ubidi_getRuns() */
    389 static void
    390 getSingleRun(UBiDi *pBiDi, UBiDiLevel level) {
    391     /* simple, single-run case */
    392     pBiDi->runs=pBiDi->simpleRuns;
    393     pBiDi->runCount=1;
    394 
    395     /* fill and reorder the single run */
    396     pBiDi->runs[0].logicalStart=MAKE_INDEX_ODD_PAIR(0, level);
    397     pBiDi->runs[0].visualLimit=pBiDi->length;
    398     pBiDi->runs[0].insertRemove=0;
    399 }
    400 
    401 /* reorder the runs array (L2) ---------------------------------------------- */
    402 
    403 /*
    404  * Reorder the same-level runs in the runs array.
    405  * Here, runCount>1 and maxLevel>=minLevel>=paraLevel.
    406  * All the visualStart fields=logical start before reordering.
    407  * The "odd" bits are not set yet.
    408  *
    409  * Reordering with this data structure lends itself to some handy shortcuts:
    410  *
    411  * Since each run is moved but not modified, and since at the initial maxLevel
    412  * each sequence of same-level runs consists of only one run each, we
    413  * don't need to do anything there and can predecrement maxLevel.
    414  * In many simple cases, the reordering is thus done entirely in the
    415  * index mapping.
    416  * Also, reordering occurs only down to the lowest odd level that occurs,
    417  * which is minLevel|1. However, if the lowest level itself is odd, then
    418  * in the last reordering the sequence of the runs at this level or higher
    419  * will be all runs, and we don't need the elaborate loop to search for them.
    420  * This is covered by ++minLevel instead of minLevel|=1 followed
    421  * by an extra reorder-all after the reorder-some loop.
    422  * About a trailing WS run:
    423  * Such a run would need special treatment because its level is not
    424  * reflected in levels[] if this is not a paragraph object.
    425  * Instead, all characters from trailingWSStart on are implicitly at
    426  * paraLevel.
    427  * However, for all maxLevel>paraLevel, this run will never be reordered
    428  * and does not need to be taken into account. maxLevel==paraLevel is only reordered
    429  * if minLevel==paraLevel is odd, which is done in the extra segment.
    430  * This means that for the main reordering loop we don't need to consider
    431  * this run and can --runCount. If it is later part of the all-runs
    432  * reordering, then runCount is adjusted accordingly.
    433  */
    434 static void
    435 reorderLine(UBiDi *pBiDi, UBiDiLevel minLevel, UBiDiLevel maxLevel) {
    436     Run *runs, tempRun;
    437     UBiDiLevel *levels;
    438     int32_t firstRun, endRun, limitRun, runCount;
    439 
    440     /* nothing to do? */
    441     if(maxLevel<=(minLevel|1)) {
    442         return;
    443     }
    444 
    445     /*
    446      * Reorder only down to the lowest odd level
    447      * and reorder at an odd minLevel in a separate, simpler loop.
    448      * See comments above for why minLevel is always incremented.
    449      */
    450     ++minLevel;
    451 
    452     runs=pBiDi->runs;
    453     levels=pBiDi->levels;
    454     runCount=pBiDi->runCount;
    455 
    456     /* do not include the WS run at paraLevel<=old minLevel except in the simple loop */
    457     if(pBiDi->trailingWSStart<pBiDi->length) {
    458         --runCount;
    459     }
    460 
    461     while(--maxLevel>=minLevel) {
    462         firstRun=0;
    463 
    464         /* loop for all sequences of runs */
    465         for(;;) {
    466             /* look for a sequence of runs that are all at >=maxLevel */
    467             /* look for the first run of such a sequence */
    468             while(firstRun<runCount && levels[runs[firstRun].logicalStart]<maxLevel) {
    469                 ++firstRun;
    470             }
    471             if(firstRun>=runCount) {
    472                 break;  /* no more such runs */
    473             }
    474 
    475             /* look for the limit run of such a sequence (the run behind it) */
    476             for(limitRun=firstRun; ++limitRun<runCount && levels[runs[limitRun].logicalStart]>=maxLevel;) {}
    477 
    478             /* Swap the entire sequence of runs from firstRun to limitRun-1. */
    479             endRun=limitRun-1;
    480             while(firstRun<endRun) {
    481                 tempRun = runs[firstRun];
    482                 runs[firstRun]=runs[endRun];
    483                 runs[endRun]=tempRun;
    484                 ++firstRun;
    485                 --endRun;
    486             }
    487 
    488             if(limitRun==runCount) {
    489                 break;  /* no more such runs */
    490             } else {
    491                 firstRun=limitRun+1;
    492             }
    493         }
    494     }
    495 
    496     /* now do maxLevel==old minLevel (==odd!), see above */
    497     if(!(minLevel&1)) {
    498         firstRun=0;
    499 
    500         /* include the trailing WS run in this complete reordering */
    501         if(pBiDi->trailingWSStart==pBiDi->length) {
    502             --runCount;
    503         }
    504 
    505         /* Swap the entire sequence of all runs. (endRun==runCount) */
    506         while(firstRun<runCount) {
    507             tempRun=runs[firstRun];
    508             runs[firstRun]=runs[runCount];
    509             runs[runCount]=tempRun;
    510             ++firstRun;
    511             --runCount;
    512         }
    513     }
    514 }
    515 
    516 /* compute the runs array --------------------------------------------------- */
    517 
    518 static int32_t getRunFromLogicalIndex(UBiDi *pBiDi, int32_t logicalIndex, UErrorCode *pErrorCode) {
    519     Run *runs=pBiDi->runs;
    520     int32_t runCount=pBiDi->runCount, visualStart=0, i, length, logicalStart;
    521 
    522     for(i=0; i<runCount; i++) {
    523         length=runs[i].visualLimit-visualStart;
    524         logicalStart=GET_INDEX(runs[i].logicalStart);
    525         if((logicalIndex>=logicalStart) && (logicalIndex<(logicalStart+length))) {
    526             return i;
    527         }
    528         visualStart+=length;
    529     }
    530     /* we should never get here */
    531     U_ASSERT(FALSE);
    532     *pErrorCode = U_INVALID_STATE_ERROR;
    533     return 0;
    534 }
    535 
    536 /*
    537  * Compute the runs array from the levels array.
    538  * After ubidi_getRuns() returns TRUE, runCount is guaranteed to be >0
    539  * and the runs are reordered.
    540  * Odd-level runs have visualStart on their visual right edge and
    541  * they progress visually to the left.
    542  * If option UBIDI_OPTION_INSERT_MARKS is set, insertRemove will contain the
    543  * sum of appropriate LRM/RLM_BEFORE/AFTER flags.
    544  * If option UBIDI_OPTION_REMOVE_CONTROLS is set, insertRemove will contain the
    545  * negative number of BiDi control characters within this run.
    546  */
    547 U_CFUNC UBool
    548 ubidi_getRuns(UBiDi *pBiDi, UErrorCode *pErrorCode) {
    549     /*
    550      * This method returns immediately if the runs are already set. This
    551      * includes the case of length==0 (handled in setPara)..
    552      */
    553     if (pBiDi->runCount>=0) {
    554         return TRUE;
    555     }
    556 
    557     if(pBiDi->direction!=UBIDI_MIXED) {
    558         /* simple, single-run case - this covers length==0 */
    559         /* pBiDi->paraLevel is ok even for contextual multiple paragraphs */
    560         getSingleRun(pBiDi, pBiDi->paraLevel);
    561     } else /* UBIDI_MIXED, length>0 */ {
    562         /* mixed directionality */
    563         int32_t length=pBiDi->length, limit;
    564         UBiDiLevel *levels=pBiDi->levels;
    565         int32_t i, runCount;
    566         UBiDiLevel level=UBIDI_DEFAULT_LTR;   /* initialize with no valid level */
    567         /*
    568          * If there are WS characters at the end of the line
    569          * and the run preceding them has a level different from
    570          * paraLevel, then they will form their own run at paraLevel (L1).
    571          * Count them separately.
    572          * We need some special treatment for this in order to not
    573          * modify the levels array which a line UBiDi object shares
    574          * with its paragraph parent and its other line siblings.
    575          * In other words, for the trailing WS, it may be
    576          * levels[]!=paraLevel but we have to treat it like it were so.
    577          */
    578         limit=pBiDi->trailingWSStart;
    579         /* count the runs, there is at least one non-WS run, and limit>0 */
    580         runCount=0;
    581         for(i=0; i<limit; ++i) {
    582             /* increment runCount at the start of each run */
    583             if(levels[i]!=level) {
    584                 ++runCount;
    585                 level=levels[i];
    586             }
    587         }
    588 
    589         /*
    590          * We don't need to see if the last run can be merged with a trailing
    591          * WS run because setTrailingWSStart() would have done that.
    592          */
    593         if(runCount==1 && limit==length) {
    594             /* There is only one non-WS run and no trailing WS-run. */
    595             getSingleRun(pBiDi, levels[0]);
    596         } else /* runCount>1 || limit<length */ {
    597             /* allocate and set the runs */
    598             Run *runs;
    599             int32_t runIndex, start;
    600             UBiDiLevel minLevel=UBIDI_MAX_EXPLICIT_LEVEL+1, maxLevel=0;
    601 
    602             /* now, count a (non-mergeable) WS run */
    603             if(limit<length) {
    604                 ++runCount;
    605             }
    606 
    607             /* runCount>1 */
    608             if(getRunsMemory(pBiDi, runCount)) {
    609                 runs=pBiDi->runsMemory;
    610             } else {
    611                 return FALSE;
    612             }
    613 
    614             /* set the runs */
    615             /* FOOD FOR THOUGHT: this could be optimized, e.g.:
    616              * 464->444, 484->444, 575->555, 595->555
    617              * However, that would take longer. Check also how it would
    618              * interact with BiDi control removal and inserting Marks.
    619              */
    620             runIndex=0;
    621 
    622             /* search for the run limits and initialize visualLimit values with the run lengths */
    623             i=0;
    624             do {
    625                 /* prepare this run */
    626                 start=i;
    627                 level=levels[i];
    628                 if(level<minLevel) {
    629                     minLevel=level;
    630                 }
    631                 if(level>maxLevel) {
    632                     maxLevel=level;
    633                 }
    634 
    635                 /* look for the run limit */
    636                 while(++i<limit && levels[i]==level) {}
    637 
    638                 /* i is another run limit */
    639                 runs[runIndex].logicalStart=start;
    640                 runs[runIndex].visualLimit=i-start;
    641                 runs[runIndex].insertRemove=0;
    642                 ++runIndex;
    643             } while(i<limit);
    644 
    645             if(limit<length) {
    646                 /* there is a separate WS run */
    647                 runs[runIndex].logicalStart=limit;
    648                 runs[runIndex].visualLimit=length-limit;
    649                 /* For the trailing WS run, pBiDi->paraLevel is ok even
    650                    if contextual multiple paragraphs.                   */
    651                 if(pBiDi->paraLevel<minLevel) {
    652                     minLevel=pBiDi->paraLevel;
    653                 }
    654             }
    655 
    656             /* set the object fields */
    657             pBiDi->runs=runs;
    658             pBiDi->runCount=runCount;
    659 
    660             reorderLine(pBiDi, minLevel, maxLevel);
    661 
    662             /* now add the direction flags and adjust the visualLimit's to be just that */
    663             /* this loop will also handle the trailing WS run */
    664             limit=0;
    665             for(i=0; i<runCount; ++i) {
    666                 ADD_ODD_BIT_FROM_LEVEL(runs[i].logicalStart, levels[runs[i].logicalStart]);
    667                 limit+=runs[i].visualLimit;
    668                 runs[i].visualLimit=limit;
    669             }
    670 
    671             /* Set the "odd" bit for the trailing WS run. */
    672             /* For a RTL paragraph, it will be the *first* run in visual order. */
    673             /* For the trailing WS run, pBiDi->paraLevel is ok even if
    674                contextual multiple paragraphs.                          */
    675             if(runIndex<runCount) {
    676                 int32_t trailingRun = ((pBiDi->paraLevel & 1) != 0)? 0 : runIndex;
    677 
    678                 ADD_ODD_BIT_FROM_LEVEL(runs[trailingRun].logicalStart, pBiDi->paraLevel);
    679             }
    680         }
    681     }
    682 
    683     /* handle insert LRM/RLM BEFORE/AFTER run */
    684     if(pBiDi->insertPoints.size>0) {
    685         Point *point, *start=pBiDi->insertPoints.points,
    686                       *limit=start+pBiDi->insertPoints.size;
    687         int32_t runIndex;
    688         for(point=start; point<limit; point++) {
    689             runIndex=getRunFromLogicalIndex(pBiDi, point->pos, pErrorCode);
    690             pBiDi->runs[runIndex].insertRemove|=point->flag;
    691         }
    692     }
    693 
    694     /* handle remove BiDi control characters */
    695     if(pBiDi->controlCount>0) {
    696         int32_t runIndex;
    697         const UChar *start=pBiDi->text, *limit=start+pBiDi->length, *pu;
    698         for(pu=start; pu<limit; pu++) {
    699             if(IS_BIDI_CONTROL_CHAR(*pu)) {
    700                 runIndex=getRunFromLogicalIndex(pBiDi, (int32_t)(pu-start), pErrorCode);
    701                 pBiDi->runs[runIndex].insertRemove--;
    702             }
    703         }
    704     }
    705 
    706     return TRUE;
    707 }
    708 
    709 static UBool
    710 prepareReorder(const UBiDiLevel *levels, int32_t length,
    711                int32_t *indexMap,
    712                UBiDiLevel *pMinLevel, UBiDiLevel *pMaxLevel) {
    713     int32_t start;
    714     UBiDiLevel level, minLevel, maxLevel;
    715 
    716     if(levels==NULL || length<=0) {
    717         return FALSE;
    718     }
    719 
    720     /* determine minLevel and maxLevel */
    721     minLevel=UBIDI_MAX_EXPLICIT_LEVEL+1;
    722     maxLevel=0;
    723     for(start=length; start>0;) {
    724         level=levels[--start];
    725         if(level>UBIDI_MAX_EXPLICIT_LEVEL+1) {
    726             return FALSE;
    727         }
    728         if(level<minLevel) {
    729             minLevel=level;
    730         }
    731         if(level>maxLevel) {
    732             maxLevel=level;
    733         }
    734     }
    735     *pMinLevel=minLevel;
    736     *pMaxLevel=maxLevel;
    737 
    738     /* initialize the index map */
    739     for(start=length; start>0;) {
    740         --start;
    741         indexMap[start]=start;
    742     }
    743 
    744     return TRUE;
    745 }
    746 
    747 /* reorder a line based on a levels array (L2) ------------------------------ */
    748 
    749 U_CAPI void U_EXPORT2
    750 ubidi_reorderLogical(const UBiDiLevel *levels, int32_t length, int32_t *indexMap) {
    751     int32_t start, limit, sumOfSosEos;
    752     UBiDiLevel minLevel = 0, maxLevel = 0;
    753 
    754     if(indexMap==NULL || !prepareReorder(levels, length, indexMap, &minLevel, &maxLevel)) {
    755         return;
    756     }
    757 
    758     /* nothing to do? */
    759     if(minLevel==maxLevel && (minLevel&1)==0) {
    760         return;
    761     }
    762 
    763     /* reorder only down to the lowest odd level */
    764     minLevel|=1;
    765 
    766     /* loop maxLevel..minLevel */
    767     do {
    768         start=0;
    769 
    770         /* loop for all sequences of levels to reorder at the current maxLevel */
    771         for(;;) {
    772             /* look for a sequence of levels that are all at >=maxLevel */
    773             /* look for the first index of such a sequence */
    774             while(start<length && levels[start]<maxLevel) {
    775                 ++start;
    776             }
    777             if(start>=length) {
    778                 break;  /* no more such sequences */
    779             }
    780 
    781             /* look for the limit of such a sequence (the index behind it) */
    782             for(limit=start; ++limit<length && levels[limit]>=maxLevel;) {}
    783 
    784             /*
    785              * sos=start of sequence, eos=end of sequence
    786              *
    787              * The closed (inclusive) interval from sos to eos includes all the logical
    788              * and visual indexes within this sequence. They are logically and
    789              * visually contiguous and in the same range.
    790              *
    791              * For each run, the new visual index=sos+eos-old visual index;
    792              * we pre-add sos+eos into sumOfSosEos ->
    793              * new visual index=sumOfSosEos-old visual index;
    794              */
    795             sumOfSosEos=start+limit-1;
    796 
    797             /* reorder each index in the sequence */
    798             do {
    799                 indexMap[start]=sumOfSosEos-indexMap[start];
    800             } while(++start<limit);
    801 
    802             /* start==limit */
    803             if(limit==length) {
    804                 break;  /* no more such sequences */
    805             } else {
    806                 start=limit+1;
    807             }
    808         }
    809     } while(--maxLevel>=minLevel);
    810 }
    811 
    812 U_CAPI void U_EXPORT2
    813 ubidi_reorderVisual(const UBiDiLevel *levels, int32_t length, int32_t *indexMap) {
    814     int32_t start, end, limit, temp;
    815     UBiDiLevel minLevel = 0, maxLevel = 0;
    816 
    817     if(indexMap==NULL || !prepareReorder(levels, length, indexMap, &minLevel, &maxLevel)) {
    818         return;
    819     }
    820 
    821     /* nothing to do? */
    822     if(minLevel==maxLevel && (minLevel&1)==0) {
    823         return;
    824     }
    825 
    826     /* reorder only down to the lowest odd level */
    827     minLevel|=1;
    828 
    829     /* loop maxLevel..minLevel */
    830     do {
    831         start=0;
    832 
    833         /* loop for all sequences of levels to reorder at the current maxLevel */
    834         for(;;) {
    835             /* look for a sequence of levels that are all at >=maxLevel */
    836             /* look for the first index of such a sequence */
    837             while(start<length && levels[start]<maxLevel) {
    838                 ++start;
    839             }
    840             if(start>=length) {
    841                 break;  /* no more such runs */
    842             }
    843 
    844             /* look for the limit of such a sequence (the index behind it) */
    845             for(limit=start; ++limit<length && levels[limit]>=maxLevel;) {}
    846 
    847             /*
    848              * Swap the entire interval of indexes from start to limit-1.
    849              * We don't need to swap the levels for the purpose of this
    850              * algorithm: the sequence of levels that we look at does not
    851              * move anyway.
    852              */
    853             end=limit-1;
    854             while(start<end) {
    855                 temp=indexMap[start];
    856                 indexMap[start]=indexMap[end];
    857                 indexMap[end]=temp;
    858 
    859                 ++start;
    860                 --end;
    861             }
    862 
    863             if(limit==length) {
    864                 break;  /* no more such sequences */
    865             } else {
    866                 start=limit+1;
    867             }
    868         }
    869     } while(--maxLevel>=minLevel);
    870 }
    871 
    872 /* API functions for logical<->visual mapping ------------------------------- */
    873 
    874 U_CAPI int32_t U_EXPORT2
    875 ubidi_getVisualIndex(UBiDi *pBiDi, int32_t logicalIndex, UErrorCode *pErrorCode) {
    876     int32_t visualIndex=UBIDI_MAP_NOWHERE;
    877     RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
    878     RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
    879     RETURN_IF_BAD_RANGE(logicalIndex, 0, pBiDi->length, *pErrorCode, -1);
    880 
    881     /* we can do the trivial cases without the runs array */
    882     switch(pBiDi->direction) {
    883     case UBIDI_LTR:
    884         visualIndex=logicalIndex;
    885         break;
    886     case UBIDI_RTL:
    887         visualIndex=pBiDi->length-logicalIndex-1;
    888         break;
    889     default:
    890         if(!ubidi_getRuns(pBiDi, pErrorCode)) {
    891             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
    892             return -1;
    893         } else {
    894             Run *runs=pBiDi->runs;
    895             int32_t i, visualStart=0, offset, length;
    896 
    897             /* linear search for the run, search on the visual runs */
    898             for(i=0; i<pBiDi->runCount; ++i) {
    899                 length=runs[i].visualLimit-visualStart;
    900                 offset=logicalIndex-GET_INDEX(runs[i].logicalStart);
    901                 if(offset>=0 && offset<length) {
    902                     if(IS_EVEN_RUN(runs[i].logicalStart)) {
    903                         /* LTR */
    904                         visualIndex=visualStart+offset;
    905                     } else {
    906                         /* RTL */
    907                         visualIndex=visualStart+length-offset-1;
    908                     }
    909                     break;          /* exit for loop */
    910                 }
    911                 visualStart+=length;
    912             }
    913             if(i>=pBiDi->runCount) {
    914                 return UBIDI_MAP_NOWHERE;
    915             }
    916         }
    917     }
    918 
    919     if(pBiDi->insertPoints.size>0) {
    920         /* add the number of added marks until the calculated visual index */
    921         Run *runs=pBiDi->runs;
    922         int32_t i, length, insertRemove;
    923         int32_t visualStart=0, markFound=0;
    924         for(i=0; ; i++, visualStart+=length) {
    925             length=runs[i].visualLimit-visualStart;
    926             insertRemove=runs[i].insertRemove;
    927             if(insertRemove & (LRM_BEFORE|RLM_BEFORE)) {
    928                 markFound++;
    929             }
    930             /* is it the run containing the visual index? */
    931             if(visualIndex<runs[i].visualLimit) {
    932                 return visualIndex+markFound;
    933             }
    934             if(insertRemove & (LRM_AFTER|RLM_AFTER)) {
    935                 markFound++;
    936             }
    937         }
    938     }
    939     else if(pBiDi->controlCount>0) {
    940         /* subtract the number of controls until the calculated visual index */
    941         Run *runs=pBiDi->runs;
    942         int32_t i, j, start, limit, length, insertRemove;
    943         int32_t visualStart=0, controlFound=0;
    944         UChar uchar=pBiDi->text[logicalIndex];
    945         /* is the logical index pointing to a control ? */
    946         if(IS_BIDI_CONTROL_CHAR(uchar)) {
    947             return UBIDI_MAP_NOWHERE;
    948         }
    949         /* loop on runs */
    950         for(i=0; ; i++, visualStart+=length) {
    951             length=runs[i].visualLimit-visualStart;
    952             insertRemove=runs[i].insertRemove;
    953             /* calculated visual index is beyond this run? */
    954             if(visualIndex>=runs[i].visualLimit) {
    955                 controlFound-=insertRemove;
    956                 continue;
    957             }
    958             /* calculated visual index must be within current run */
    959             if(insertRemove==0) {
    960                 return visualIndex-controlFound;
    961             }
    962             if(IS_EVEN_RUN(runs[i].logicalStart)) {
    963                 /* LTR: check from run start to logical index */
    964                 start=runs[i].logicalStart;
    965                 limit=logicalIndex;
    966             } else {
    967                 /* RTL: check from logical index to run end */
    968                 start=logicalIndex+1;
    969                 limit=GET_INDEX(runs[i].logicalStart)+length;
    970             }
    971             for(j=start; j<limit; j++) {
    972                 uchar=pBiDi->text[j];
    973                 if(IS_BIDI_CONTROL_CHAR(uchar)) {
    974                     controlFound++;
    975                 }
    976             }
    977             return visualIndex-controlFound;
    978         }
    979     }
    980 
    981     return visualIndex;
    982 }
    983 
    984 U_CAPI int32_t U_EXPORT2
    985 ubidi_getLogicalIndex(UBiDi *pBiDi, int32_t visualIndex, UErrorCode *pErrorCode) {
    986     Run *runs;
    987     int32_t i, runCount, start;
    988     RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
    989     RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
    990     RETURN_IF_BAD_RANGE(visualIndex, 0, pBiDi->resultLength, *pErrorCode, -1);
    991     /* we can do the trivial cases without the runs array */
    992     if(pBiDi->insertPoints.size==0 && pBiDi->controlCount==0) {
    993         if(pBiDi->direction==UBIDI_LTR) {
    994             return visualIndex;
    995         }
    996         else if(pBiDi->direction==UBIDI_RTL) {
    997             return pBiDi->length-visualIndex-1;
    998         }
    999     }
   1000     if(!ubidi_getRuns(pBiDi, pErrorCode)) {
   1001         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
   1002         return -1;
   1003     }
   1004 
   1005     runs=pBiDi->runs;
   1006     runCount=pBiDi->runCount;
   1007     if(pBiDi->insertPoints.size>0) {
   1008         /* handle inserted LRM/RLM */
   1009         int32_t markFound=0, insertRemove;
   1010         int32_t visualStart=0, length;
   1011         runs=pBiDi->runs;
   1012         /* subtract number of marks until visual index */
   1013         for(i=0; ; i++, visualStart+=length) {
   1014             length=runs[i].visualLimit-visualStart;
   1015             insertRemove=runs[i].insertRemove;
   1016             if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
   1017                 if(visualIndex<=(visualStart+markFound)) {
   1018                     return UBIDI_MAP_NOWHERE;
   1019                 }
   1020                 markFound++;
   1021             }
   1022             /* is adjusted visual index within this run? */
   1023             if(visualIndex<(runs[i].visualLimit+markFound)) {
   1024                 visualIndex-=markFound;
   1025                 break;
   1026             }
   1027             if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
   1028                 if(visualIndex==(visualStart+length+markFound)) {
   1029                     return UBIDI_MAP_NOWHERE;
   1030                 }
   1031                 markFound++;
   1032             }
   1033         }
   1034     }
   1035     else if(pBiDi->controlCount>0) {
   1036         /* handle removed BiDi control characters */
   1037         int32_t controlFound=0, insertRemove, length;
   1038         int32_t logicalStart, logicalEnd, visualStart=0, j, k;
   1039         UChar uchar;
   1040         UBool evenRun;
   1041         /* add number of controls until visual index */
   1042         for(i=0; ; i++, visualStart+=length) {
   1043             length=runs[i].visualLimit-visualStart;
   1044             insertRemove=runs[i].insertRemove;
   1045             /* is adjusted visual index beyond current run? */
   1046             if(visualIndex>=(runs[i].visualLimit-controlFound+insertRemove)) {
   1047                 controlFound-=insertRemove;
   1048                 continue;
   1049             }
   1050             /* adjusted visual index is within current run */
   1051             if(insertRemove==0) {
   1052                 visualIndex+=controlFound;
   1053                 break;
   1054             }
   1055             /* count non-control chars until visualIndex */
   1056             logicalStart=runs[i].logicalStart;
   1057             evenRun=IS_EVEN_RUN(logicalStart);
   1058             REMOVE_ODD_BIT(logicalStart);
   1059             logicalEnd=logicalStart+length-1;
   1060             for(j=0; j<length; j++) {
   1061                 k= evenRun ? logicalStart+j : logicalEnd-j;
   1062                 uchar=pBiDi->text[k];
   1063                 if(IS_BIDI_CONTROL_CHAR(uchar)) {
   1064                     controlFound++;
   1065                 }
   1066                 if((visualIndex+controlFound)==(visualStart+j)) {
   1067                     break;
   1068                 }
   1069             }
   1070             visualIndex+=controlFound;
   1071             break;
   1072         }
   1073     }
   1074     /* handle all cases */
   1075     if(runCount<=10) {
   1076         /* linear search for the run */
   1077         for(i=0; visualIndex>=runs[i].visualLimit; ++i) {}
   1078     } else {
   1079         /* binary search for the run */
   1080         int32_t begin=0, limit=runCount;
   1081 
   1082         /* the middle if() is guaranteed to find the run, we don't need a loop limit */
   1083         for(;;) {
   1084             i=(begin+limit)/2;
   1085             if(visualIndex>=runs[i].visualLimit) {
   1086                 begin=i+1;
   1087             } else if(i==0 || visualIndex>=runs[i-1].visualLimit) {
   1088                 break;
   1089             } else {
   1090                 limit=i;
   1091             }
   1092         }
   1093     }
   1094 
   1095     start=runs[i].logicalStart;
   1096     if(IS_EVEN_RUN(start)) {
   1097         /* LTR */
   1098         /* the offset in runs[i] is visualIndex-runs[i-1].visualLimit */
   1099         if(i>0) {
   1100             visualIndex-=runs[i-1].visualLimit;
   1101         }
   1102         return start+visualIndex;
   1103     } else {
   1104         /* RTL */
   1105         return GET_INDEX(start)+runs[i].visualLimit-visualIndex-1;
   1106     }
   1107 }
   1108 
   1109 U_CAPI void U_EXPORT2
   1110 ubidi_getLogicalMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) {
   1111     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
   1112     /* ubidi_countRuns() checks for VALID_PARA_OR_LINE */
   1113     ubidi_countRuns(pBiDi, pErrorCode);
   1114     if(U_FAILURE(*pErrorCode)) {
   1115         /* no op */
   1116     } else if(indexMap==NULL) {
   1117         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   1118     } else {
   1119         /* fill a logical-to-visual index map using the runs[] */
   1120         int32_t visualStart, visualLimit, i, j, k;
   1121         int32_t logicalStart, logicalLimit;
   1122         Run *runs=pBiDi->runs;
   1123         if (pBiDi->length<=0) {
   1124             return;
   1125         }
   1126         if (pBiDi->length>pBiDi->resultLength) {
   1127             uprv_memset(indexMap, 0xFF, pBiDi->length*sizeof(int32_t));
   1128         }
   1129 
   1130         visualStart=0;
   1131         for(j=0; j<pBiDi->runCount; ++j) {
   1132             logicalStart=GET_INDEX(runs[j].logicalStart);
   1133             visualLimit=runs[j].visualLimit;
   1134             if(IS_EVEN_RUN(runs[j].logicalStart)) {
   1135                 do { /* LTR */
   1136                     indexMap[logicalStart++]=visualStart++;
   1137                 } while(visualStart<visualLimit);
   1138             } else {
   1139                 logicalStart+=visualLimit-visualStart;  /* logicalLimit */
   1140                 do { /* RTL */
   1141                     indexMap[--logicalStart]=visualStart++;
   1142                 } while(visualStart<visualLimit);
   1143             }
   1144             /* visualStart==visualLimit; */
   1145         }
   1146 
   1147         if(pBiDi->insertPoints.size>0) {
   1148             int32_t markFound=0, runCount=pBiDi->runCount;
   1149             int32_t length, insertRemove;
   1150             visualStart=0;
   1151             /* add number of marks found until each index */
   1152             for(i=0; i<runCount; i++, visualStart+=length) {
   1153                 length=runs[i].visualLimit-visualStart;
   1154                 insertRemove=runs[i].insertRemove;
   1155                 if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
   1156                     markFound++;
   1157                 }
   1158                 if(markFound>0) {
   1159                     logicalStart=GET_INDEX(runs[i].logicalStart);
   1160                     logicalLimit=logicalStart+length;
   1161                     for(j=logicalStart; j<logicalLimit; j++) {
   1162                         indexMap[j]+=markFound;
   1163                     }
   1164                 }
   1165                 if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
   1166                     markFound++;
   1167                 }
   1168             }
   1169         }
   1170         else if(pBiDi->controlCount>0) {
   1171             int32_t controlFound=0, runCount=pBiDi->runCount;
   1172             int32_t length, insertRemove;
   1173             UBool evenRun;
   1174             UChar uchar;
   1175             visualStart=0;
   1176             /* subtract number of controls found until each index */
   1177             for(i=0; i<runCount; i++, visualStart+=length) {
   1178                 length=runs[i].visualLimit-visualStart;
   1179                 insertRemove=runs[i].insertRemove;
   1180                 /* no control found within previous runs nor within this run */
   1181                 if((controlFound-insertRemove)==0) {
   1182                     continue;
   1183                 }
   1184                 logicalStart=runs[i].logicalStart;
   1185                 evenRun=IS_EVEN_RUN(logicalStart);
   1186                 REMOVE_ODD_BIT(logicalStart);
   1187                 logicalLimit=logicalStart+length;
   1188                 /* if no control within this run */
   1189                 if(insertRemove==0) {
   1190                     for(j=logicalStart; j<logicalLimit; j++) {
   1191                         indexMap[j]-=controlFound;
   1192                     }
   1193                     continue;
   1194                 }
   1195                 for(j=0; j<length; j++) {
   1196                     k= evenRun ? logicalStart+j : logicalLimit-j-1;
   1197                     uchar=pBiDi->text[k];
   1198                     if(IS_BIDI_CONTROL_CHAR(uchar)) {
   1199                         controlFound++;
   1200                         indexMap[k]=UBIDI_MAP_NOWHERE;
   1201                         continue;
   1202                     }
   1203                     indexMap[k]-=controlFound;
   1204                 }
   1205             }
   1206         }
   1207     }
   1208 }
   1209 
   1210 U_CAPI void U_EXPORT2
   1211 ubidi_getVisualMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) {
   1212     RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
   1213     if(indexMap==NULL) {
   1214         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   1215         return;
   1216     }
   1217     /* ubidi_countRuns() checks for VALID_PARA_OR_LINE */
   1218     ubidi_countRuns(pBiDi, pErrorCode);
   1219     if(U_SUCCESS(*pErrorCode)) {
   1220         /* fill a visual-to-logical index map using the runs[] */
   1221         Run *runs=pBiDi->runs, *runsLimit=runs+pBiDi->runCount;
   1222         int32_t logicalStart, visualStart, visualLimit, *pi=indexMap;
   1223 
   1224         if (pBiDi->resultLength<=0) {
   1225             return;
   1226         }
   1227         visualStart=0;
   1228         for(; runs<runsLimit; ++runs) {
   1229             logicalStart=runs->logicalStart;
   1230             visualLimit=runs->visualLimit;
   1231             if(IS_EVEN_RUN(logicalStart)) {
   1232                 do { /* LTR */
   1233                     *pi++ = logicalStart++;
   1234                 } while(++visualStart<visualLimit);
   1235             } else {
   1236                 REMOVE_ODD_BIT(logicalStart);
   1237                 logicalStart+=visualLimit-visualStart;  /* logicalLimit */
   1238                 do { /* RTL */
   1239                     *pi++ = --logicalStart;
   1240                 } while(++visualStart<visualLimit);
   1241             }
   1242             /* visualStart==visualLimit; */
   1243         }
   1244 
   1245         if(pBiDi->insertPoints.size>0) {
   1246             int32_t markFound=0, runCount=pBiDi->runCount;
   1247             int32_t insertRemove, i, j, k;
   1248             runs=pBiDi->runs;
   1249             /* count all inserted marks */
   1250             for(i=0; i<runCount; i++) {
   1251                 insertRemove=runs[i].insertRemove;
   1252                 if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
   1253                     markFound++;
   1254                 }
   1255                 if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
   1256                     markFound++;
   1257                 }
   1258             }
   1259             /* move back indexes by number of preceding marks */
   1260             k=pBiDi->resultLength;
   1261             for(i=runCount-1; i>=0 && markFound>0; i--) {
   1262                 insertRemove=runs[i].insertRemove;
   1263                 if(insertRemove&(LRM_AFTER|RLM_AFTER)) {
   1264                     indexMap[--k]= UBIDI_MAP_NOWHERE;
   1265                     markFound--;
   1266                 }
   1267                 visualStart= i>0 ? runs[i-1].visualLimit : 0;
   1268                 for(j=runs[i].visualLimit-1; j>=visualStart && markFound>0; j--) {
   1269                     indexMap[--k]=indexMap[j];
   1270                 }
   1271                 if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) {
   1272                     indexMap[--k]= UBIDI_MAP_NOWHERE;
   1273                     markFound--;
   1274                 }
   1275             }
   1276         }
   1277         else if(pBiDi->controlCount>0) {
   1278             int32_t runCount=pBiDi->runCount, logicalEnd;
   1279             int32_t insertRemove, length, i, j, k, m;
   1280             UChar uchar;
   1281             UBool evenRun;
   1282             runs=pBiDi->runs;
   1283             visualStart=0;
   1284             /* move forward indexes by number of preceding controls */
   1285             k=0;
   1286             for(i=0; i<runCount; i++, visualStart+=length) {
   1287                 length=runs[i].visualLimit-visualStart;
   1288                 insertRemove=runs[i].insertRemove;
   1289                 /* if no control found yet, nothing to do in this run */
   1290                 if((insertRemove==0)&&(k==visualStart)) {
   1291                     k+=length;
   1292                     continue;
   1293                 }
   1294                 /* if no control in this run */
   1295                 if(insertRemove==0) {
   1296                     visualLimit=runs[i].visualLimit;
   1297                     for(j=visualStart; j<visualLimit; j++) {
   1298                         indexMap[k++]=indexMap[j];
   1299                     }
   1300                     continue;
   1301                 }
   1302                 logicalStart=runs[i].logicalStart;
   1303                 evenRun=IS_EVEN_RUN(logicalStart);
   1304                 REMOVE_ODD_BIT(logicalStart);
   1305                 logicalEnd=logicalStart+length-1;
   1306                 for(j=0; j<length; j++) {
   1307                     m= evenRun ? logicalStart+j : logicalEnd-j;
   1308                     uchar=pBiDi->text[m];
   1309                     if(!IS_BIDI_CONTROL_CHAR(uchar)) {
   1310                         indexMap[k++]=m;
   1311                     }
   1312                 }
   1313             }
   1314         }
   1315     }
   1316 }
   1317 
   1318 U_CAPI void U_EXPORT2
   1319 ubidi_invertMap(const int32_t *srcMap, int32_t *destMap, int32_t length) {
   1320     if(srcMap!=NULL && destMap!=NULL && length>0) {
   1321         const int32_t *pi;
   1322         int32_t destLength=-1, count=0;
   1323         /* find highest value and count positive indexes in srcMap */
   1324         pi=srcMap+length;
   1325         while(pi>srcMap) {
   1326             if(*--pi>destLength) {
   1327                 destLength=*pi;
   1328             }
   1329             if(*pi>=0) {
   1330                 count++;
   1331             }
   1332         }
   1333         destLength++;           /* add 1 for origin 0 */
   1334         if(count<destLength) {
   1335             /* we must fill unmatched destMap entries with -1 */
   1336             uprv_memset(destMap, 0xFF, destLength*sizeof(int32_t));
   1337         }
   1338         pi=srcMap+length;
   1339         while(length>0) {
   1340             if(*--pi>=0) {
   1341                 destMap[*pi]=--length;
   1342             } else {
   1343                 --length;
   1344             }
   1345         }
   1346     }
   1347 }
   1348