2 ******************************************************************************
4 * Copyright (C) 1999-2003, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
10 * tab size: 8 (not used)
13 * created on: 1999aug06
14 * created by: Markus W. Scherer
17 /* set import/export definitions */
18 #ifndef U_COMMON_IMPLEMENTATION
19 # define U_COMMON_IMPLEMENTATION
23 #include "unicode/utypes.h"
24 #include "unicode/ustring.h"
25 #include "unicode/uchar.h"
26 #include "unicode/ubidi.h"
30 * General remarks about the functions in this file:
32 * These functions deal with the aspects of potentially mixed-directional
33 * text in a single paragraph or in a line of a single paragraph
34 * which has already been processed according to
35 * the Unicode 3.0 BiDi algorithm as defined in
36 * http://www.unicode.org/unicode/reports/tr9/ , version 5,
37 * also described in The Unicode Standard, Version 3.0 .
39 * This means that there is a UBiDi object with a levels
40 * and a dirProps array.
41 * paraLevel and direction are also set.
42 * Only if the length of the text is zero, then levels==dirProps==NULL.
44 * The overall directionality of the paragraph
45 * or line is used to bypass the reordering steps if possible.
46 * Even purely RTL text does not need reordering there because
47 * the ubidi_getLogical/VisualIndex() functions can compute the
48 * index on the fly in such a case.
50 * The implementation of the access to same-level-runs and of the reordering
51 * do attempt to provide better performance and less memory usage compared to
52 * a direct implementation of especially rule (L2) with an array of
53 * one (32-bit) integer per text character.
55 * Here, the levels array is scanned as soon as necessary, and a vector of
56 * same-level-runs is created. Reordering then is done on this vector.
57 * For each run of text positions that were resolved to the same level,
58 * only 8 bytes are stored: the first text position of the run and the visual
59 * position behind the run after reordering.
60 * One sign bit is used to hold the directionality of the run.
61 * This is inefficient if there are many very short runs. If the average run
62 * length is <2, then this uses more memory.
64 * In a further attempt to save memory, the levels array is never changed
65 * after all the resolution rules (Xn, Wn, Nn, In).
66 * Many functions have to consider the field trailingWSStart:
67 * if it is less than length, then there is an implicit trailing run
69 * which is not reflected in the levels array.
70 * This allows a line UBiDi object to use the same levels array as
71 * its paragraph parent object.
73 * When a UBiDi object is created for a line of a paragraph, then the
74 * paragraph's levels and dirProps arrays are reused by way of setting
75 * a pointer into them, not by copying. This again saves memory and forbids to
76 * change the now shared levels for (L1).
79 /* handle trailing WS (L1) -------------------------------------------------- */
82 * setTrailingWSStart() sets the start index for a trailing
83 * run of WS in the line. This is necessary because we do not modify
84 * the paragraph's levels array that we just point into.
85 * Using trailingWSStart is another form of performing (L1).
87 * To make subsequent operations easier, we also include the run
88 * before the WS if it is at the paraLevel - we merge the two here.
91 setTrailingWSStart(UBiDi
*pBiDi
) {
92 /* pBiDi->direction!=UBIDI_MIXED */
94 const DirProp
*dirProps
=pBiDi
->dirProps
;
95 UBiDiLevel
*levels
=pBiDi
->levels
;
96 int32_t start
=pBiDi
->length
;
97 UBiDiLevel paraLevel
=pBiDi
->paraLevel
;
99 /* go backwards across all WS, BN, explicit codes */
100 while(start
>0 && DIRPROP_FLAG(dirProps
[start
-1])&MASK_WS
) {
104 /* if the WS run can be merged with the previous run then do so here */
105 while(start
>0 && levels
[start
-1]==paraLevel
) {
109 pBiDi
->trailingWSStart
=start
;
112 /* ubidi_setLine ------------------------------------------------------------ */
114 U_CAPI
void U_EXPORT2
115 ubidi_setLine(const UBiDi
*pParaBiDi
,
116 int32_t start
, int32_t limit
,
118 UErrorCode
*pErrorCode
) {
121 /* check the argument values */
122 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
124 } else if(pParaBiDi
==NULL
|| pLineBiDi
==NULL
) {
125 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
127 } else if(start
<0 || start
>limit
|| limit
>pParaBiDi
->length
) {
128 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
132 /* set the values in pLineBiDi from its pParaBiDi parent */
133 pLineBiDi
->text
=pParaBiDi
->text
+start
;
134 length
=pLineBiDi
->length
=limit
-start
;
135 pLineBiDi
->paraLevel
=pParaBiDi
->paraLevel
;
137 pLineBiDi
->runs
=NULL
;
141 pLineBiDi
->dirProps
=pParaBiDi
->dirProps
+start
;
142 pLineBiDi
->levels
=pParaBiDi
->levels
+start
;
143 pLineBiDi
->runCount
=-1;
145 if(pParaBiDi
->direction
!=UBIDI_MIXED
) {
146 /* the parent is already trivial */
147 pLineBiDi
->direction
=pParaBiDi
->direction
;
150 * The parent's levels are all either
151 * implicitly or explicitly ==paraLevel;
154 if(pParaBiDi
->trailingWSStart
<=start
) {
155 pLineBiDi
->trailingWSStart
=0;
156 } else if(pParaBiDi
->trailingWSStart
<limit
) {
157 pLineBiDi
->trailingWSStart
=pParaBiDi
->trailingWSStart
-start
;
159 pLineBiDi
->trailingWSStart
=length
;
162 const UBiDiLevel
*levels
=pLineBiDi
->levels
;
163 int32_t i
, trailingWSStart
;
166 setTrailingWSStart(pLineBiDi
);
167 trailingWSStart
=pLineBiDi
->trailingWSStart
;
169 /* recalculate pLineBiDi->direction */
170 if(trailingWSStart
==0) {
171 /* all levels are at paraLevel */
172 pLineBiDi
->direction
=(UBiDiDirection
)(pLineBiDi
->paraLevel
&1);
174 /* get the level of the first character */
175 level
=(UBiDiLevel
)(levels
[0]&1);
177 /* if there is anything of a different level, then the line is mixed */
178 if(trailingWSStart
<length
&& (pLineBiDi
->paraLevel
&1)!=level
) {
179 /* the trailing WS is at paraLevel, which differs from levels[0] */
180 pLineBiDi
->direction
=UBIDI_MIXED
;
182 /* see if levels[1..trailingWSStart-1] have the same direction as levels[0] and paraLevel */
185 if(i
==trailingWSStart
) {
186 /* the direction values match those in level */
187 pLineBiDi
->direction
=(UBiDiDirection
)level
;
189 } else if((levels
[i
]&1)!=level
) {
190 pLineBiDi
->direction
=UBIDI_MIXED
;
198 switch(pLineBiDi
->direction
) {
200 /* make sure paraLevel is even */
201 pLineBiDi
->paraLevel
=(UBiDiLevel
)((pLineBiDi
->paraLevel
+1)&~1);
203 /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
204 pLineBiDi
->trailingWSStart
=0;
207 /* make sure paraLevel is odd */
208 pLineBiDi
->paraLevel
|=1;
210 /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
211 pLineBiDi
->trailingWSStart
=0;
218 /* create an object for a zero-length line */
219 pLineBiDi
->direction
=pLineBiDi
->paraLevel
&1 ? UBIDI_RTL
: UBIDI_LTR
;
220 pLineBiDi
->trailingWSStart
=pLineBiDi
->runCount
=0;
222 pLineBiDi
->dirProps
=NULL
;
223 pLineBiDi
->levels
=NULL
;
228 U_CAPI UBiDiLevel U_EXPORT2
229 ubidi_getLevelAt(const UBiDi
*pBiDi
, int32_t charIndex
) {
230 /* return paraLevel if in the trailing WS run, otherwise the real level */
231 if(pBiDi
==NULL
|| charIndex
<0 || pBiDi
->length
<=charIndex
) {
233 } else if(pBiDi
->direction
!=UBIDI_MIXED
|| charIndex
>=pBiDi
->trailingWSStart
) {
234 return pBiDi
->paraLevel
;
236 return pBiDi
->levels
[charIndex
];
240 U_CAPI
const UBiDiLevel
* U_EXPORT2
241 ubidi_getLevels(UBiDi
*pBiDi
, UErrorCode
*pErrorCode
) {
242 int32_t start
, length
;
244 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
246 } else if(pBiDi
==NULL
|| (length
=pBiDi
->length
)<=0) {
247 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
251 if((start
=pBiDi
->trailingWSStart
)==length
) {
252 /* the current levels array reflects the WS run */
253 return pBiDi
->levels
;
257 * After the previous if(), we know that the levels array
258 * has an implicit trailing WS run and therefore does not fully
259 * reflect itself all the levels.
260 * This must be a UBiDi object for a line, and
261 * we need to create a new levels array.
264 if(getLevelsMemory(pBiDi
, length
)) {
265 UBiDiLevel
*levels
=pBiDi
->levelsMemory
;
267 if(start
>0 && levels
!=pBiDi
->levels
) {
268 uprv_memcpy(levels
, pBiDi
->levels
, start
);
270 uprv_memset(levels
+start
, pBiDi
->paraLevel
, length
-start
);
272 /* this new levels array is set for the line and reflects the WS run */
273 pBiDi
->trailingWSStart
=length
;
274 return pBiDi
->levels
=levels
;
277 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
282 U_CAPI
void U_EXPORT2
283 ubidi_getLogicalRun(const UBiDi
*pBiDi
, int32_t logicalStart
,
284 int32_t *pLogicalLimit
, UBiDiLevel
*pLevel
) {
287 if(pBiDi
==NULL
|| logicalStart
<0 || (length
=pBiDi
->length
)<=logicalStart
) {
291 if(pBiDi
->direction
!=UBIDI_MIXED
|| logicalStart
>=pBiDi
->trailingWSStart
) {
292 if(pLogicalLimit
!=NULL
) {
293 *pLogicalLimit
=length
;
296 *pLevel
=pBiDi
->paraLevel
;
299 UBiDiLevel
*levels
=pBiDi
->levels
;
300 UBiDiLevel level
=levels
[logicalStart
];
302 /* search for the end of the run */
303 length
=pBiDi
->trailingWSStart
;
304 while(++logicalStart
<length
&& level
==levels
[logicalStart
]) {}
306 if(pLogicalLimit
!=NULL
) {
307 *pLogicalLimit
=logicalStart
;
315 /* runs API functions ------------------------------------------------------- */
317 U_CAPI
int32_t U_EXPORT2
318 ubidi_countRuns(UBiDi
*pBiDi
, UErrorCode
*pErrorCode
) {
319 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
321 } else if(pBiDi
==NULL
|| (pBiDi
->runCount
<0 && !ubidi_getRuns(pBiDi
))) {
322 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
325 return pBiDi
->runCount
;
329 U_CAPI UBiDiDirection U_EXPORT2
330 ubidi_getVisualRun(UBiDi
*pBiDi
, int32_t runIndex
,
331 int32_t *pLogicalStart
, int32_t *pLength
) {
332 if( pBiDi
==NULL
|| runIndex
<0 ||
333 (pBiDi
->runCount
==-1 && !ubidi_getRuns(pBiDi
)) ||
334 runIndex
>=pBiDi
->runCount
338 int32_t start
=pBiDi
->runs
[runIndex
].logicalStart
;
339 if(pLogicalStart
!=NULL
) {
340 *pLogicalStart
=GET_INDEX(start
);
344 *pLength
=pBiDi
->runs
[runIndex
].visualLimit
-
345 pBiDi
->runs
[runIndex
-1].visualLimit
;
347 *pLength
=pBiDi
->runs
[0].visualLimit
;
350 return (UBiDiDirection
)GET_ODD_BIT(start
);
354 /* in trivial cases there is only one trivial run; called by ubidi_getRuns() */
356 getSingleRun(UBiDi
*pBiDi
, UBiDiLevel level
) {
357 /* simple, single-run case */
358 pBiDi
->runs
=pBiDi
->simpleRuns
;
361 /* fill and reorder the single run */
362 pBiDi
->runs
[0].logicalStart
=MAKE_INDEX_ODD_PAIR(0, level
);
363 pBiDi
->runs
[0].visualLimit
=pBiDi
->length
;
366 /* reorder the runs array (L2) ---------------------------------------------- */
369 * Reorder the same-level runs in the runs array.
370 * Here, runCount>1 and maxLevel>=minLevel>=paraLevel.
371 * All the visualStart fields=logical start before reordering.
372 * The "odd" bits are not set yet.
374 * Reordering with this data structure lends itself to some handy shortcuts:
376 * Since each run is moved but not modified, and since at the initial maxLevel
377 * each sequence of same-level runs consists of only one run each, we
378 * don't need to do anything there and can predecrement maxLevel.
379 * In many simple cases, the reordering is thus done entirely in the
381 * Also, reordering occurs only down to the lowest odd level that occurs,
382 * which is minLevel|1. However, if the lowest level itself is odd, then
383 * in the last reordering the sequence of the runs at this level or higher
384 * will be all runs, and we don't need the elaborate loop to search for them.
385 * This is covered by ++minLevel instead of minLevel|=1 followed
386 * by an extra reorder-all after the reorder-some loop.
387 * About a trailing WS run:
388 * Such a run would need special treatment because its level is not
389 * reflected in levels[] if this is not a paragraph object.
390 * Instead, all characters from trailingWSStart on are implicitly at
392 * However, for all maxLevel>paraLevel, this run will never be reordered
393 * and does not need to be taken into account. maxLevel==paraLevel is only reordered
394 * if minLevel==paraLevel is odd, which is done in the extra segment.
395 * This means that for the main reordering loop we don't need to consider
396 * this run and can --runCount. If it is later part of the all-runs
397 * reordering, then runCount is adjusted accordingly.
400 reorderLine(UBiDi
*pBiDi
, UBiDiLevel minLevel
, UBiDiLevel maxLevel
) {
403 int32_t firstRun
, endRun
, limitRun
, runCount
,
407 if(maxLevel
<=(minLevel
|1)) {
412 * Reorder only down to the lowest odd level
413 * and reorder at an odd minLevel in a separate, simpler loop.
414 * See comments above for why minLevel is always incremented.
419 levels
=pBiDi
->levels
;
420 runCount
=pBiDi
->runCount
;
422 /* do not include the WS run at paraLevel<=old minLevel except in the simple loop */
423 if(pBiDi
->trailingWSStart
<pBiDi
->length
) {
427 while(--maxLevel
>=minLevel
) {
430 /* loop for all sequences of runs */
432 /* look for a sequence of runs that are all at >=maxLevel */
433 /* look for the first run of such a sequence */
434 while(firstRun
<runCount
&& levels
[runs
[firstRun
].logicalStart
]<maxLevel
) {
437 if(firstRun
>=runCount
) {
438 break; /* no more such runs */
441 /* look for the limit run of such a sequence (the run behind it) */
442 for(limitRun
=firstRun
; ++limitRun
<runCount
&& levels
[runs
[limitRun
].logicalStart
]>=maxLevel
;) {}
444 /* Swap the entire sequence of runs from firstRun to limitRun-1. */
446 while(firstRun
<endRun
) {
447 temp
=runs
[firstRun
].logicalStart
;
448 runs
[firstRun
].logicalStart
=runs
[endRun
].logicalStart
;
449 runs
[endRun
].logicalStart
=temp
;
451 temp
=runs
[firstRun
].visualLimit
;
452 runs
[firstRun
].visualLimit
=runs
[endRun
].visualLimit
;
453 runs
[endRun
].visualLimit
=temp
;
459 if(limitRun
==runCount
) {
460 break; /* no more such runs */
467 /* now do maxLevel==old minLevel (==odd!), see above */
471 /* include the trailing WS run in this complete reordering */
472 if(pBiDi
->trailingWSStart
==pBiDi
->length
) {
476 /* Swap the entire sequence of all runs. (endRun==runCount) */
477 while(firstRun
<runCount
) {
478 temp
=runs
[firstRun
].logicalStart
;
479 runs
[firstRun
].logicalStart
=runs
[runCount
].logicalStart
;
480 runs
[runCount
].logicalStart
=temp
;
482 temp
=runs
[firstRun
].visualLimit
;
483 runs
[firstRun
].visualLimit
=runs
[runCount
].visualLimit
;
484 runs
[runCount
].visualLimit
=temp
;
492 /* compute the runs array --------------------------------------------------- */
495 * Compute the runs array from the levels array.
496 * After ubidi_getRuns() returns TRUE, runCount is guaranteed to be >0
497 * and the runs are reordered.
498 * Odd-level runs have visualStart on their visual right edge and
499 * they progress visually to the left.
502 ubidi_getRuns(UBiDi
*pBiDi
) {
503 if(pBiDi
->direction
!=UBIDI_MIXED
) {
504 /* simple, single-run case - this covers length==0 */
505 getSingleRun(pBiDi
, pBiDi
->paraLevel
);
506 } else /* UBIDI_MIXED, length>0 */ {
507 /* mixed directionality */
508 int32_t length
=pBiDi
->length
, limit
;
511 * If there are WS characters at the end of the line
512 * and the run preceding them has a level different from
513 * paraLevel, then they will form their own run at paraLevel (L1).
514 * Count them separately.
515 * We need some special treatment for this in order to not
516 * modify the levels array which a line UBiDi object shares
517 * with its paragraph parent and its other line siblings.
518 * In other words, for the trailing WS, it may be
519 * levels[]!=paraLevel but we have to treat it like it were so.
521 limit
=pBiDi
->trailingWSStart
;
523 /* there is only WS on this line */
524 getSingleRun(pBiDi
, pBiDi
->paraLevel
);
526 UBiDiLevel
*levels
=pBiDi
->levels
;
528 UBiDiLevel level
=UBIDI_DEFAULT_LTR
; /* initialize with no valid level */
530 /* count the runs, there is at least one non-WS run, and limit>0 */
532 for(i
=0; i
<limit
; ++i
) {
533 /* increment runCount at the start of each run */
534 if(levels
[i
]!=level
) {
541 * We don't need to see if the last run can be merged with a trailing
542 * WS run because setTrailingWSStart() would have done that.
544 if(runCount
==1 && limit
==length
) {
545 /* There is only one non-WS run and no trailing WS-run. */
546 getSingleRun(pBiDi
, levels
[0]);
547 } else /* runCount>1 || limit<length */ {
548 /* allocate and set the runs */
550 int32_t runIndex
, start
;
551 UBiDiLevel minLevel
=UBIDI_MAX_EXPLICIT_LEVEL
+1, maxLevel
=0;
553 /* now, count a (non-mergable) WS run */
559 if(getRunsMemory(pBiDi
, runCount
)) {
560 runs
=pBiDi
->runsMemory
;
566 /* this could be optimized, e.g.: 464->444, 484->444, 575->555, 595->555 */
567 /* however, that would take longer and make other functions more complicated */
570 /* search for the run limits and initialize visualLimit values with the run lengths */
573 /* prepare this run */
583 /* look for the run limit */
584 while(++i
<limit
&& levels
[i
]==level
) {}
586 /* i is another run limit */
587 runs
[runIndex
].logicalStart
=start
;
588 runs
[runIndex
].visualLimit
=i
-start
;
593 /* there is a separate WS run */
594 runs
[runIndex
].logicalStart
=limit
;
595 runs
[runIndex
].visualLimit
=length
-limit
;
596 if(pBiDi
->paraLevel
<minLevel
) {
597 minLevel
=pBiDi
->paraLevel
;
601 /* set the object fields */
603 pBiDi
->runCount
=runCount
;
605 reorderLine(pBiDi
, minLevel
, maxLevel
);
607 /* now add the direction flags and adjust the visualLimit's to be just that */
608 ADD_ODD_BIT_FROM_LEVEL(runs
[0].logicalStart
, levels
[runs
[0].logicalStart
]);
609 limit
=runs
[0].visualLimit
;
611 /* this loop will also handle the trailing WS run */
612 for(i
=1; i
<runCount
; ++i
) {
613 ADD_ODD_BIT_FROM_LEVEL(runs
[i
].logicalStart
, levels
[runs
[i
].logicalStart
]);
614 limit
=runs
[i
].visualLimit
+=limit
;
617 /* Set the "odd" bit for the trailing WS run. */
618 /* For a RTL paragraph, it will be the *first* run in visual order. */
619 if(runIndex
<runCount
) {
620 int32_t trailingRun
= ((pBiDi
->paraLevel
& 1) != 0)? 0 : runIndex
;
622 ADD_ODD_BIT_FROM_LEVEL(runs
[trailingRun
].logicalStart
, pBiDi
->paraLevel
);
631 prepareReorder(const UBiDiLevel
*levels
, int32_t length
,
633 UBiDiLevel
*pMinLevel
, UBiDiLevel
*pMaxLevel
) {
635 UBiDiLevel level
, minLevel
, maxLevel
;
637 if(levels
==NULL
|| length
<=0) {
641 /* determine minLevel and maxLevel */
642 minLevel
=UBIDI_MAX_EXPLICIT_LEVEL
+1;
644 for(start
=length
; start
>0;) {
645 level
=levels
[--start
];
646 if(level
>UBIDI_MAX_EXPLICIT_LEVEL
+1) {
659 /* initialize the index map */
660 for(start
=length
; start
>0;) {
662 indexMap
[start
]=start
;
668 /* reorder a line based on a levels array (L2) ------------------------------ */
670 U_CAPI
void U_EXPORT2
671 ubidi_reorderLogical(const UBiDiLevel
*levels
, int32_t length
, int32_t *indexMap
) {
672 int32_t start
, limit
, sumOfSosEos
;
673 UBiDiLevel minLevel
, maxLevel
;
675 if(indexMap
==NULL
|| !prepareReorder(levels
, length
, indexMap
, &minLevel
, &maxLevel
)) {
680 if(minLevel
==maxLevel
&& (minLevel
&1)==0) {
684 /* reorder only down to the lowest odd level */
687 /* loop maxLevel..minLevel */
691 /* loop for all sequences of levels to reorder at the current maxLevel */
693 /* look for a sequence of levels that are all at >=maxLevel */
694 /* look for the first index of such a sequence */
695 while(start
<length
&& levels
[start
]<maxLevel
) {
699 break; /* no more such sequences */
702 /* look for the limit of such a sequence (the index behind it) */
703 for(limit
=start
; ++limit
<length
&& levels
[limit
]>=maxLevel
;) {}
706 * sos=start of sequence, eos=end of sequence
708 * The closed (inclusive) interval from sos to eos includes all the logical
709 * and visual indexes within this sequence. They are logically and
710 * visually contiguous and in the same range.
712 * For each run, the new visual index=sos+eos-old visual index;
713 * we pre-add sos+eos into sumOfSosEos ->
714 * new visual index=sumOfSosEos-old visual index;
716 sumOfSosEos
=start
+limit
-1;
718 /* reorder each index in the sequence */
720 indexMap
[start
]=sumOfSosEos
-indexMap
[start
];
721 } while(++start
<limit
);
725 break; /* no more such sequences */
730 } while(--maxLevel
>=minLevel
);
733 U_CAPI
void U_EXPORT2
734 ubidi_reorderVisual(const UBiDiLevel
*levels
, int32_t length
, int32_t *indexMap
) {
735 int32_t start
, end
, limit
, temp
;
736 UBiDiLevel minLevel
, maxLevel
;
738 if(indexMap
==NULL
|| !prepareReorder(levels
, length
, indexMap
, &minLevel
, &maxLevel
)) {
743 if(minLevel
==maxLevel
&& (minLevel
&1)==0) {
747 /* reorder only down to the lowest odd level */
750 /* loop maxLevel..minLevel */
754 /* loop for all sequences of levels to reorder at the current maxLevel */
756 /* look for a sequence of levels that are all at >=maxLevel */
757 /* look for the first index of such a sequence */
758 while(start
<length
&& levels
[start
]<maxLevel
) {
762 break; /* no more such runs */
765 /* look for the limit of such a sequence (the index behind it) */
766 for(limit
=start
; ++limit
<length
&& levels
[limit
]>=maxLevel
;) {}
769 * Swap the entire interval of indexes from start to limit-1.
770 * We don't need to swap the levels for the purpose of this
771 * algorithm: the sequence of levels that we look at does not
776 temp
=indexMap
[start
];
777 indexMap
[start
]=indexMap
[end
];
785 break; /* no more such sequences */
790 } while(--maxLevel
>=minLevel
);
793 /* API functions for logical<->visual mapping ------------------------------- */
795 U_CAPI
int32_t U_EXPORT2
796 ubidi_getVisualIndex(UBiDi
*pBiDi
, int32_t logicalIndex
, UErrorCode
*pErrorCode
) {
797 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
799 } else if(pBiDi
==NULL
) {
800 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
802 } else if(logicalIndex
<0 || pBiDi
->length
<=logicalIndex
) {
803 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
806 /* we can do the trivial cases without the runs array */
807 switch(pBiDi
->direction
) {
811 return pBiDi
->length
-logicalIndex
-1;
813 if(pBiDi
->runCount
<0 && !ubidi_getRuns(pBiDi
)) {
814 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
817 Run
*runs
=pBiDi
->runs
;
818 int32_t i
, visualStart
=0, offset
, length
;
820 /* linear search for the run, search on the visual runs */
822 length
=runs
[i
].visualLimit
-visualStart
;
823 offset
=logicalIndex
-GET_INDEX(runs
[i
].logicalStart
);
824 if(offset
>=0 && offset
<length
) {
825 if(IS_EVEN_RUN(runs
[i
].logicalStart
)) {
827 return visualStart
+offset
;
830 return visualStart
+length
-offset
-1;
840 U_CAPI
int32_t U_EXPORT2
841 ubidi_getLogicalIndex(UBiDi
*pBiDi
, int32_t visualIndex
, UErrorCode
*pErrorCode
) {
842 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
844 } else if(pBiDi
==NULL
) {
845 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
847 } else if(visualIndex
<0 || pBiDi
->length
<=visualIndex
) {
848 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
851 /* we can do the trivial cases without the runs array */
852 switch(pBiDi
->direction
) {
856 return pBiDi
->length
-visualIndex
-1;
858 if(pBiDi
->runCount
<0 && !ubidi_getRuns(pBiDi
)) {
859 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
862 Run
*runs
=pBiDi
->runs
;
863 int32_t i
, runCount
=pBiDi
->runCount
, start
;
866 /* linear search for the run */
867 for(i
=0; visualIndex
>=runs
[i
].visualLimit
; ++i
) {}
869 /* binary search for the run */
870 int32_t begin
=0, limit
=runCount
;
872 /* the middle if() will guaranteed find the run, we don't need a loop limit */
875 if(visualIndex
>=runs
[i
].visualLimit
) {
877 } else if(i
==0 || visualIndex
>=runs
[i
-1].visualLimit
) {
885 start
=runs
[i
].logicalStart
;
886 if(IS_EVEN_RUN(start
)) {
888 /* the offset in runs[i] is visualIndex-runs[i-1].visualLimit */
890 visualIndex
-=runs
[i
-1].visualLimit
;
892 return GET_INDEX(start
)+visualIndex
;
895 return GET_INDEX(start
)+runs
[i
].visualLimit
-visualIndex
-1;
902 U_CAPI
void U_EXPORT2
903 ubidi_getLogicalMap(UBiDi
*pBiDi
, int32_t *indexMap
, UErrorCode
*pErrorCode
) {
906 /* ubidi_getLevels() checks all of its and our arguments */
907 if((levels
=(UBiDiLevel
*)ubidi_getLevels(pBiDi
, pErrorCode
))==NULL
) {
909 } else if(indexMap
==NULL
) {
910 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
912 ubidi_reorderLogical(levels
, pBiDi
->length
, indexMap
);
916 U_CAPI
void U_EXPORT2
917 ubidi_getVisualMap(UBiDi
*pBiDi
, int32_t *indexMap
, UErrorCode
*pErrorCode
) {
918 /* ubidi_countRuns() checks all of its and our arguments */
919 if(ubidi_countRuns(pBiDi
, pErrorCode
)<=0) {
921 } else if(indexMap
==NULL
) {
922 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
924 /* fill a visual-to-logical index map using the runs[] */
925 Run
*runs
=pBiDi
->runs
, *runsLimit
=runs
+pBiDi
->runCount
;
926 int32_t logicalStart
, visualStart
, visualLimit
;
929 for(; runs
<runsLimit
; ++runs
) {
930 logicalStart
=runs
->logicalStart
;
931 visualLimit
=runs
->visualLimit
;
932 if(IS_EVEN_RUN(logicalStart
)) {
934 *indexMap
++ = logicalStart
++;
935 } while(++visualStart
<visualLimit
);
937 REMOVE_ODD_BIT(logicalStart
);
938 logicalStart
+=visualLimit
-visualStart
; /* logicalLimit */
940 *indexMap
++ = --logicalStart
;
941 } while(++visualStart
<visualLimit
);
943 /* visualStart==visualLimit; */
948 U_CAPI
void U_EXPORT2
949 ubidi_invertMap(const int32_t *srcMap
, int32_t *destMap
, int32_t length
) {
950 if(srcMap
!=NULL
&& destMap
!=NULL
) {
953 destMap
[*--srcMap
]=--length
;