• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
setTrailingWSStart(UBiDi * pBiDi)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
ubidi_setLine(const UBiDi * pParaBiDi,int32_t start,int32_t limit,UBiDi * pLineBiDi,UErrorCode * pErrorCode)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
ubidi_getLevelAt(const UBiDi * pBiDi,int32_t charIndex)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
ubidi_getLevels(UBiDi * pBiDi,UErrorCode * pErrorCode)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
ubidi_getLogicalRun(const UBiDi * pBiDi,int32_t logicalPosition,int32_t * pLogicalLimit,UBiDiLevel * pLevel)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
ubidi_countRuns(UBiDi * pBiDi,UErrorCode * pErrorCode)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
ubidi_getVisualRun(UBiDi * pBiDi,int32_t runIndex,int32_t * pLogicalStart,int32_t * pLength)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
getSingleRun(UBiDi * pBiDi,UBiDiLevel level)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
reorderLine(UBiDi * pBiDi,UBiDiLevel minLevel,UBiDiLevel maxLevel)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 
getRunFromLogicalIndex(UBiDi * pBiDi,int32_t logicalIndex,UErrorCode * pErrorCode)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
ubidi_getRuns(UBiDi * pBiDi,UErrorCode * pErrorCode)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
prepareReorder(const UBiDiLevel * levels,int32_t length,int32_t * indexMap,UBiDiLevel * pMinLevel,UBiDiLevel * pMaxLevel)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
ubidi_reorderLogical(const UBiDiLevel * levels,int32_t length,int32_t * indexMap)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
ubidi_reorderVisual(const UBiDiLevel * levels,int32_t length,int32_t * indexMap)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
ubidi_getVisualIndex(UBiDi * pBiDi,int32_t logicalIndex,UErrorCode * pErrorCode)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
ubidi_getLogicalIndex(UBiDi * pBiDi,int32_t visualIndex,UErrorCode * pErrorCode)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
ubidi_getLogicalMap(UBiDi * pBiDi,int32_t * indexMap,UErrorCode * pErrorCode)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
ubidi_getVisualMap(UBiDi * pBiDi,int32_t * indexMap,UErrorCode * pErrorCode)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
ubidi_invertMap(const int32_t * srcMap,int32_t * destMap,int32_t length)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