LCOV - code coverage report
Current view: top level - intl/icu/source/common - ubidiln.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 615 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13