1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 1999-2015, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
12 * tab size: 8 (not used)
15 * created on: 1999jul27
16 * created by: Markus W. Scherer, updated by Matitiahu Allouche
21 #include "unicode/utypes.h"
22 #include "unicode/ustring.h"
23 #include "unicode/uchar.h"
24 #include "unicode/ubidi.h"
25 #include "unicode/utf16.h"
26 #include "ubidi_props.h"
31 * General implementation notes:
33 * Throughout the implementation, there are comments like (W2) that refer to
34 * rules of the BiDi algorithm, in this example to the second rule of the
35 * resolution of weak types.
37 * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32)
38 * character according to UTF-16, the second UChar gets the directional property of
39 * the entire character assigned, while the first one gets a BN, a boundary
40 * neutral, type, which is ignored by most of the algorithm according to
41 * rule (X9) and the implementation suggestions of the BiDi algorithm.
43 * Later, adjustWSLevels() will set the level for each BN to that of the
44 * following character (UChar), which results in surrogate pairs getting the
45 * same level on each of their surrogates.
47 * In a UTF-8 implementation, the same thing could be done: the last byte of
48 * a multi-byte sequence would get the "real" property, while all previous
49 * bytes of that sequence would get BN.
51 * It is not possible to assign all those parts of a character the same real
52 * property because this would fail in the resolution of weak types with rules
53 * that look at immediately surrounding types.
55 * As a related topic, this implementation does not remove Boundary Neutral
56 * types from the input, but ignores them wherever this is relevant.
57 * For example, the loop for the resolution of the weak types reads
58 * types until it finds a non-BN.
59 * Also, explicit embedding codes are neither changed into BN nor removed.
60 * They are only treated the same way real BNs are.
61 * As stated before, adjustWSLevels() takes care of them at the end.
62 * For the purpose of conformance, the levels of all these codes
65 * Note that this implementation modifies the dirProps
66 * after the initial setup, when applying X5c (replace FSI by LRI or RLI),
67 * X6, N0 (replace paired brackets by L or R).
69 * In this implementation, the resolution of weak types (W1 to W6),
70 * neutrals (N1 and N2), and the assignment of the resolved level (In)
71 * are all done in one single loop, in resolveImplicitLevels().
72 * Changes of dirProp values are done on the fly, without writing
73 * them back to the dirProps array.
76 * This implementation contains code that allows to bypass steps of the
77 * algorithm that are not needed on the specific paragraph
78 * in order to speed up the most common cases considerably,
79 * like text that is entirely LTR, or RTL text without numbers.
81 * Most of this is done by setting a bit for each directional property
82 * in a flags variable and later checking for whether there are
83 * any LTR characters or any RTL characters, or both, whether
84 * there are any explicit embedding codes, etc.
86 * If the (Xn) steps are performed, then the flags are re-evaluated,
87 * because they will then not contain the embedding codes any more
88 * and will be adjusted for override codes, so that subsequently
89 * more bypassing may be possible than what the initial flags suggested.
91 * If the text is not mixed-directional, then the
92 * algorithm steps for the weak type resolution are not performed,
93 * and all levels are set to the paragraph level.
95 * If there are no explicit embedding codes, then the (Xn) steps
98 * If embedding levels are supplied as a parameter, then all
99 * explicit embedding codes are ignored, and the (Xn) steps
102 * White Space types could get the level of the run they belong to,
103 * and are checked with a test of (flags&MASK_EMBEDDING) to
104 * consider if the paragraph direction should be considered in
105 * the flags variable.
107 * If there are no White Space types in the paragraph, then
108 * (L1) is not necessary in adjustWSLevels().
111 /* to avoid some conditional statements, use tiny constant arrays */
112 static const Flags flagLR[2]={ DIRPROP_FLAG(L), DIRPROP_FLAG(R) };
113 static const Flags flagE[2]={ DIRPROP_FLAG(LRE), DIRPROP_FLAG(RLE) };
114 static const Flags flagO[2]={ DIRPROP_FLAG(LRO), DIRPROP_FLAG(RLO) };
116 #define DIRPROP_FLAG_LR(level) flagLR[(level)&1]
117 #define DIRPROP_FLAG_E(level) flagE[(level)&1]
118 #define DIRPROP_FLAG_O(level) flagO[(level)&1]
120 #define DIR_FROM_STRONG(strong) ((strong)==L ? L : R)
122 #define NO_OVERRIDE(level) ((level)&~UBIDI_LEVEL_OVERRIDE)
124 /* UBiDi object management -------------------------------------------------- */
126 U_CAPI UBiDi * U_EXPORT2
129 UErrorCode errorCode=U_ZERO_ERROR;
130 return ubidi_openSized(0, 0, &errorCode);
133 U_CAPI UBiDi * U_EXPORT2
134 ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode) {
137 /* check the argument values */
138 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
140 } else if(maxLength<0 || maxRunCount<0) {
141 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
142 return NULL; /* invalid arguments */
145 /* allocate memory for the object */
146 pBiDi=(UBiDi *)uprv_malloc(sizeof(UBiDi));
148 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
152 /* reset the object, all pointers NULL, all flags FALSE, all sizes 0 */
153 uprv_memset(pBiDi, 0, sizeof(UBiDi));
155 /* get BiDi properties */
156 pBiDi->bdp=ubidi_getSingleton();
158 /* allocate memory for arrays as requested */
160 if( !getInitialDirPropsMemory(pBiDi, maxLength) ||
161 !getInitialLevelsMemory(pBiDi, maxLength)
163 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
166 pBiDi->mayAllocateText=TRUE;
171 /* use simpleRuns[] */
172 pBiDi->runsSize=sizeof(Run);
173 } else if(!getInitialRunsMemory(pBiDi, maxRunCount)) {
174 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
177 pBiDi->mayAllocateRuns=TRUE;
180 if(U_SUCCESS(*pErrorCode)) {
189 * We are allowed to allocate memory if memory==NULL or
190 * mayAllocate==TRUE for each array that we need.
191 * We also try to grow memory as needed if we
194 * Assume sizeNeeded>0.
195 * If *pMemory!=NULL, then assume *pSize>0.
197 * ### this realloc() may unnecessarily copy the old data,
198 * which we know we don't need any more;
199 * is this the best way to do this??
202 ubidi_getMemory(BidiMemoryForAllocation *bidiMem, int32_t *pSize, UBool mayAllocate, int32_t sizeNeeded) {
203 void **pMemory = (void **)bidiMem;
204 /* check for existing memory */
206 /* we need to allocate memory */
207 if(mayAllocate && (*pMemory=uprv_malloc(sizeNeeded))!=NULL) {
214 if(sizeNeeded<=*pSize) {
215 /* there is already enough memory */
218 else if(!mayAllocate) {
219 /* not enough memory, and we must not allocate */
224 /* in most cases, we do not need the copy-old-data part of
225 * realloc, but it is needed when adding runs using getRunsMemory()
226 * in setParaRunsOnly()
228 if((memory=uprv_realloc(*pMemory, sizeNeeded))!=NULL) {
233 /* we failed to grow */
240 U_CAPI void U_EXPORT2
241 ubidi_close(UBiDi *pBiDi) {
243 pBiDi->pParaBiDi=NULL; /* in case one tries to reuse this block */
244 if(pBiDi->dirPropsMemory!=NULL) {
245 uprv_free(pBiDi->dirPropsMemory);
247 if(pBiDi->levelsMemory!=NULL) {
248 uprv_free(pBiDi->levelsMemory);
250 if(pBiDi->openingsMemory!=NULL) {
251 uprv_free(pBiDi->openingsMemory);
253 if(pBiDi->parasMemory!=NULL) {
254 uprv_free(pBiDi->parasMemory);
256 if(pBiDi->runsMemory!=NULL) {
257 uprv_free(pBiDi->runsMemory);
259 if(pBiDi->isolatesMemory!=NULL) {
260 uprv_free(pBiDi->isolatesMemory);
262 if(pBiDi->insertPoints.points!=NULL) {
263 uprv_free(pBiDi->insertPoints.points);
270 /* set to approximate "inverse BiDi" ---------------------------------------- */
272 U_CAPI void U_EXPORT2
273 ubidi_setInverse(UBiDi *pBiDi, UBool isInverse) {
275 pBiDi->isInverse=isInverse;
276 pBiDi->reorderingMode = isInverse ? UBIDI_REORDER_INVERSE_NUMBERS_AS_L
277 : UBIDI_REORDER_DEFAULT;
281 U_CAPI UBool U_EXPORT2
282 ubidi_isInverse(UBiDi *pBiDi) {
284 return pBiDi->isInverse;
290 /* FOOD FOR THOUGHT: currently the reordering modes are a mixture of
291 * algorithm for direct BiDi, algorithm for inverse BiDi and the bizarre
292 * concept of RUNS_ONLY which is a double operation.
293 * It could be advantageous to divide this into 3 concepts:
294 * a) Operation: direct / inverse / RUNS_ONLY
295 * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_R
296 * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL
297 * This would allow combinations not possible today like RUNS_ONLY with
299 * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and
300 * REMOVE_CONTROLS for the inverse step.
301 * Not all combinations would be supported, and probably not all do make sense.
302 * This would need to document which ones are supported and what are the
303 * fallbacks for unsupported combinations.
305 U_CAPI void U_EXPORT2
306 ubidi_setReorderingMode(UBiDi *pBiDi, UBiDiReorderingMode reorderingMode) {
307 if ((pBiDi!=NULL) && (reorderingMode >= UBIDI_REORDER_DEFAULT)
308 && (reorderingMode < UBIDI_REORDER_COUNT)) {
309 pBiDi->reorderingMode = reorderingMode;
310 pBiDi->isInverse = (UBool)(reorderingMode == UBIDI_REORDER_INVERSE_NUMBERS_AS_L);
314 U_CAPI UBiDiReorderingMode U_EXPORT2
315 ubidi_getReorderingMode(UBiDi *pBiDi) {
317 return pBiDi->reorderingMode;
319 return UBIDI_REORDER_DEFAULT;
323 U_CAPI void U_EXPORT2
324 ubidi_setReorderingOptions(UBiDi *pBiDi, uint32_t reorderingOptions) {
325 if (reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
326 reorderingOptions&=~UBIDI_OPTION_INSERT_MARKS;
329 pBiDi->reorderingOptions=reorderingOptions;
333 U_CAPI uint32_t U_EXPORT2
334 ubidi_getReorderingOptions(UBiDi *pBiDi) {
336 return pBiDi->reorderingOptions;
342 U_CAPI UBiDiDirection U_EXPORT2
343 ubidi_getBaseDirection(const UChar *text,
350 if( text==NULL || length<-1 ){
351 return UBIDI_NEUTRAL;
355 length=u_strlen(text);
358 for( i = 0 ; i < length; ) {
359 /* i is incremented by U16_NEXT */
360 U16_NEXT(text, i, length, uchar);
361 dir = u_charDirection(uchar);
362 if( dir == U_LEFT_TO_RIGHT )
364 if( dir == U_RIGHT_TO_LEFT || dir ==U_RIGHT_TO_LEFT_ARABIC )
367 return UBIDI_NEUTRAL;
370 /* perform (P2)..(P3) ------------------------------------------------------- */
373 * Returns the directionality of the first strong character
374 * after the last B in prologue, if any.
375 * Requires prologue!=null.
378 firstL_R_AL(UBiDi *pBiDi) {
379 const UChar *text=pBiDi->prologue;
380 int32_t length=pBiDi->proLength;
383 DirProp dirProp, result=ON;
384 for(i=0; i<length; ) {
385 /* i is incremented by U16_NEXT */
386 U16_NEXT(text, i, length, uchar);
387 dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar);
389 if(dirProp==L || dirProp==R || dirProp==AL) {
402 * Check that there are enough entries in the array pointed to by pBiDi->paras
405 checkParaCount(UBiDi *pBiDi) {
406 int32_t count=pBiDi->paraCount;
407 if(pBiDi->paras==pBiDi->simpleParas) {
408 if(count<=SIMPLE_PARAS_COUNT)
410 if(!getInitialParasMemory(pBiDi, SIMPLE_PARAS_COUNT * 2))
412 pBiDi->paras=pBiDi->parasMemory;
413 uprv_memcpy(pBiDi->parasMemory, pBiDi->simpleParas, SIMPLE_PARAS_COUNT * sizeof(Para));
416 if(!getInitialParasMemory(pBiDi, count * 2))
418 pBiDi->paras=pBiDi->parasMemory;
423 * Get the directional properties for the text, calculate the flags bit-set, and
424 * determine the paragraph level if necessary (in pBiDi->paras[i].level).
425 * FSI initiators are also resolved and their dirProp replaced with LRI or RLI.
426 * When encountering an FSI, it is initially replaced with an LRI, which is the
427 * default. Only if a strong R or AL is found within its scope will the LRI be
428 * replaced by an RLI.
431 getDirProps(UBiDi *pBiDi) {
432 const UChar *text=pBiDi->text;
433 DirProp *dirProps=pBiDi->dirPropsMemory; /* pBiDi->dirProps is const */
435 int32_t i=0, originalLength=pBiDi->originalLength;
436 Flags flags=0; /* collect all directionalities in the text */
438 DirProp dirProp=0, defaultParaLevel=0; /* initialize to avoid compiler warnings */
439 UBool isDefaultLevel=IS_DEFAULT_LEVEL(pBiDi->paraLevel);
440 /* for inverse BiDi, the default para level is set to RTL if there is a
441 strong R or AL character at either end of the text */
442 UBool isDefaultLevelInverse=isDefaultLevel && (UBool)
443 (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT ||
444 pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL);
445 int32_t lastArabicPos=-1;
446 int32_t controlCount=0;
447 UBool removeBiDiControls = (UBool)(pBiDi->reorderingOptions &
448 UBIDI_OPTION_REMOVE_CONTROLS);
451 NOT_SEEKING_STRONG, /* 0: not contextual paraLevel, not after FSI */
452 SEEKING_STRONG_FOR_PARA, /* 1: looking for first strong char in para */
453 SEEKING_STRONG_FOR_FSI, /* 2: looking for first strong after FSI */
454 LOOKING_FOR_PDI /* 3: found strong after FSI, looking for PDI */
457 DirProp lastStrong=ON; /* for default level & inverse BiDi */
458 /* The following stacks are used to manage isolate sequences. Those
459 sequences may be nested, but obviously never more deeply than the
460 maximum explicit embedding level.
461 lastStack is the index of the last used entry in the stack. A value of -1
462 means that there is no open isolate sequence.
463 lastStack is reset to -1 on paragraph boundaries. */
464 /* The following stack contains the position of the initiator of
465 each open isolate sequence */
466 int32_t isolateStartStack[UBIDI_MAX_EXPLICIT_LEVEL+1];
467 /* The following stack contains the last known state before
468 encountering the initiator of an isolate sequence */
469 int8_t previousStateStack[UBIDI_MAX_EXPLICIT_LEVEL+1];
470 int32_t stackLast=-1;
472 if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING)
474 defaultParaLevel=pBiDi->paraLevel&1;
476 pBiDi->paras[0].level=defaultParaLevel;
477 lastStrong=defaultParaLevel;
478 if(pBiDi->proLength>0 && /* there is a prologue */
479 (dirProp=firstL_R_AL(pBiDi))!=ON) { /* with a strong character */
481 pBiDi->paras[0].level=0; /* set the default para level */
483 pBiDi->paras[0].level=1; /* set the default para level */
484 state=NOT_SEEKING_STRONG;
486 state=SEEKING_STRONG_FOR_PARA;
489 pBiDi->paras[0].level=pBiDi->paraLevel;
490 state=NOT_SEEKING_STRONG;
492 /* count paragraphs and determine the paragraph level (P2..P3) */
494 * see comment in ubidi.h:
495 * the UBIDI_DEFAULT_XXX values are designed so that
496 * their bit 0 alone yields the intended default
498 for( /* i=0 above */ ; i<originalLength; ) {
499 /* i is incremented by U16_NEXT */
500 U16_NEXT(text, i, originalLength, uchar);
501 flags|=DIRPROP_FLAG(dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar));
502 dirProps[i-1]=dirProp;
503 if(uchar>0xffff) { /* set the lead surrogate's property to BN */
504 flags|=DIRPROP_FLAG(BN);
507 if(removeBiDiControls && IS_BIDI_CONTROL_CHAR(uchar))
510 if(state==SEEKING_STRONG_FOR_PARA) {
511 pBiDi->paras[pBiDi->paraCount-1].level=0;
512 state=NOT_SEEKING_STRONG;
514 else if(state==SEEKING_STRONG_FOR_FSI) {
515 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
516 /* no need for next statement, already set by default */
517 /* dirProps[isolateStartStack[stackLast]]=LRI; */
518 flags|=DIRPROP_FLAG(LRI);
520 state=LOOKING_FOR_PDI;
525 if(dirProp==R || dirProp==AL) {
526 if(state==SEEKING_STRONG_FOR_PARA) {
527 pBiDi->paras[pBiDi->paraCount-1].level=1;
528 state=NOT_SEEKING_STRONG;
530 else if(state==SEEKING_STRONG_FOR_FSI) {
531 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
532 dirProps[isolateStartStack[stackLast]]=RLI;
533 flags|=DIRPROP_FLAG(RLI);
535 state=LOOKING_FOR_PDI;
542 if(dirProp>=FSI && dirProp<=RLI) { /* FSI, LRI or RLI */
544 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
545 isolateStartStack[stackLast]=i-1;
546 previousStateStack[stackLast]=state;
549 dirProps[i-1]=LRI; /* default if no strong char */
550 state=SEEKING_STRONG_FOR_FSI;
553 state=LOOKING_FOR_PDI;
557 if(state==SEEKING_STRONG_FOR_FSI) {
558 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL) {
559 /* no need for next statement, already set by default */
560 /* dirProps[isolateStartStack[stackLast]]=LRI; */
561 flags|=DIRPROP_FLAG(LRI);
565 if(stackLast<=UBIDI_MAX_EXPLICIT_LEVEL)
566 state=previousStateStack[stackLast];
572 if(i<originalLength && uchar==CR && text[i]==LF) /* do nothing on the CR */
574 pBiDi->paras[pBiDi->paraCount-1].limit=i;
575 if(isDefaultLevelInverse && lastStrong==R)
576 pBiDi->paras[pBiDi->paraCount-1].level=1;
577 if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
578 /* When streaming, we only process whole paragraphs
579 thus some updates are only done on paragraph boundaries */
580 pBiDi->length=i; /* i is index to next character */
581 pBiDi->controlCount=controlCount;
583 if(i<originalLength) { /* B not last char in text */
585 if(checkParaCount(pBiDi)==FALSE) /* not enough memory for a new para entry */
588 pBiDi->paras[pBiDi->paraCount-1].level=defaultParaLevel;
589 state=SEEKING_STRONG_FOR_PARA;
590 lastStrong=defaultParaLevel;
592 pBiDi->paras[pBiDi->paraCount-1].level=pBiDi->paraLevel;
593 state=NOT_SEEKING_STRONG;
600 /* Ignore still open isolate sequences with overflow */
601 if(stackLast>UBIDI_MAX_EXPLICIT_LEVEL) {
602 stackLast=UBIDI_MAX_EXPLICIT_LEVEL;
603 state=SEEKING_STRONG_FOR_FSI; /* to be on the safe side */
605 /* Resolve direction of still unresolved open FSI sequences */
606 while(stackLast>=0) {
607 if(state==SEEKING_STRONG_FOR_FSI) {
608 /* no need for next statement, already set by default */
609 /* dirProps[isolateStartStack[stackLast]]=LRI; */
610 flags|=DIRPROP_FLAG(LRI);
613 state=previousStateStack[stackLast];
616 /* When streaming, ignore text after the last paragraph separator */
617 if(pBiDi->reorderingOptions & UBIDI_OPTION_STREAMING) {
618 if(pBiDi->length<originalLength)
621 pBiDi->paras[pBiDi->paraCount-1].limit=originalLength;
622 pBiDi->controlCount=controlCount;
624 /* For inverse bidi, default para direction is RTL if there is
625 a strong R or AL at either end of the paragraph */
626 if(isDefaultLevelInverse && lastStrong==R) {
627 pBiDi->paras[pBiDi->paraCount-1].level=1;
630 pBiDi->paraLevel=pBiDi->paras[0].level;
632 /* The following is needed to resolve the text direction for default level
633 paragraphs containing no strong character */
634 for(i=0; i<pBiDi->paraCount; i++)
635 flags|=DIRPROP_FLAG_LR(pBiDi->paras[i].level);
637 if(pBiDi->orderParagraphsLTR && (flags&DIRPROP_FLAG(B))) {
638 flags|=DIRPROP_FLAG(L);
641 pBiDi->lastArabicPos=lastArabicPos;
645 /* determine the paragraph level at position index */
647 ubidi_getParaLevelAtIndex(const UBiDi *pBiDi, int32_t pindex) {
649 for(i=0; i<pBiDi->paraCount; i++)
650 if(pindex<pBiDi->paras[i].limit)
652 if(i>=pBiDi->paraCount)
653 i=pBiDi->paraCount-1;
654 return (UBiDiLevel)(pBiDi->paras[i].level);
657 /* Functions for handling paired brackets ----------------------------------- */
659 /* In the isoRuns array, the first entry is used for text outside of any
660 isolate sequence. Higher entries are used for each more deeply nested
661 isolate sequence. isoRunLast is the index of the last used entry. The
662 openings array is used to note the data of opening brackets not yet
663 matched by a closing bracket, or matched but still susceptible to change
665 Each isoRun entry contains the index of the first and
666 one-after-last openings entries for pending opening brackets it
667 contains. The next openings entry to use is the one-after-last of the
668 most deeply nested isoRun entry.
669 isoRun entries also contain their current embedding level and the last
670 encountered strong character, since these will be needed to resolve
671 the level of paired brackets. */
674 bracketInit(UBiDi *pBiDi, BracketData *bd) {
677 bd->isoRuns[0].start=0;
678 bd->isoRuns[0].limit=0;
679 bd->isoRuns[0].level=GET_PARALEVEL(pBiDi, 0);
680 bd->isoRuns[0].lastStrong=bd->isoRuns[0].lastBase=bd->isoRuns[0].contextDir=GET_PARALEVEL(pBiDi, 0)&1;
681 bd->isoRuns[0].contextPos=0;
682 if(pBiDi->openingsMemory) {
683 bd->openings=pBiDi->openingsMemory;
684 bd->openingsCount=pBiDi->openingsSize / sizeof(Opening);
686 bd->openings=bd->simpleOpenings;
687 bd->openingsCount=SIMPLE_OPENINGS_COUNT;
689 bd->isNumbersSpecial=bd->pBiDi->reorderingMode==UBIDI_REORDER_NUMBERS_SPECIAL ||
690 bd->pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL;
693 /* paragraph boundary */
695 bracketProcessB(BracketData *bd, UBiDiLevel level) {
697 bd->isoRuns[0].limit=0;
698 bd->isoRuns[0].level=level;
699 bd->isoRuns[0].lastStrong=bd->isoRuns[0].lastBase=bd->isoRuns[0].contextDir=level&1;
700 bd->isoRuns[0].contextPos=0;
703 /* LRE, LRO, RLE, RLO, PDF */
705 bracketProcessBoundary(BracketData *bd, int32_t lastCcPos,
706 UBiDiLevel contextLevel, UBiDiLevel embeddingLevel) {
707 IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
708 DirProp *dirProps=bd->pBiDi->dirProps;
709 if(DIRPROP_FLAG(dirProps[lastCcPos])&MASK_ISO) /* after an isolate */
711 if(NO_OVERRIDE(embeddingLevel)>NO_OVERRIDE(contextLevel)) /* not a PDF */
712 contextLevel=embeddingLevel;
713 pLastIsoRun->limit=pLastIsoRun->start;
714 pLastIsoRun->level=embeddingLevel;
715 pLastIsoRun->lastStrong=pLastIsoRun->lastBase=pLastIsoRun->contextDir=contextLevel&1;
716 pLastIsoRun->contextPos=lastCcPos;
721 bracketProcessLRI_RLI(BracketData *bd, UBiDiLevel level) {
722 IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
724 pLastIsoRun->lastBase=ON;
725 lastLimit=pLastIsoRun->limit;
728 pLastIsoRun->start=pLastIsoRun->limit=lastLimit;
729 pLastIsoRun->level=level;
730 pLastIsoRun->lastStrong=pLastIsoRun->lastBase=pLastIsoRun->contextDir=level&1;
731 pLastIsoRun->contextPos=0;
736 bracketProcessPDI(BracketData *bd) {
739 pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
740 pLastIsoRun->lastBase=ON;
743 /* newly found opening bracket: create an openings entry */
744 static UBool /* return TRUE if success */
745 bracketAddOpening(BracketData *bd, UChar match, int32_t position) {
746 IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
748 if(pLastIsoRun->limit>=bd->openingsCount) { /* no available new entry */
749 UBiDi *pBiDi=bd->pBiDi;
750 if(!getInitialOpeningsMemory(pBiDi, pLastIsoRun->limit * 2))
752 if(bd->openings==bd->simpleOpenings)
753 uprv_memcpy(pBiDi->openingsMemory, bd->simpleOpenings,
754 SIMPLE_OPENINGS_COUNT * sizeof(Opening));
755 bd->openings=pBiDi->openingsMemory; /* may have changed */
756 bd->openingsCount=pBiDi->openingsSize / sizeof(Opening);
758 pOpening=&bd->openings[pLastIsoRun->limit];
759 pOpening->position=position;
760 pOpening->match=match;
761 pOpening->contextDir=pLastIsoRun->contextDir;
762 pOpening->contextPos=pLastIsoRun->contextPos;
764 pLastIsoRun->limit++;
768 /* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */
770 fixN0c(BracketData *bd, int32_t openingIndex, int32_t newPropPosition, DirProp newProp) {
771 /* This function calls itself recursively */
772 IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
774 DirProp *dirProps=bd->pBiDi->dirProps;
775 int32_t k, openingPosition, closingPosition;
776 for(k=openingIndex+1, qOpening=&bd->openings[k]; k<pLastIsoRun->limit; k++, qOpening++) {
777 if(qOpening->match>=0) /* not an N0c match */
779 if(newPropPosition<qOpening->contextPos)
781 if(newPropPosition>=qOpening->position)
783 if(newProp==qOpening->contextDir)
785 openingPosition=qOpening->position;
786 dirProps[openingPosition]=newProp;
787 closingPosition=-(qOpening->match);
788 dirProps[closingPosition]=newProp;
789 qOpening->match=0; /* prevent further changes */
790 fixN0c(bd, k, openingPosition, newProp);
791 fixN0c(bd, k, closingPosition, newProp);
795 /* process closing bracket */
796 static DirProp /* return L or R if N0b or N0c, ON if N0d */
797 bracketProcessClosing(BracketData *bd, int32_t openIdx, int32_t position) {
798 IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
799 Opening *pOpening, *qOpening;
800 UBiDiDirection direction;
803 pOpening=&bd->openings[openIdx];
804 direction=pLastIsoRun->level&1;
805 stable=TRUE; /* assume stable until proved otherwise */
807 /* The stable flag is set when brackets are paired and their
808 level is resolved and cannot be changed by what will be
809 found later in the source string.
810 An unstable match can occur only when applying N0c, where
811 the resolved level depends on the preceding context, and
812 this context may be affected by text occurring later.
813 Example: RTL paragraph containing: abc[(latin) HEBREW]
814 When the closing parenthesis is encountered, it appears
815 that N0c1 must be applied since 'abc' sets an opposite
816 direction context and both parentheses receive level 2.
817 However, when the closing square bracket is processed,
818 N0b applies because of 'HEBREW' being included within the
819 brackets, thus the square brackets are treated like R and
820 receive level 1. However, this changes the preceding
821 context of the opening parenthesis, and it now appears
822 that N0c2 must be applied to the parentheses rather than
825 if((direction==0 && pOpening->flags&FOUND_L) ||
826 (direction==1 && pOpening->flags&FOUND_R)) { /* N0b */
829 else if(pOpening->flags&(FOUND_L|FOUND_R)) { /* N0c */
830 /* it is stable if there is no containing pair or in
831 conditions too complicated and not worth checking */
832 stable=(openIdx==pLastIsoRun->start);
833 if(direction!=pOpening->contextDir)
834 newProp=pOpening->contextDir; /* N0c1 */
836 newProp=direction; /* N0c2 */
838 /* forget this and any brackets nested within this pair */
839 pLastIsoRun->limit=openIdx;
842 bd->pBiDi->dirProps[pOpening->position]=newProp;
843 bd->pBiDi->dirProps[position]=newProp;
844 /* Update nested N0c pairs that may be affected */
845 fixN0c(bd, openIdx, pOpening->position, newProp);
847 pLastIsoRun->limit=openIdx; /* forget any brackets nested within this pair */
848 /* remove lower located synonyms if any */
849 while(pLastIsoRun->limit>pLastIsoRun->start &&
850 bd->openings[pLastIsoRun->limit-1].position==pOpening->position)
851 pLastIsoRun->limit--;
854 pOpening->match=-position;
855 /* neutralize lower located synonyms if any */
857 while(k>=pLastIsoRun->start &&
858 bd->openings[k].position==pOpening->position)
859 bd->openings[k--].match=0;
860 /* neutralize any unmatched opening between the current pair;
861 this will also neutralize higher located synonyms if any */
862 for(k=openIdx+1; k<pLastIsoRun->limit; k++) {
863 qOpening=&bd->openings[k];
864 if(qOpening->position>=position)
866 if(qOpening->match>0)
873 /* handle strong characters, digits and candidates for closing brackets */
874 static UBool /* return TRUE if success */
875 bracketProcessChar(BracketData *bd, int32_t position) {
876 IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
877 DirProp *dirProps, dirProp, newProp;
879 dirProps=bd->pBiDi->dirProps;
880 dirProp=dirProps[position];
884 /* First see if it is a matching closing bracket. Hopefully, this is
885 more efficient than checking if it is a closing bracket at all */
886 c=bd->pBiDi->text[position];
887 for(idx=pLastIsoRun->limit-1; idx>=pLastIsoRun->start; idx--) {
888 if(bd->openings[idx].match!=c)
890 /* We have a match */
891 newProp=bracketProcessClosing(bd, idx, position);
892 if(newProp==ON) { /* N0d */
893 c=0; /* prevent handling as an opening */
896 pLastIsoRun->lastBase=ON;
897 pLastIsoRun->contextDir=newProp;
898 pLastIsoRun->contextPos=position;
899 level=bd->pBiDi->levels[position];
900 if(level&UBIDI_LEVEL_OVERRIDE) { /* X4, X5 */
904 pLastIsoRun->lastStrong=newProp;
905 flag=DIRPROP_FLAG(newProp);
906 for(i=pLastIsoRun->start; i<idx; i++)
907 bd->openings[i].flags|=flag;
908 /* matching brackets are not overridden by LRO/RLO */
909 bd->pBiDi->levels[position]&=~UBIDI_LEVEL_OVERRIDE;
911 /* matching brackets are not overridden by LRO/RLO */
912 bd->pBiDi->levels[bd->openings[idx].position]&=~UBIDI_LEVEL_OVERRIDE;
915 /* We get here only if the ON character is not a matching closing
916 bracket or it is a case of N0d */
917 /* Now see if it is an opening bracket */
919 match=u_getBidiPairedBracket(c); /* get the matching char */
922 if(match!=c && /* has a matching char */
923 ubidi_getPairedBracketType(bd->pBiDi->bdp, c)==U_BPT_OPEN) { /* opening bracket */
924 /* special case: process synonyms
925 create an opening entry for each synonym */
926 if(match==0x232A) { /* RIGHT-POINTING ANGLE BRACKET */
927 if(!bracketAddOpening(bd, 0x3009, position))
930 else if(match==0x3009) { /* RIGHT ANGLE BRACKET */
931 if(!bracketAddOpening(bd, 0x232A, position))
934 if(!bracketAddOpening(bd, match, position))
938 level=bd->pBiDi->levels[position];
939 if(level&UBIDI_LEVEL_OVERRIDE) { /* X4, X5 */
941 if(dirProp!=S && dirProp!=WS && dirProp!=ON)
942 dirProps[position]=newProp;
943 pLastIsoRun->lastBase=newProp;
944 pLastIsoRun->lastStrong=newProp;
945 pLastIsoRun->contextDir=newProp;
946 pLastIsoRun->contextPos=position;
948 else if(dirProp<=R || dirProp==AL) {
949 newProp=DIR_FROM_STRONG(dirProp);
950 pLastIsoRun->lastBase=dirProp;
951 pLastIsoRun->lastStrong=dirProp;
952 pLastIsoRun->contextDir=newProp;
953 pLastIsoRun->contextPos=position;
955 else if(dirProp==EN) {
956 pLastIsoRun->lastBase=EN;
957 if(pLastIsoRun->lastStrong==L) {
959 if(!bd->isNumbersSpecial)
960 dirProps[position]=ENL;
961 pLastIsoRun->contextDir=L;
962 pLastIsoRun->contextPos=position;
966 if(pLastIsoRun->lastStrong==AL)
967 dirProps[position]=AN; /* W2 */
969 dirProps[position]=ENR;
970 pLastIsoRun->contextDir=R;
971 pLastIsoRun->contextPos=position;
974 else if(dirProp==AN) {
976 pLastIsoRun->lastBase=AN;
977 pLastIsoRun->contextDir=R;
978 pLastIsoRun->contextPos=position;
980 else if(dirProp==NSM) {
981 /* if the last real char was ON, change NSM to ON so that it
982 will stay ON even if the last real char is a bracket which
983 may be changed to L or R */
984 newProp=pLastIsoRun->lastBase;
986 dirProps[position]=newProp;
990 pLastIsoRun->lastBase=dirProp;
992 if(newProp<=R || newProp==AL) {
994 uint16_t flag=DIRPROP_FLAG(DIR_FROM_STRONG(newProp));
995 for(i=pLastIsoRun->start; i<pLastIsoRun->limit; i++)
996 if(position>bd->openings[i].position)
997 bd->openings[i].flags|=flag;
1002 /* perform (X1)..(X9) ------------------------------------------------------- */
1004 /* determine if the text is mixed-directional or single-directional */
1005 static UBiDiDirection
1006 directionFromFlags(UBiDi *pBiDi) {
1007 Flags flags=pBiDi->flags;
1008 /* if the text contains AN and neutrals, then some neutrals may become RTL */
1009 if(!(flags&MASK_RTL || ((flags&DIRPROP_FLAG(AN)) && (flags&MASK_POSSIBLE_N)))) {
1011 } else if(!(flags&MASK_LTR)) {
1019 * Resolve the explicit levels as specified by explicit embedding codes.
1020 * Recalculate the flags to have them reflect the real properties
1021 * after taking the explicit embeddings into account.
1023 * The BiDi algorithm is designed to result in the same behavior whether embedding
1024 * levels are externally specified (from "styled text", supposedly the preferred
1025 * method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, PDI) in the plain text.
1026 * That is why (X9) instructs to remove all not-isolate explicit codes (and BN).
1027 * However, in a real implementation, the removal of these codes and their index
1028 * positions in the plain text is undesirable since it would result in
1029 * reallocated, reindexed text.
1030 * Instead, this implementation leaves the codes in there and just ignores them
1031 * in the subsequent processing.
1032 * In order to get the same reordering behavior, positions with a BN or a not-isolate
1033 * explicit embedding code just get the same level assigned as the last "real"
1036 * Some implementations, not this one, then overwrite some of these
1037 * directionality properties at "real" same-level-run boundaries by
1038 * L or R codes so that the resolution of weak types can be performed on the
1039 * entire paragraph at once instead of having to parse it once more and
1040 * perform that resolution on same-level-runs.
1041 * This limits the scope of the implicit rules in effectively
1042 * the same way as the run limits.
1044 * Instead, this implementation does not modify these codes, except for
1045 * paired brackets whose properties (ON) may be replaced by L or R.
1046 * On one hand, the paragraph has to be scanned for same-level-runs, but
1047 * on the other hand, this saves another loop to reset these codes,
1048 * or saves making and modifying a copy of dirProps[].
1051 * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi algorithm.
1054 * Handling the stack of explicit levels (Xn):
1056 * With the BiDi stack of explicit levels, as pushed with each
1057 * LRE, RLE, LRO, RLO, LRI, RLI and FSI and popped with each PDF and PDI,
1058 * the explicit level must never exceed UBIDI_MAX_EXPLICIT_LEVEL.
1060 * In order to have a correct push-pop semantics even in the case of overflows,
1061 * overflow counters and a valid isolate counter are used as described in UAX#9
1062 * section 3.3.2 "Explicit Levels and Directions".
1064 * This implementation assumes that UBIDI_MAX_EXPLICIT_LEVEL is odd.
1066 * Returns normally the direction; -1 if there was a memory shortage
1069 static UBiDiDirection
1070 resolveExplicitLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
1071 DirProp *dirProps=pBiDi->dirProps;
1072 UBiDiLevel *levels=pBiDi->levels;
1073 const UChar *text=pBiDi->text;
1075 int32_t i=0, length=pBiDi->length;
1076 Flags flags=pBiDi->flags; /* collect all directionalities in the text */
1078 UBiDiLevel level=GET_PARALEVEL(pBiDi, 0);
1079 UBiDiDirection direction;
1080 pBiDi->isolateCount=0;
1082 if(U_FAILURE(*pErrorCode)) { return UBIDI_LTR; }
1084 /* determine if the text is mixed-directional or single-directional */
1085 direction=directionFromFlags(pBiDi);
1087 /* we may not need to resolve any explicit levels */
1088 if((direction!=UBIDI_MIXED)) {
1089 /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */
1092 if(pBiDi->reorderingMode > UBIDI_REORDER_LAST_LOGICAL_TO_VISUAL) {
1093 /* inverse BiDi: mixed, but all characters are at the same embedding level */
1094 /* set all levels to the paragraph level */
1095 int32_t paraIndex, start, limit;
1096 for(paraIndex=0; paraIndex<pBiDi->paraCount; paraIndex++) {
1100 start=pBiDi->paras[paraIndex-1].limit;
1101 limit=pBiDi->paras[paraIndex].limit;
1102 level=pBiDi->paras[paraIndex].level;
1103 for(i=start; i<limit; i++)
1106 return direction; /* no bracket matching for inverse BiDi */
1108 if(!(flags&(MASK_EXPLICIT|MASK_ISO))) {
1109 /* no embeddings, set all levels to the paragraph level */
1110 /* we still have to perform bracket matching */
1111 int32_t paraIndex, start, limit;
1112 BracketData bracketData;
1113 bracketInit(pBiDi, &bracketData);
1114 for(paraIndex=0; paraIndex<pBiDi->paraCount; paraIndex++) {
1118 start=pBiDi->paras[paraIndex-1].limit;
1119 limit=pBiDi->paras[paraIndex].limit;
1120 level=pBiDi->paras[paraIndex].level;
1121 for(i=start; i<limit; i++) {
1123 dirProp=dirProps[i];
1128 if(text[i]==CR && text[i+1]==LF)
1129 continue; /* skip CR when followed by LF */
1130 bracketProcessB(&bracketData, level);
1134 if(!bracketProcessChar(&bracketData, i)) {
1135 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
1143 /* continue to perform (Xn) */
1145 /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */
1146 /* both variables may carry the UBIDI_LEVEL_OVERRIDE flag to indicate the override status */
1147 UBiDiLevel embeddingLevel=level, newLevel;
1148 UBiDiLevel previousLevel=level; /* previous level for regular (not CC) characters */
1149 int32_t lastCcPos=0; /* index of last effective LRx,RLx, PDx */
1151 /* The following stack remembers the embedding level and the ISOLATE flag of level runs.
1152 stackLast points to its current entry. */
1153 uint16_t stack[UBIDI_MAX_EXPLICIT_LEVEL+2]; /* we never push anything >=UBIDI_MAX_EXPLICIT_LEVEL
1154 but we need one more entry as base */
1155 uint32_t stackLast=0;
1156 int32_t overflowIsolateCount=0;
1157 int32_t overflowEmbeddingCount=0;
1158 int32_t validIsolateCount=0;
1159 BracketData bracketData;
1160 bracketInit(pBiDi, &bracketData);
1161 stack[0]=level; /* initialize base entry to para level, no override, no isolate */
1163 /* recalculate the flags */
1166 for(i=0; i<length; ++i) {
1167 dirProp=dirProps[i];
1173 /* (X2, X3, X4, X5) */
1174 flags|=DIRPROP_FLAG(BN);
1175 levels[i]=previousLevel;
1176 if (dirProp==LRE || dirProp==LRO)
1177 /* least greater even level */
1178 newLevel=(UBiDiLevel)((embeddingLevel+2)&~(UBIDI_LEVEL_OVERRIDE|1));
1180 /* least greater odd level */
1181 newLevel=(UBiDiLevel)((NO_OVERRIDE(embeddingLevel)+1)|1);
1182 if(newLevel<=UBIDI_MAX_EXPLICIT_LEVEL && overflowIsolateCount==0 &&
1183 overflowEmbeddingCount==0) {
1185 embeddingLevel=newLevel;
1186 if(dirProp==LRO || dirProp==RLO)
1187 embeddingLevel|=UBIDI_LEVEL_OVERRIDE;
1189 stack[stackLast]=embeddingLevel;
1190 /* we don't need to set UBIDI_LEVEL_OVERRIDE off for LRE and RLE
1191 since this has already been done for newLevel which is
1192 the source for embeddingLevel.
1195 if(overflowIsolateCount==0)
1196 overflowEmbeddingCount++;
1201 flags|=DIRPROP_FLAG(BN);
1202 levels[i]=previousLevel;
1203 /* handle all the overflow cases first */
1204 if(overflowIsolateCount) {
1207 if(overflowEmbeddingCount) {
1208 overflowEmbeddingCount--;
1211 if(stackLast>0 && stack[stackLast]<ISOLATE) { /* not an isolate entry */
1214 embeddingLevel=(UBiDiLevel)stack[stackLast];
1219 flags|=(DIRPROP_FLAG(ON)|DIRPROP_FLAG_LR(embeddingLevel));
1220 levels[i]=NO_OVERRIDE(embeddingLevel);
1221 if(NO_OVERRIDE(embeddingLevel)!=NO_OVERRIDE(previousLevel)) {
1222 bracketProcessBoundary(&bracketData, lastCcPos,
1223 previousLevel, embeddingLevel);
1224 flags|=DIRPROP_FLAG_MULTI_RUNS;
1226 previousLevel=embeddingLevel;
1229 /* least greater even level */
1230 newLevel=(UBiDiLevel)((embeddingLevel+2)&~(UBIDI_LEVEL_OVERRIDE|1));
1232 /* least greater odd level */
1233 newLevel=(UBiDiLevel)((NO_OVERRIDE(embeddingLevel)+1)|1);
1234 if(newLevel<=UBIDI_MAX_EXPLICIT_LEVEL && overflowIsolateCount==0 &&
1235 overflowEmbeddingCount==0) {
1236 flags|=DIRPROP_FLAG(dirProp);
1238 validIsolateCount++;
1239 if(validIsolateCount>pBiDi->isolateCount)
1240 pBiDi->isolateCount=validIsolateCount;
1241 embeddingLevel=newLevel;
1242 /* we can increment stackLast without checking because newLevel
1243 will exceed UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows */
1245 stack[stackLast]=embeddingLevel+ISOLATE;
1246 bracketProcessLRI_RLI(&bracketData, embeddingLevel);
1248 /* make it WS so that it is handled by adjustWSLevels() */
1250 overflowIsolateCount++;
1254 if(NO_OVERRIDE(embeddingLevel)!=NO_OVERRIDE(previousLevel)) {
1255 bracketProcessBoundary(&bracketData, lastCcPos,
1256 previousLevel, embeddingLevel);
1257 flags|=DIRPROP_FLAG_MULTI_RUNS;
1260 if(overflowIsolateCount) {
1261 overflowIsolateCount--;
1262 /* make it WS so that it is handled by adjustWSLevels() */
1265 else if(validIsolateCount) {
1266 flags|=DIRPROP_FLAG(PDI);
1268 overflowEmbeddingCount=0;
1269 while(stack[stackLast]<ISOLATE) /* pop embedding entries */
1270 stackLast--; /* until the last isolate entry */
1271 stackLast--; /* pop also the last isolate entry */
1272 validIsolateCount--;
1273 bracketProcessPDI(&bracketData);
1275 /* make it WS so that it is handled by adjustWSLevels() */
1277 embeddingLevel=(UBiDiLevel)stack[stackLast]&~ISOLATE;
1278 flags|=(DIRPROP_FLAG(ON)|DIRPROP_FLAG_LR(embeddingLevel));
1279 previousLevel=embeddingLevel;
1280 levels[i]=NO_OVERRIDE(embeddingLevel);
1283 flags|=DIRPROP_FLAG(B);
1284 levels[i]=GET_PARALEVEL(pBiDi, i);
1286 if(text[i]==CR && text[i+1]==LF)
1287 break; /* skip CR when followed by LF */
1288 overflowEmbeddingCount=overflowIsolateCount=0;
1289 validIsolateCount=0;
1291 previousLevel=embeddingLevel=GET_PARALEVEL(pBiDi, i+1);
1292 stack[0]=embeddingLevel; /* initialize base entry to para level, no override, no isolate */
1293 bracketProcessB(&bracketData, embeddingLevel);
1297 /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */
1298 /* they will get their levels set correctly in adjustWSLevels() */
1299 levels[i]=previousLevel;
1300 flags|=DIRPROP_FLAG(BN);
1303 /* all other types are normal characters and get the "real" level */
1304 if(NO_OVERRIDE(embeddingLevel)!=NO_OVERRIDE(previousLevel)) {
1305 bracketProcessBoundary(&bracketData, lastCcPos,
1306 previousLevel, embeddingLevel);
1307 flags|=DIRPROP_FLAG_MULTI_RUNS;
1308 if(embeddingLevel&UBIDI_LEVEL_OVERRIDE)
1309 flags|=DIRPROP_FLAG_O(embeddingLevel);
1311 flags|=DIRPROP_FLAG_E(embeddingLevel);
1313 previousLevel=embeddingLevel;
1314 levels[i]=embeddingLevel;
1315 if(!bracketProcessChar(&bracketData, i))
1317 /* the dirProp may have been changed in bracketProcessChar() */
1318 flags|=DIRPROP_FLAG(dirProps[i]);
1322 if(flags&MASK_EMBEDDING)
1323 flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
1324 if(pBiDi->orderParagraphsLTR && (flags&DIRPROP_FLAG(B)))
1325 flags|=DIRPROP_FLAG(L);
1326 /* again, determine if the text is mixed-directional or single-directional */
1328 direction=directionFromFlags(pBiDi);
1334 * Use a pre-specified embedding levels array:
1336 * Adjust the directional properties for overrides (->LEVEL_OVERRIDE),
1337 * ignore all explicit codes (X9),
1338 * and check all the preset levels.
1340 * Recalculate the flags to have them reflect the real properties
1341 * after taking the explicit embeddings into account.
1343 static UBiDiDirection
1344 checkExplicitLevels(UBiDi *pBiDi, UErrorCode *pErrorCode) {
1345 DirProp *dirProps=pBiDi->dirProps;
1347 UBiDiLevel *levels=pBiDi->levels;
1348 int32_t isolateCount=0;
1350 int32_t i, length=pBiDi->length;
1351 Flags flags=0; /* collect all directionalities in the text */
1353 pBiDi->isolateCount=0;
1355 for(i=0; i<length; ++i) {
1357 dirProp=dirProps[i];
1358 if(dirProp==LRI || dirProp==RLI) {
1360 if(isolateCount>pBiDi->isolateCount)
1361 pBiDi->isolateCount=isolateCount;
1363 else if(dirProp==PDI)
1367 if(level&UBIDI_LEVEL_OVERRIDE) {
1368 /* keep the override flag in levels[i] but adjust the flags */
1369 level&=~UBIDI_LEVEL_OVERRIDE; /* make the range check below simpler */
1370 flags|=DIRPROP_FLAG_O(level);
1373 flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG(dirProp);
1375 if((level<GET_PARALEVEL(pBiDi, i) &&
1376 !((0==level)&&(dirProp==B))) ||
1377 (UBIDI_MAX_EXPLICIT_LEVEL<level)) {
1378 /* level out of bounds */
1379 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
1383 if(flags&MASK_EMBEDDING)
1384 flags|=DIRPROP_FLAG_LR(pBiDi->paraLevel);
1385 /* determine if the text is mixed-directional or single-directional */
1387 return directionFromFlags(pBiDi);
1390 /******************************************************************
1391 The Properties state machine table
1392 *******************************************************************
1394 All table cells are 8 bits:
1395 bits 0..4: next state
1396 bits 5..7: action to perform (if > 0)
1398 Cells may be of format "n" where n represents the next state
1399 (except for the rightmost column).
1400 Cells may also be of format "s(x,y)" where x represents an action
1401 to perform and y represents the next state.
1403 *******************************************************************
1404 Definitions and type for properties state table
1405 *******************************************************************
1407 #define IMPTABPROPS_COLUMNS 16
1408 #define IMPTABPROPS_RES (IMPTABPROPS_COLUMNS - 1)
1409 #define GET_STATEPROPS(cell) ((cell)&0x1f)
1410 #define GET_ACTIONPROPS(cell) ((cell)>>5)
1411 #define s(action, newState) ((uint8_t)(newState+(action<<5)))
1413 static const uint8_t groupProp[] = /* dirProp regrouped */
1415 /* L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN FSI LRI RLI PDI ENL ENR */
1416 0, 1, 2, 7, 8, 3, 9, 6, 5, 4, 4, 10, 10, 12, 10, 10, 10, 11, 10, 4, 4, 4, 4, 13, 14
1418 enum { DirProp_L=0, DirProp_R=1, DirProp_EN=2, DirProp_AN=3, DirProp_ON=4, DirProp_S=5, DirProp_B=6 }; /* reduced dirProp */
1420 /******************************************************************
1422 PROPERTIES STATE TABLE
1424 In table impTabProps,
1425 - the ON column regroups ON and WS, FSI, RLI, LRI and PDI
1426 - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF
1427 - the Res column is the reduced property assigned to a run
1429 Action 1: process current run1, init new run1
1431 3: process run1, process run2, init new run1
1432 4: process run1, set run1=run2, init new run2
1435 1) This table is used in resolveImplicitLevels().
1436 2) This table triggers actions when there is a change in the Bidi
1437 property of incoming characters (action 1).
1438 3) Most such property sequences are processed immediately (in
1439 fact, passed to processPropertySeq().
1440 4) However, numbers are assembled as one sequence. This means
1441 that undefined situations (like CS following digits, until
1442 it is known if the next char will be a digit) are held until
1443 following chars define them.
1444 Example: digits followed by CS, then comes another CS or ON;
1445 the digits will be processed, then the CS assigned
1446 as the start of an ON sequence (action 3).
1447 5) There are cases where more than one sequence must be
1448 processed, for instance digits followed by CS followed by L:
1449 the digits must be processed as one sequence, and the CS
1450 must be processed as an ON sequence, all this before starting
1451 assembling chars for the opening L sequence.
1455 static const uint8_t impTabProps[][IMPTABPROPS_COLUMNS] =
1457 /* L , R , EN , AN , ON , S , B , ES , ET , CS , BN , NSM , AL , ENL , ENR , Res */
1458 /* 0 Init */ { 1 , 2 , 4 , 5 , 7 , 15 , 17 , 7 , 9 , 7 , 0 , 7 , 3 , 18 , 21 , DirProp_ON },
1459 /* 1 L */ { 1 , s(1,2), s(1,4), s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), s(1,9), s(1,7), 1 , 1 , s(1,3),s(1,18),s(1,21), DirProp_L },
1460 /* 2 R */ { s(1,1), 2 , s(1,4), s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), s(1,9), s(1,7), 2 , 2 , s(1,3),s(1,18),s(1,21), DirProp_R },
1461 /* 3 AL */ { s(1,1), s(1,2), s(1,6), s(1,6), s(1,8),s(1,16),s(1,17), s(1,8), s(1,8), s(1,8), 3 , 3 , 3 ,s(1,18),s(1,21), DirProp_R },
1462 /* 4 EN */ { s(1,1), s(1,2), 4 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,10), 11 ,s(2,10), 4 , 4 , s(1,3), 18 , 21 , DirProp_EN },
1463 /* 5 AN */ { s(1,1), s(1,2), s(1,4), 5 , s(1,7),s(1,15),s(1,17), s(1,7), s(1,9),s(2,12), 5 , 5 , s(1,3),s(1,18),s(1,21), DirProp_AN },
1464 /* 6 AL:EN/AN */ { s(1,1), s(1,2), 6 , 6 , s(1,8),s(1,16),s(1,17), s(1,8), s(1,8),s(2,13), 6 , 6 , s(1,3), 18 , 21 , DirProp_AN },
1465 /* 7 ON */ { s(1,1), s(1,2), s(1,4), s(1,5), 7 ,s(1,15),s(1,17), 7 ,s(2,14), 7 , 7 , 7 , s(1,3),s(1,18),s(1,21), DirProp_ON },
1466 /* 8 AL:ON */ { s(1,1), s(1,2), s(1,6), s(1,6), 8 ,s(1,16),s(1,17), 8 , 8 , 8 , 8 , 8 , s(1,3),s(1,18),s(1,21), DirProp_ON },
1467 /* 9 ET */ { s(1,1), s(1,2), 4 , s(1,5), 7 ,s(1,15),s(1,17), 7 , 9 , 7 , 9 , 9 , s(1,3), 18 , 21 , DirProp_ON },
1468 /*10 EN+ES/CS */ { s(3,1), s(3,2), 4 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7), 10 , s(4,7), s(3,3), 18 , 21 , DirProp_EN },
1469 /*11 EN+ET */ { s(1,1), s(1,2), 4 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), 11 , s(1,7), 11 , 11 , s(1,3), 18 , 21 , DirProp_EN },
1470 /*12 AN+CS */ { s(3,1), s(3,2), s(3,4), 5 , s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7), 12 , s(4,7), s(3,3),s(3,18),s(3,21), DirProp_AN },
1471 /*13 AL:EN/AN+CS */ { s(3,1), s(3,2), 6 , 6 , s(4,8),s(3,16),s(3,17), s(4,8), s(4,8), s(4,8), 13 , s(4,8), s(3,3), 18 , 21 , DirProp_AN },
1472 /*14 ON+ET */ { s(1,1), s(1,2), s(4,4), s(1,5), 7 ,s(1,15),s(1,17), 7 , 14 , 7 , 14 , 14 , s(1,3),s(4,18),s(4,21), DirProp_ON },
1473 /*15 S */ { s(1,1), s(1,2), s(1,4), s(1,5), s(1,7), 15 ,s(1,17), s(1,7), s(1,9), s(1,7), 15 , s(1,7), s(1,3),s(1,18),s(1,21), DirProp_S },
1474 /*16 AL:S */ { s(1,1), s(1,2), s(1,6), s(1,6), s(1,8), 16 ,s(1,17), s(1,8), s(1,8), s(1,8), 16 , s(1,8), s(1,3),s(1,18),s(1,21), DirProp_S },
1475 /*17 B */ { s(1,1), s(1,2), s(1,4), s(1,5), s(1,7),s(1,15), 17 , s(1,7), s(1,9), s(1,7), 17 , s(1,7), s(1,3),s(1,18),s(1,21), DirProp_B },
1476 /*18 ENL */ { s(1,1), s(1,2), 18 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,19), 20 ,s(2,19), 18 , 18 , s(1,3), 18 , 21 , DirProp_L },
1477 /*19 ENL+ES/CS */ { s(3,1), s(3,2), 18 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7), 19 , s(4,7), s(3,3), 18 , 21 , DirProp_L },
1478 /*20 ENL+ET */ { s(1,1), s(1,2), 18 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), 20 , s(1,7), 20 , 20 , s(1,3), 18 , 21 , DirProp_L },
1479 /*21 ENR */ { s(1,1), s(1,2), 21 , s(1,5), s(1,7),s(1,15),s(1,17),s(2,22), 23 ,s(2,22), 21 , 21 , s(1,3), 18 , 21 , DirProp_AN },
1480 /*22 ENR+ES/CS */ { s(3,1), s(3,2), 21 , s(3,5), s(4,7),s(3,15),s(3,17), s(4,7),s(4,14), s(4,7), 22 , s(4,7), s(3,3), 18 , 21 , DirProp_AN },
1481 /*23 ENR+ET */ { s(1,1), s(1,2), 21 , s(1,5), s(1,7),s(1,15),s(1,17), s(1,7), 23 , s(1,7), 23 , 23 , s(1,3), 18 , 21 , DirProp_AN }
1484 /* we must undef macro s because the levels tables have a different
1485 * structure (4 bits for action and 4 bits for next state.
1489 /******************************************************************
1490 The levels state machine tables
1491 *******************************************************************
1493 All table cells are 8 bits:
1494 bits 0..3: next state
1495 bits 4..7: action to perform (if > 0)
1497 Cells may be of format "n" where n represents the next state
1498 (except for the rightmost column).
1499 Cells may also be of format "s(x,y)" where x represents an action
1500 to perform and y represents the next state.
1502 This format limits each table to 16 states each and to 15 actions.
1504 *******************************************************************
1505 Definitions and type for levels state tables
1506 *******************************************************************
1508 #define IMPTABLEVELS_COLUMNS (DirProp_B + 2)
1509 #define IMPTABLEVELS_RES (IMPTABLEVELS_COLUMNS - 1)
1510 #define GET_STATE(cell) ((cell)&0x0f)
1511 #define GET_ACTION(cell) ((cell)>>4)
1512 #define s(action, newState) ((uint8_t)(newState+(action<<4)))
1514 typedef uint8_t ImpTab[][IMPTABLEVELS_COLUMNS];
1515 typedef uint8_t ImpAct[];
1517 /* FOOD FOR THOUGHT: each ImpTab should have its associated ImpAct,
1518 * instead of having a pair of ImpTab and a pair of ImpAct.
1520 typedef struct ImpTabPair {
1521 const void * pImpTab[2];
1522 const void * pImpAct[2];
1525 /******************************************************************
1529 In all levels state tables,
1530 - state 0 is the initial state
1531 - the Res column is the increment to add to the text level
1532 for this property sequence.
1534 The impAct arrays for each table of a pair map the local action
1535 numbers of the table to the total list of actions. For instance,
1536 action 2 in a given table corresponds to the action number which
1537 appears in entry [2] of the impAct array for that table.
1538 The first entry of all impAct arrays must be 0.
1540 Action 1: init conditional sequence
1541 2: prepend conditional sequence to current sequence
1542 3: set ON sequence to new level - 1
1543 4: init EN/AN/ON sequence
1544 5: fix EN/AN/ON sequence followed by R
1545 6: set previous level sequence to level 2
1548 1) These tables are used in processPropertySeq(). The input
1549 is property sequences as determined by resolveImplicitLevels.
1550 2) Most such property sequences are processed immediately
1551 (levels are assigned).
1552 3) However, some sequences cannot be assigned a final level till
1553 one or more following sequences are received. For instance,
1554 ON following an R sequence within an even-level paragraph.
1555 If the following sequence is R, the ON sequence will be
1556 assigned basic run level+1, and so will the R sequence.
1557 4) S is generally handled like ON, since its level will be fixed
1558 to paragraph level in adjustWSLevels().
1562 static const ImpTab impTabL_DEFAULT = /* Even paragraph level */
1563 /* In this table, conditional sequences receive the lower possible level
1564 until proven otherwise.
1567 /* L , R , EN , AN , ON , S , B , Res */
1568 /* 0 : init */ { 0 , 1 , 0 , 2 , 0 , 0 , 0 , 0 },
1569 /* 1 : R */ { 0 , 1 , 3 , 3 , s(1,4), s(1,4), 0 , 1 },
1570 /* 2 : AN */ { 0 , 1 , 0 , 2 , s(1,5), s(1,5), 0 , 2 },
1571 /* 3 : R+EN/AN */ { 0 , 1 , 3 , 3 , s(1,4), s(1,4), 0 , 2 },
1572 /* 4 : R+ON */ { 0 , s(2,1), s(3,3), s(3,3), 4 , 4 , 0 , 0 },
1573 /* 5 : AN+ON */ { 0 , s(2,1), 0 , s(3,2), 5 , 5 , 0 , 0 }
1575 static const ImpTab impTabR_DEFAULT = /* Odd paragraph level */
1576 /* In this table, conditional sequences receive the lower possible level
1577 until proven otherwise.
1580 /* L , R , EN , AN , ON , S , B , Res */
1581 /* 0 : init */ { 1 , 0 , 2 , 2 , 0 , 0 , 0 , 0 },
1582 /* 1 : L */ { 1 , 0 , 1 , 3 , s(1,4), s(1,4), 0 , 1 },
1583 /* 2 : EN/AN */ { 1 , 0 , 2 , 2 , 0 , 0 , 0 , 1 },
1584 /* 3 : L+AN */ { 1 , 0 , 1 , 3 , 5 , 5 , 0 , 1 },
1585 /* 4 : L+ON */ { s(2,1), 0 , s(2,1), 3 , 4 , 4 , 0 , 0 },
1586 /* 5 : L+AN+ON */ { 1 , 0 , 1 , 3 , 5 , 5 , 0 , 0 }
1588 static const ImpAct impAct0 = {0,1,2,3,4};
1589 static const ImpTabPair impTab_DEFAULT = {{&impTabL_DEFAULT,
1591 {&impAct0, &impAct0}};
1593 static const ImpTab impTabL_NUMBERS_SPECIAL = /* Even paragraph level */
1594 /* In this table, conditional sequences receive the lower possible level
1595 until proven otherwise.
1598 /* L , R , EN , AN , ON , S , B , Res */
1599 /* 0 : init */ { 0 , 2 , s(1,1), s(1,1), 0 , 0 , 0 , 0 },
1600 /* 1 : L+EN/AN */ { 0 , s(4,2), 1 , 1 , 0 , 0 , 0 , 0 },
1601 /* 2 : R */ { 0 , 2 , 4 , 4 , s(1,3), s(1,3), 0 , 1 },
1602 /* 3 : R+ON */ { 0 , s(2,2), s(3,4), s(3,4), 3 , 3 , 0 , 0 },
1603 /* 4 : R+EN/AN */ { 0 , 2 , 4 , 4 , s(1,3), s(1,3), 0 , 2 }
1605 static const ImpTabPair impTab_NUMBERS_SPECIAL = {{&impTabL_NUMBERS_SPECIAL,
1607 {&impAct0, &impAct0}};
1609 static const ImpTab impTabL_GROUP_NUMBERS_WITH_R =
1610 /* In this table, EN/AN+ON sequences receive levels as if associated with R
1611 until proven that there is L or sor/eor on both sides. AN is handled like EN.
1614 /* L , R , EN , AN , ON , S , B , Res */
1615 /* 0 init */ { 0 , 3 , s(1,1), s(1,1), 0 , 0 , 0 , 0 },
1616 /* 1 EN/AN */ { s(2,0), 3 , 1 , 1 , 2 , s(2,0), s(2,0), 2 },
1617 /* 2 EN/AN+ON */ { s(2,0), 3 , 1 , 1 , 2 , s(2,0), s(2,0), 1 },
1618 /* 3 R */ { 0 , 3 , 5 , 5 , s(1,4), 0 , 0 , 1 },
1619 /* 4 R+ON */ { s(2,0), 3 , 5 , 5 , 4 , s(2,0), s(2,0), 1 },
1620 /* 5 R+EN/AN */ { 0 , 3 , 5 , 5 , s(1,4), 0 , 0 , 2 }
1622 static const ImpTab impTabR_GROUP_NUMBERS_WITH_R =
1623 /* In this table, EN/AN+ON sequences receive levels as if associated with R
1624 until proven that there is L on both sides. AN is handled like EN.
1627 /* L , R , EN , AN , ON , S , B , Res */
1628 /* 0 init */ { 2 , 0 , 1 , 1 , 0 , 0 , 0 , 0 },
1629 /* 1 EN/AN */ { 2 , 0 , 1 , 1 , 0 , 0 , 0 , 1 },
1630 /* 2 L */ { 2 , 0 , s(1,4), s(1,4), s(1,3), 0 , 0 , 1 },
1631 /* 3 L+ON */ { s(2,2), 0 , 4 , 4 , 3 , 0 , 0 , 0 },
1632 /* 4 L+EN/AN */ { s(2,2), 0 , 4 , 4 , 3 , 0 , 0 , 1 }
1634 static const ImpTabPair impTab_GROUP_NUMBERS_WITH_R = {
1635 {&impTabL_GROUP_NUMBERS_WITH_R,
1636 &impTabR_GROUP_NUMBERS_WITH_R},
1637 {&impAct0, &impAct0}};
1640 static const ImpTab impTabL_INVERSE_NUMBERS_AS_L =
1641 /* This table is identical to the Default LTR table except that EN and AN are
1645 /* L , R , EN , AN , ON , S , B , Res */
1646 /* 0 : init */ { 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 },
1647 /* 1 : R */ { 0 , 1 , 0 , 0 , s(1,4), s(1,4), 0 , 1 },
1648 /* 2 : AN */ { 0 , 1 , 0 , 0 , s(1,5), s(1,5), 0 , 2 },
1649 /* 3 : R+EN/AN */ { 0 , 1 , 0 , 0 , s(1,4), s(1,4), 0 , 2 },
1650 /* 4 : R+ON */ { s(2,0), 1 , s(2,0), s(2,0), 4 , 4 , s(2,0), 1 },
1651 /* 5 : AN+ON */ { s(2,0), 1 , s(2,0), s(2,0), 5 , 5 , s(2,0), 1 }
1653 static const ImpTab impTabR_INVERSE_NUMBERS_AS_L =
1654 /* This table is identical to the Default RTL table except that EN and AN are
1658 /* L , R , EN , AN , ON , S , B , Res */
1659 /* 0 : init */ { 1 , 0 , 1 , 1 , 0 , 0 , 0 , 0 },
1660 /* 1 : L */ { 1 , 0 , 1 , 1 , s(1,4), s(1,4), 0 , 1 },
1661 /* 2 : EN/AN */ { 1 , 0 , 1 , 1 , 0 , 0 , 0 , 1 },
1662 /* 3 : L+AN */ { 1 , 0 , 1 , 1 , 5 , 5 , 0 , 1 },
1663 /* 4 : L+ON */ { s(2,1), 0 , s(2,1), s(2,1), 4 , 4 , 0 , 0 },
1664 /* 5 : L+AN+ON */ { 1 , 0 , 1 , 1 , 5 , 5 , 0 , 0 }
1666 static const ImpTabPair impTab_INVERSE_NUMBERS_AS_L = {
1667 {&impTabL_INVERSE_NUMBERS_AS_L,
1668 &impTabR_INVERSE_NUMBERS_AS_L},
1669 {&impAct0, &impAct0}};
1671 static const ImpTab impTabR_INVERSE_LIKE_DIRECT = /* Odd paragraph level */
1672 /* In this table, conditional sequences receive the lower possible level
1673 until proven otherwise.
1676 /* L , R , EN , AN , ON , S , B , Res */
1677 /* 0 : init */ { 1 , 0 , 2 , 2 , 0 , 0 , 0 , 0 },
1678 /* 1 : L */ { 1 , 0 , 1 , 2 , s(1,3), s(1,3), 0 , 1 },
1679 /* 2 : EN/AN */ { 1 , 0 , 2 , 2 , 0 , 0 , 0 , 1 },
1680 /* 3 : L+ON */ { s(2,1), s(3,0), 6 , 4 , 3 , 3 , s(3,0), 0 },
1681 /* 4 : L+ON+AN */ { s(2,1), s(3,0), 6 , 4 , 5 , 5 , s(3,0), 3 },
1682 /* 5 : L+AN+ON */ { s(2,1), s(3,0), 6 , 4 , 5 , 5 , s(3,0), 2 },
1683 /* 6 : L+ON+EN */ { s(2,1), s(3,0), 6 , 4 , 3 , 3 , s(3,0), 1 }
1685 static const ImpAct impAct1 = {0,1,13,14};
1686 /* FOOD FOR THOUGHT: in LTR table below, check case "JKL 123abc"
1688 static const ImpTabPair impTab_INVERSE_LIKE_DIRECT = {
1690 &impTabR_INVERSE_LIKE_DIRECT},
1691 {&impAct0, &impAct1}};
1693 static const ImpTab impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS =
1694 /* The case handled in this table is (visually): R EN L
1697 /* L , R , EN , AN , ON , S , B , Res */
1698 /* 0 : init */ { 0 , s(6,3), 0 , 1 , 0 , 0 , 0 , 0 },
1699 /* 1 : L+AN */ { 0 , s(6,3), 0 , 1 , s(1,2), s(3,0), 0 , 4 },
1700 /* 2 : L+AN+ON */ { s(2,0), s(6,3), s(2,0), 1 , 2 , s(3,0), s(2,0), 3 },
1701 /* 3 : R */ { 0 , s(6,3), s(5,5), s(5,6), s(1,4), s(3,0), 0 , 3 },
1702 /* 4 : R+ON */ { s(3,0), s(4,3), s(5,5), s(5,6), 4 , s(3,0), s(3,0), 3 },
1703 /* 5 : R+EN */ { s(3,0), s(4,3), 5 , s(5,6), s(1,4), s(3,0), s(3,0), 4 },
1704 /* 6 : R+AN */ { s(3,0), s(4,3), s(5,5), 6 , s(1,4), s(3,0), s(3,0), 4 }
1706 static const ImpTab impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS =
1707 /* The cases handled in this table are (visually): R EN L
1711 /* L , R , EN , AN , ON , S , B , Res */
1712 /* 0 : init */ { s(1,3), 0 , 1 , 1 , 0 , 0 , 0 , 0 },
1713 /* 1 : R+EN/AN */ { s(2,3), 0 , 1 , 1 , 2 , s(4,0), 0 , 1 },
1714 /* 2 : R+EN/AN+ON */ { s(2,3), 0 , 1 , 1 , 2 , s(4,0), 0 , 0 },
1715 /* 3 : L */ { 3 , 0 , 3 , s(3,6), s(1,4), s(4,0), 0 , 1 },
1716 /* 4 : L+ON */ { s(5,3), s(4,0), 5 , s(3,6), 4 , s(4,0), s(4,0), 0 },
1717 /* 5 : L+ON+EN */ { s(5,3), s(4,0), 5 , s(3,6), 4 , s(4,0), s(4,0), 1 },
1718 /* 6 : L+AN */ { s(5,3), s(4,0), 6 , 6 , 4 , s(4,0), s(4,0), 3 }
1720 static const ImpAct impAct2 = {0,1,2,5,6,7,8};
1721 static const ImpAct impAct3 = {0,1,9,10,11,12};
1722 static const ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = {
1723 {&impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS,
1724 &impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS},
1725 {&impAct2, &impAct3}};
1727 static const ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = {
1728 {&impTabL_NUMBERS_SPECIAL,
1729 &impTabR_INVERSE_LIKE_DIRECT},
1730 {&impAct0, &impAct1}};
1732 static const ImpTab impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS =
1733 /* The case handled in this table is (visually): R EN L
1736 /* L , R , EN , AN , ON , S , B , Res */
1737 /* 0 : init */ { 0 , s(6,2), 1 , 1 , 0 , 0 , 0 , 0 },
1738 /* 1 : L+EN/AN */ { 0 , s(6,2), 1 , 1 , 0 , s(3,0), 0 , 4 },
1739 /* 2 : R */ { 0 , s(6,2), s(5,4), s(5,4), s(1,3), s(3,0), 0 , 3 },
1740 /* 3 : R+ON */ { s(3,0), s(4,2), s(5,4), s(5,4), 3 , s(3,0), s(3,0), 3 },
1741 /* 4 : R+EN/AN */ { s(3,0), s(4,2), 4 , 4 , s(1,3), s(3,0), s(3,0), 4 }
1743 static const ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = {
1744 {&impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS,
1745 &impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS},
1746 {&impAct2, &impAct3}};
1751 const ImpTab * pImpTab; /* level table pointer */
1752 const ImpAct * pImpAct; /* action map array */
1753 int32_t startON; /* start of ON sequence */
1754 int32_t startL2EN; /* start of level 2 sequence */
1755 int32_t lastStrongRTL; /* index of last found R or AL */
1756 int32_t state; /* current state */
1757 int32_t runStart; /* start position of the run */
1758 UBiDiLevel runLevel; /* run level before implicit solving */
1761 /*------------------------------------------------------------------------*/
1764 addPoint(UBiDi *pBiDi, int32_t pos, int32_t flag)
1765 /* param pos: position where to insert
1766 param flag: one of LRM_BEFORE, LRM_AFTER, RLM_BEFORE, RLM_AFTER
1769 #define FIRSTALLOC 10
1771 InsertPoints * pInsertPoints=&(pBiDi->insertPoints);
1773 if (pInsertPoints->capacity == 0)
1775 pInsertPoints->points=uprv_malloc(sizeof(Point)*FIRSTALLOC);
1776 if (pInsertPoints->points == NULL)
1778 pInsertPoints->errorCode=U_MEMORY_ALLOCATION_ERROR;
1781 pInsertPoints->capacity=FIRSTALLOC;
1783 if (pInsertPoints->size >= pInsertPoints->capacity) /* no room for new point */
1785 void * savePoints=pInsertPoints->points;
1786 pInsertPoints->points=uprv_realloc(pInsertPoints->points,
1787 pInsertPoints->capacity*2*sizeof(Point));
1788 if (pInsertPoints->points == NULL)
1790 pInsertPoints->points=savePoints;
1791 pInsertPoints->errorCode=U_MEMORY_ALLOCATION_ERROR;
1794 else pInsertPoints->capacity*=2;
1798 pInsertPoints->points[pInsertPoints->size]=point;
1799 pInsertPoints->size++;
1804 setLevelsOutsideIsolates(UBiDi *pBiDi, int32_t start, int32_t limit, UBiDiLevel level)
1806 DirProp *dirProps=pBiDi->dirProps, dirProp;
1807 UBiDiLevel *levels=pBiDi->levels;
1808 int32_t isolateCount=0, k;
1809 for(k=start; k<limit; k++) {
1810 dirProp=dirProps[k];
1815 if(dirProp==LRI || dirProp==RLI)
1820 /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */
1823 * This implementation of the (Wn) rules applies all rules in one pass.
1824 * In order to do so, it needs a look-ahead of typically 1 character
1825 * (except for W5: sequences of ET) and keeps track of changes
1826 * in a rule Wp that affect a later Wq (p<q).
1828 * The (Nn) and (In) rules are also performed in that same single loop,
1829 * but effectively one iteration behind for white space.
1831 * Since all implicit rules are performed in one step, it is not necessary
1832 * to actually store the intermediate directional properties in dirProps[].
1836 processPropertySeq(UBiDi *pBiDi, LevState *pLevState, uint8_t _prop,
1837 int32_t start, int32_t limit) {
1838 uint8_t cell, oldStateSeq, actionSeq;
1839 const ImpTab * pImpTab=pLevState->pImpTab;
1840 const ImpAct * pImpAct=pLevState->pImpAct;
1841 UBiDiLevel * levels=pBiDi->levels;
1842 UBiDiLevel level, addLevel;
1843 InsertPoints * pInsertPoints;
1846 start0=start; /* save original start position */
1847 oldStateSeq=(uint8_t)pLevState->state;
1848 cell=(*pImpTab)[oldStateSeq][_prop];
1849 pLevState->state=GET_STATE(cell); /* isolate the new state */
1850 actionSeq=(*pImpAct)[GET_ACTION(cell)]; /* isolate the action */
1851 addLevel=(*pImpTab)[pLevState->state][IMPTABLEVELS_RES];
1855 case 1: /* init ON seq */
1856 pLevState->startON=start0;
1859 case 2: /* prepend ON seq to current seq */
1860 start=pLevState->startON;
1863 case 3: /* EN/AN after R+ON */
1864 level=pLevState->runLevel+1;
1865 setLevelsOutsideIsolates(pBiDi, pLevState->startON, start0, level);
1868 case 4: /* EN/AN before R for NUMBERS_SPECIAL */
1869 level=pLevState->runLevel+2;
1870 setLevelsOutsideIsolates(pBiDi, pLevState->startON, start0, level);
1873 case 5: /* L or S after possible relevant EN/AN */
1874 /* check if we had EN after R/AL */
1875 if (pLevState->startL2EN >= 0) {
1876 addPoint(pBiDi, pLevState->startL2EN, LRM_BEFORE);
1878 pLevState->startL2EN=-1; /* not within previous if since could also be -2 */
1879 /* check if we had any relevant EN/AN after R/AL */
1880 pInsertPoints=&(pBiDi->insertPoints);
1881 if ((pInsertPoints->capacity == 0) ||
1882 (pInsertPoints->size <= pInsertPoints->confirmed))
1884 /* nothing, just clean up */
1885 pLevState->lastStrongRTL=-1;
1886 /* check if we have a pending conditional segment */
1887 level=(*pImpTab)[oldStateSeq][IMPTABLEVELS_RES];
1888 if ((level & 1) && (pLevState->startON > 0)) { /* after ON */
1889 start=pLevState->startON; /* reset to basic run level */
1891 if (_prop == DirProp_S) /* add LRM before S */
1893 addPoint(pBiDi, start0, LRM_BEFORE);
1894 pInsertPoints->confirmed=pInsertPoints->size;
1898 /* reset previous RTL cont to level for LTR text */
1899 for (k=pLevState->lastStrongRTL+1; k<start0; k++)
1901 /* reset odd level, leave runLevel+2 as is */
1902 levels[k]=(levels[k] - 2) & ~1;
1904 /* mark insert points as confirmed */
1905 pInsertPoints->confirmed=pInsertPoints->size;
1906 pLevState->lastStrongRTL=-1;
1907 if (_prop == DirProp_S) /* add LRM before S */
1909 addPoint(pBiDi, start0, LRM_BEFORE);
1910 pInsertPoints->confirmed=pInsertPoints->size;
1914 case 6: /* R/AL after possible relevant EN/AN */
1916 pInsertPoints=&(pBiDi->insertPoints);
1917 if (pInsertPoints->capacity > 0)
1918 /* remove all non confirmed insert points */
1919 pInsertPoints->size=pInsertPoints->confirmed;
1920 pLevState->startON=-1;
1921 pLevState->startL2EN=-1;
1922 pLevState->lastStrongRTL=limit - 1;
1925 case 7: /* EN/AN after R/AL + possible cont */
1926 /* check for real AN */
1927 if ((_prop == DirProp_AN) && (pBiDi->dirProps[start0] == AN) &&
1928 (pBiDi->reorderingMode!=UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL))
1931 if (pLevState->startL2EN == -1) /* if no relevant EN already found */
1933 /* just note the righmost digit as a strong RTL */
1934 pLevState->lastStrongRTL=limit - 1;
1937 if (pLevState->startL2EN >= 0) /* after EN, no AN */
1939 addPoint(pBiDi, pLevState->startL2EN, LRM_BEFORE);
1940 pLevState->startL2EN=-2;
1943 addPoint(pBiDi, start0, LRM_BEFORE);
1946 /* if first EN/AN after R/AL */
1947 if (pLevState->startL2EN == -1) {
1948 pLevState->startL2EN=start0;
1952 case 8: /* note location of latest R/AL */
1953 pLevState->lastStrongRTL=limit - 1;
1954 pLevState->startON=-1;
1957 case 9: /* L after R+ON/EN/AN */
1958 /* include possible adjacent number on the left */
1959 for (k=start0-1; k>=0 && !(levels[k]&1); k--);
1961 addPoint(pBiDi, k, RLM_BEFORE); /* add RLM before */
1962 pInsertPoints=&(pBiDi->insertPoints);
1963 pInsertPoints->confirmed=pInsertPoints->size; /* confirm it */
1965 pLevState->startON=start0;
1968 case 10: /* AN after L */
1969 /* AN numbers between L text on both sides may be trouble. */
1970 /* tentatively bracket with LRMs; will be confirmed if followed by L */
1971 addPoint(pBiDi, start0, LRM_BEFORE); /* add LRM before */
1972 addPoint(pBiDi, start0, LRM_AFTER); /* add LRM after */
1975 case 11: /* R after L+ON/EN/AN */
1976 /* false alert, infirm LRMs around previous AN */
1977 pInsertPoints=&(pBiDi->insertPoints);
1978 pInsertPoints->size=pInsertPoints->confirmed;
1979 if (_prop == DirProp_S) /* add RLM before S */
1981 addPoint(pBiDi, start0, RLM_BEFORE);
1982 pInsertPoints->confirmed=pInsertPoints->size;
1986 case 12: /* L after L+ON/AN */
1987 level=pLevState->runLevel + addLevel;
1988 for(k=pLevState->startON; k<start0; k++) {
1989 if (levels[k]<level)
1992 pInsertPoints=&(pBiDi->insertPoints);
1993 pInsertPoints->confirmed=pInsertPoints->size; /* confirm inserts */
1994 pLevState->startON=start0;
1997 case 13: /* L after L+ON+EN/AN/ON */
1998 level=pLevState->runLevel;
1999 for(k=start0-1; k>=pLevState->startON; k--) {
2000 if(levels[k]==level+3) {
2001 while(levels[k]==level+3) {
2004 while(levels[k]==level) {
2008 if(levels[k]==level+2) {
2016 case 14: /* R after L+ON+EN/AN/ON */
2017 level=pLevState->runLevel+1;
2018 for(k=start0-1; k>=pLevState->startON; k--) {
2019 if(levels[k]>level) {
2025 default: /* we should never get here */
2030 if((addLevel) || (start < start0)) {
2031 level=pLevState->runLevel + addLevel;
2032 if(start>=pLevState->runStart) {
2033 for(k=start; k<limit; k++) {
2037 setLevelsOutsideIsolates(pBiDi, start, limit, level);
2043 * Returns the directionality of the last strong character at the end of the prologue, if any.
2044 * Requires prologue!=null.
2047 lastL_R_AL(UBiDi *pBiDi) {
2048 const UChar *text=pBiDi->prologue;
2049 int32_t length=pBiDi->proLength;
2053 for(i=length; i>0; ) {
2054 /* i is decremented by U16_PREV */
2055 U16_PREV(text, 0, i, uchar);
2056 dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar);
2060 if(dirProp==R || dirProp==AL) {
2071 * Returns the directionality of the first strong character, or digit, in the epilogue, if any.
2072 * Requires epilogue!=null.
2075 firstL_R_AL_EN_AN(UBiDi *pBiDi) {
2076 const UChar *text=pBiDi->epilogue;
2077 int32_t length=pBiDi->epiLength;
2081 for(i=0; i<length; ) {
2082 /* i is incremented by U16_NEXT */
2083 U16_NEXT(text, i, length, uchar);
2084 dirProp=(DirProp)ubidi_getCustomizedClass(pBiDi, uchar);
2088 if(dirProp==R || dirProp==AL) {
2102 resolveImplicitLevels(UBiDi *pBiDi,
2103 int32_t start, int32_t limit,
2104 DirProp sor, DirProp eor) {
2105 const DirProp *dirProps=pBiDi->dirProps;
2108 int32_t i, start1, start2;
2109 uint16_t oldStateImp, stateImp, actionImp;
2110 uint8_t gprop, resProp, cell;
2112 DirProp nextStrongProp=R;
2113 int32_t nextStrongPos=-1;
2115 /* check for RTL inverse BiDi mode */
2116 /* FOOD FOR THOUGHT: in case of RTL inverse BiDi, it would make sense to
2117 * loop on the text characters from end to start.
2118 * This would need a different properties state table (at least different
2119 * actions) and different levels state tables (maybe very similar to the
2120 * LTR corresponding ones.
2123 ((start<pBiDi->lastArabicPos) && (GET_PARALEVEL(pBiDi, start) & 1) &&
2124 (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT ||
2125 pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL));
2127 /* initialize for property and levels state tables */
2128 levState.startL2EN=-1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
2129 levState.lastStrongRTL=-1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
2130 levState.runStart=start;
2131 levState.runLevel=pBiDi->levels[start];
2132 levState.pImpTab=(const ImpTab*)((pBiDi->pImpTabPair)->pImpTab)[levState.runLevel&1];
2133 levState.pImpAct=(const ImpAct*)((pBiDi->pImpTabPair)->pImpAct)[levState.runLevel&1];
2134 if(start==0 && pBiDi->proLength>0) {
2135 DirProp lastStrong=lastL_R_AL(pBiDi);
2136 if(lastStrong!=DirProp_ON) {
2140 /* The isolates[] entries contain enough information to
2141 resume the bidi algorithm in the same state as it was
2142 when it was interrupted by an isolate sequence. */
2143 if(dirProps[start]==PDI && pBiDi->isolateCount >= 0) {
2144 levState.startON=pBiDi->isolates[pBiDi->isolateCount].startON;
2145 start1=pBiDi->isolates[pBiDi->isolateCount].start1;
2146 stateImp=pBiDi->isolates[pBiDi->isolateCount].stateImp;
2147 levState.state=pBiDi->isolates[pBiDi->isolateCount].state;
2148 pBiDi->isolateCount--;
2150 levState.startON=-1;
2152 if(dirProps[start]==NSM)
2157 processPropertySeq(pBiDi, &levState, sor, start, start);
2159 start2=start; /* to make Java compiler happy */
2161 for(i=start; i<=limit; i++) {
2164 for(k=limit-1; k>start&&(DIRPROP_FLAG(dirProps[k])&MASK_BN_EXPLICIT); k--);
2165 dirProp=dirProps[k];
2166 if(dirProp==LRI || dirProp==RLI)
2167 break; /* no forced closing for sequence ending with LRI/RLI */
2170 DirProp prop, prop1;
2173 pBiDi->isolateCount=-1; /* current isolates stack entry == none */
2177 /* AL before EN does not make it AN */
2179 } else if(prop==EN) {
2180 if(nextStrongPos<=i) {
2181 /* look for next strong char (L/R/AL) */
2183 nextStrongProp=R; /* set default */
2184 nextStrongPos=limit;
2185 for(j=i+1; j<limit; j++) {
2187 if(prop1==L || prop1==R || prop1==AL) {
2188 nextStrongProp=prop1;
2194 if(nextStrongProp==AL) {
2199 gprop=groupProp[prop];
2201 oldStateImp=stateImp;
2202 cell=impTabProps[oldStateImp][gprop];
2203 stateImp=GET_STATEPROPS(cell); /* isolate the new state */
2204 actionImp=GET_ACTIONPROPS(cell); /* isolate the action */
2205 if((i==limit) && (actionImp==0)) {
2206 /* there is an unprocessed sequence if its property == eor */
2207 actionImp=1; /* process the last sequence */
2210 resProp=impTabProps[oldStateImp][IMPTABPROPS_RES];
2212 case 1: /* process current seq1, init new seq1 */
2213 processPropertySeq(pBiDi, &levState, resProp, start1, i);
2216 case 2: /* init new seq2 */
2219 case 3: /* process seq1, process seq2, init new seq1 */
2220 processPropertySeq(pBiDi, &levState, resProp, start1, start2);
2221 processPropertySeq(pBiDi, &levState, DirProp_ON, start2, i);
2224 case 4: /* process seq1, set seq1=seq2, init new seq2 */
2225 processPropertySeq(pBiDi, &levState, resProp, start1, start2);
2229 default: /* we should never get here */
2236 /* flush possible pending sequence, e.g. ON */
2237 if(limit==pBiDi->length && pBiDi->epiLength>0) {
2238 DirProp firstStrong=firstL_R_AL_EN_AN(pBiDi);
2239 if(firstStrong!=DirProp_ON) {
2244 /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */
2245 for(i=limit-1; i>start&&(DIRPROP_FLAG(dirProps[i])&MASK_BN_EXPLICIT); i--);
2246 dirProp=dirProps[i];
2247 if((dirProp==LRI || dirProp==RLI) && limit<pBiDi->length) {
2248 pBiDi->isolateCount++;
2249 pBiDi->isolates[pBiDi->isolateCount].stateImp=stateImp;
2250 pBiDi->isolates[pBiDi->isolateCount].state=levState.state;
2251 pBiDi->isolates[pBiDi->isolateCount].start1=start1;
2252 pBiDi->isolates[pBiDi->isolateCount].startON=levState.startON;
2255 processPropertySeq(pBiDi, &levState, eor, limit, limit);
2258 /* perform (L1) and (X9) ---------------------------------------------------- */
2261 * Reset the embedding levels for some non-graphic characters (L1).
2262 * This function also sets appropriate levels for BN, and
2263 * explicit embedding types that are supposed to have been removed
2264 * from the paragraph in (X9).
2267 adjustWSLevels(UBiDi *pBiDi) {
2268 const DirProp *dirProps=pBiDi->dirProps;
2269 UBiDiLevel *levels=pBiDi->levels;
2272 if(pBiDi->flags&MASK_WS) {
2273 UBool orderParagraphsLTR=pBiDi->orderParagraphsLTR;
2276 i=pBiDi->trailingWSStart;
2278 /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */
2279 while(i>0 && (flag=DIRPROP_FLAG(dirProps[--i]))&MASK_WS) {
2280 if(orderParagraphsLTR&&(flag&DIRPROP_FLAG(B))) {
2283 levels[i]=GET_PARALEVEL(pBiDi, i);
2287 /* reset BN to the next character's paraLevel until B/S, which restarts above loop */
2288 /* here, i+1 is guaranteed to be <length */
2290 flag=DIRPROP_FLAG(dirProps[--i]);
2291 if(flag&MASK_BN_EXPLICIT) {
2292 levels[i]=levels[i+1];
2293 } else if(orderParagraphsLTR&&(flag&DIRPROP_FLAG(B))) {
2296 } else if(flag&MASK_B_S) {
2297 levels[i]=GET_PARALEVEL(pBiDi, i);
2305 U_CAPI void U_EXPORT2
2306 ubidi_setContext(UBiDi *pBiDi,
2307 const UChar *prologue, int32_t proLength,
2308 const UChar *epilogue, int32_t epiLength,
2309 UErrorCode *pErrorCode) {
2310 /* check the argument values */
2311 RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
2312 if(pBiDi==NULL || proLength<-1 || epiLength<-1 ||
2313 (prologue==NULL && proLength!=0) || (epilogue==NULL && epiLength!=0)) {
2314 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2319 pBiDi->proLength=u_strlen(prologue);
2321 pBiDi->proLength=proLength;
2324 pBiDi->epiLength=u_strlen(epilogue);
2326 pBiDi->epiLength=epiLength;
2328 pBiDi->prologue=prologue;
2329 pBiDi->epilogue=epilogue;
2333 setParaSuccess(UBiDi *pBiDi) {
2334 pBiDi->proLength=0; /* forget the last context */
2336 pBiDi->pParaBiDi=pBiDi; /* mark successful setPara */
2339 #define BIDI_MIN(x, y) ((x)<(y) ? (x) : (y))
2340 #define BIDI_ABS(x) ((x)>=0 ? (x) : (-(x)))
2343 setParaRunsOnly(UBiDi *pBiDi, const UChar *text, int32_t length,
2344 UBiDiLevel paraLevel, UErrorCode *pErrorCode) {
2345 void *runsOnlyMemory = NULL;
2348 int32_t saveLength, saveTrailingWSStart;
2349 const UBiDiLevel *levels;
2350 UBiDiLevel *saveLevels;
2351 UBiDiDirection saveDirection;
2352 UBool saveMayAllocateText;
2354 int32_t visualLength, i, j, visualStart, logicalStart,
2355 runCount, runLength, addedRuns, insertRemove,
2356 start, limit, step, indexOddBit, logicalPos,
2358 uint32_t saveOptions;
2360 pBiDi->reorderingMode=UBIDI_REORDER_DEFAULT;
2362 ubidi_setPara(pBiDi, text, length, paraLevel, NULL, pErrorCode);
2365 /* obtain memory for mapping table and visual text */
2366 runsOnlyMemory=uprv_malloc(length*(sizeof(int32_t)+sizeof(UChar)+sizeof(UBiDiLevel)));
2367 if(runsOnlyMemory==NULL) {
2368 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
2371 visualMap=runsOnlyMemory;
2372 visualText=(UChar *)&visualMap[length];
2373 saveLevels=(UBiDiLevel *)&visualText[length];
2374 saveOptions=pBiDi->reorderingOptions;
2375 if(saveOptions & UBIDI_OPTION_INSERT_MARKS) {
2376 pBiDi->reorderingOptions&=~UBIDI_OPTION_INSERT_MARKS;
2377 pBiDi->reorderingOptions|=UBIDI_OPTION_REMOVE_CONTROLS;
2379 paraLevel&=1; /* accept only 0 or 1 */
2380 ubidi_setPara(pBiDi, text, length, paraLevel, NULL, pErrorCode);
2381 if(U_FAILURE(*pErrorCode)) {
2384 /* we cannot access directly pBiDi->levels since it is not yet set if
2385 * direction is not MIXED
2387 levels=ubidi_getLevels(pBiDi, pErrorCode);
2388 uprv_memcpy(saveLevels, levels, (size_t)pBiDi->length*sizeof(UBiDiLevel));
2389 saveTrailingWSStart=pBiDi->trailingWSStart;
2390 saveLength=pBiDi->length;
2391 saveDirection=pBiDi->direction;
2393 /* FOOD FOR THOUGHT: instead of writing the visual text, we could use
2394 * the visual map and the dirProps array to drive the second call
2395 * to ubidi_setPara (but must make provision for possible removal of
2396 * BiDi controls. Alternatively, only use the dirProps array via
2397 * customized classifier callback.
2399 visualLength=ubidi_writeReordered(pBiDi, visualText, length,
2400 UBIDI_DO_MIRRORING, pErrorCode);
2401 ubidi_getVisualMap(pBiDi, visualMap, pErrorCode);
2402 if(U_FAILURE(*pErrorCode)) {
2405 pBiDi->reorderingOptions=saveOptions;
2407 pBiDi->reorderingMode=UBIDI_REORDER_INVERSE_LIKE_DIRECT;
2409 /* Because what we did with reorderingOptions, visualText may be shorter
2410 * than the original text. But we don't want the levels memory to be
2411 * reallocated shorter than the original length, since we need to restore
2412 * the levels as after the first call to ubidi_setpara() before returning.
2413 * We will force mayAllocateText to FALSE before the second call to
2414 * ubidi_setpara(), and will restore it afterwards.
2416 saveMayAllocateText=pBiDi->mayAllocateText;
2417 pBiDi->mayAllocateText=FALSE;
2418 ubidi_setPara(pBiDi, visualText, visualLength, paraLevel, NULL, pErrorCode);
2419 pBiDi->mayAllocateText=saveMayAllocateText;
2420 ubidi_getRuns(pBiDi, pErrorCode);
2421 if(U_FAILURE(*pErrorCode)) {
2424 /* check if some runs must be split, count how many splits */
2426 runCount=pBiDi->runCount;
2429 for(i=0; i<runCount; i++, visualStart+=runLength) {
2430 runLength=runs[i].visualLimit-visualStart;
2434 logicalStart=GET_INDEX(runs[i].logicalStart);
2435 for(j=logicalStart+1; j<logicalStart+runLength; j++) {
2436 index0=visualMap[j];
2437 index1=visualMap[j-1];
2438 if((BIDI_ABS(index0-index1)!=1) || (saveLevels[index0]!=saveLevels[index1])) {
2444 if(getRunsMemory(pBiDi, runCount+addedRuns)) {
2446 /* because we switch from UBiDi.simpleRuns to UBiDi.runs */
2447 pBiDi->runsMemory[0]=runs[0];
2449 runs=pBiDi->runs=pBiDi->runsMemory;
2450 pBiDi->runCount+=addedRuns;
2455 /* split runs which are not consecutive in source text */
2456 for(i=runCount-1; i>=0; i--) {
2457 runLength= i==0 ? runs[0].visualLimit :
2458 runs[i].visualLimit-runs[i-1].visualLimit;
2459 logicalStart=runs[i].logicalStart;
2460 indexOddBit=GET_ODD_BIT(logicalStart);
2461 logicalStart=GET_INDEX(logicalStart);
2464 runs[i+addedRuns]=runs[i];
2466 logicalPos=visualMap[logicalStart];
2467 runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
2468 saveLevels[logicalPos]^indexOddBit);
2473 limit=logicalStart+runLength-1;
2476 start=logicalStart+runLength-1;
2480 for(j=start; j!=limit; j+=step) {
2481 index0=visualMap[j];
2482 index1=visualMap[j+step];
2483 if((BIDI_ABS(index0-index1)!=1) || (saveLevels[index0]!=saveLevels[index1])) {
2484 logicalPos=BIDI_MIN(visualMap[start], index0);
2485 runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
2486 saveLevels[logicalPos]^indexOddBit);
2487 runs[i+addedRuns].visualLimit=runs[i].visualLimit;
2488 runs[i].visualLimit-=BIDI_ABS(j-start)+1;
2489 insertRemove=runs[i].insertRemove&(LRM_AFTER|RLM_AFTER);
2490 runs[i+addedRuns].insertRemove=insertRemove;
2491 runs[i].insertRemove&=~insertRemove;
2497 runs[i+addedRuns]=runs[i];
2499 logicalPos=BIDI_MIN(visualMap[start], visualMap[limit]);
2500 runs[i+addedRuns].logicalStart=MAKE_INDEX_ODD_PAIR(logicalPos,
2501 saveLevels[logicalPos]^indexOddBit);
2505 /* restore initial paraLevel */
2506 pBiDi->paraLevel^=1;
2508 /* restore real text */
2510 pBiDi->length=saveLength;
2511 pBiDi->originalLength=length;
2512 pBiDi->direction=saveDirection;
2513 /* the saved levels should never excess levelsSize, but we check anyway */
2514 if(saveLength>pBiDi->levelsSize) {
2515 saveLength=pBiDi->levelsSize;
2517 uprv_memcpy(pBiDi->levels, saveLevels, (size_t)saveLength*sizeof(UBiDiLevel));
2518 pBiDi->trailingWSStart=saveTrailingWSStart;
2519 if(pBiDi->runCount>1) {
2520 pBiDi->direction=UBIDI_MIXED;
2523 /* free memory for mapping table and visual text */
2524 uprv_free(runsOnlyMemory);
2526 pBiDi->reorderingMode=UBIDI_REORDER_RUNS_ONLY;
2529 /* ubidi_setPara ------------------------------------------------------------ */
2531 U_CAPI void U_EXPORT2
2532 ubidi_setPara(UBiDi *pBiDi, const UChar *text, int32_t length,
2533 UBiDiLevel paraLevel, UBiDiLevel *embeddingLevels,
2534 UErrorCode *pErrorCode) {
2535 UBiDiDirection direction;
2538 /* check the argument values */
2539 RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
2540 if(pBiDi==NULL || text==NULL || length<-1 ||
2541 (paraLevel>UBIDI_MAX_EXPLICIT_LEVEL && paraLevel<UBIDI_DEFAULT_LTR)) {
2542 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2547 length=u_strlen(text);
2550 /* special treatment for RUNS_ONLY mode */
2551 if(pBiDi->reorderingMode==UBIDI_REORDER_RUNS_ONLY) {
2552 setParaRunsOnly(pBiDi, text, length, paraLevel, pErrorCode);
2556 /* initialize the UBiDi structure */
2557 pBiDi->pParaBiDi=NULL; /* mark unfinished setPara */
2559 pBiDi->length=pBiDi->originalLength=pBiDi->resultLength=length;
2560 pBiDi->paraLevel=paraLevel;
2561 pBiDi->direction=paraLevel&1;
2564 pBiDi->dirProps=NULL;
2567 pBiDi->insertPoints.size=0; /* clean up from last call */
2568 pBiDi->insertPoints.confirmed=0; /* clean up from last call */
2571 * Save the original paraLevel if contextual; otherwise, set to 0.
2573 pBiDi->defaultParaLevel=IS_DEFAULT_LEVEL(paraLevel);
2577 * For an empty paragraph, create a UBiDi object with the paraLevel and
2578 * the flags and the direction set but without allocating zero-length arrays.
2579 * There is nothing more to do.
2581 if(IS_DEFAULT_LEVEL(paraLevel)) {
2582 pBiDi->paraLevel&=1;
2583 pBiDi->defaultParaLevel=0;
2585 pBiDi->flags=DIRPROP_FLAG_LR(paraLevel);
2588 setParaSuccess(pBiDi); /* mark successful setPara */
2594 /* allocate paras memory */
2595 if(pBiDi->parasMemory)
2596 pBiDi->paras=pBiDi->parasMemory;
2598 pBiDi->paras=pBiDi->simpleParas;
2601 * Get the directional properties,
2602 * the flags bit-set, and
2603 * determine the paragraph level if necessary.
2605 if(getDirPropsMemory(pBiDi, length)) {
2606 pBiDi->dirProps=pBiDi->dirPropsMemory;
2607 if(!getDirProps(pBiDi)) {
2608 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
2612 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
2615 dirProps=pBiDi->dirProps;
2616 /* the processed length may have changed if UBIDI_OPTION_STREAMING */
2617 length= pBiDi->length;
2618 pBiDi->trailingWSStart=length; /* the levels[] will reflect the WS run */
2620 /* are explicit levels specified? */
2621 if(embeddingLevels==NULL) {
2622 /* no: determine explicit levels according to the (Xn) rules */\
2623 if(getLevelsMemory(pBiDi, length)) {
2624 pBiDi->levels=pBiDi->levelsMemory;
2625 direction=resolveExplicitLevels(pBiDi, pErrorCode);
2626 if(U_FAILURE(*pErrorCode)) {
2630 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
2634 /* set BN for all explicit codes, check that all levels are 0 or paraLevel..UBIDI_MAX_EXPLICIT_LEVEL */
2635 pBiDi->levels=embeddingLevels;
2636 direction=checkExplicitLevels(pBiDi, pErrorCode);
2637 if(U_FAILURE(*pErrorCode)) {
2642 /* allocate isolate memory */
2643 if(pBiDi->isolateCount<=SIMPLE_ISOLATES_COUNT)
2644 pBiDi->isolates=pBiDi->simpleIsolates;
2646 if((int32_t)(pBiDi->isolateCount*sizeof(Isolate))<=pBiDi->isolatesSize)
2647 pBiDi->isolates=pBiDi->isolatesMemory;
2649 if(getInitialIsolatesMemory(pBiDi, pBiDi->isolateCount)) {
2650 pBiDi->isolates=pBiDi->isolatesMemory;
2652 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
2656 pBiDi->isolateCount=-1; /* current isolates stack entry == none */
2659 * The steps after (X9) in the UBiDi algorithm are performed only if
2660 * the paragraph text has mixed directionality!
2662 pBiDi->direction=direction;
2665 /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
2666 pBiDi->trailingWSStart=0;
2669 /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */
2670 pBiDi->trailingWSStart=0;
2674 * Choose the right implicit state table
2676 switch(pBiDi->reorderingMode) {
2677 case UBIDI_REORDER_DEFAULT:
2678 pBiDi->pImpTabPair=&impTab_DEFAULT;
2680 case UBIDI_REORDER_NUMBERS_SPECIAL:
2681 pBiDi->pImpTabPair=&impTab_NUMBERS_SPECIAL;
2683 case UBIDI_REORDER_GROUP_NUMBERS_WITH_R:
2684 pBiDi->pImpTabPair=&impTab_GROUP_NUMBERS_WITH_R;
2686 case UBIDI_REORDER_INVERSE_NUMBERS_AS_L:
2687 pBiDi->pImpTabPair=&impTab_INVERSE_NUMBERS_AS_L;
2689 case UBIDI_REORDER_INVERSE_LIKE_DIRECT:
2690 if (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
2691 pBiDi->pImpTabPair=&impTab_INVERSE_LIKE_DIRECT_WITH_MARKS;
2693 pBiDi->pImpTabPair=&impTab_INVERSE_LIKE_DIRECT;
2696 case UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
2697 if (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) {
2698 pBiDi->pImpTabPair=&impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS;
2700 pBiDi->pImpTabPair=&impTab_INVERSE_FOR_NUMBERS_SPECIAL;
2704 /* we should never get here */
2709 * If there are no external levels specified and there
2710 * are no significant explicit level codes in the text,
2711 * then we can treat the entire paragraph as one run.
2712 * Otherwise, we need to perform the following rules on runs of
2713 * the text with the same embedding levels. (X10)
2714 * "Significant" explicit level codes are ones that actually
2715 * affect non-BN characters.
2716 * Examples for "insignificant" ones are empty embeddings
2717 * LRE-PDF, LRE-RLE-PDF-PDF, etc.
2719 if(embeddingLevels==NULL && pBiDi->paraCount<=1 &&
2720 !(pBiDi->flags&DIRPROP_FLAG_MULTI_RUNS)) {
2721 resolveImplicitLevels(pBiDi, 0, length,
2722 GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, 0)),
2723 GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, length-1)));
2725 /* sor, eor: start and end types of same-level-run */
2726 UBiDiLevel *levels=pBiDi->levels;
2727 int32_t start, limit=0;
2728 UBiDiLevel level, nextLevel;
2731 /* determine the first sor and set eor to it because of the loop body (sor=eor there) */
2732 level=GET_PARALEVEL(pBiDi, 0);
2733 nextLevel=levels[0];
2734 if(level<nextLevel) {
2735 eor=GET_LR_FROM_LEVEL(nextLevel);
2737 eor=GET_LR_FROM_LEVEL(level);
2741 /* determine start and limit of the run (end points just behind the run) */
2743 /* the values for this run's start are the same as for the previous run's end */
2746 if((start>0) && (dirProps[start-1]==B)) {
2747 /* except if this is a new paragraph, then set sor = para level */
2748 sor=GET_LR_FROM_LEVEL(GET_PARALEVEL(pBiDi, start));
2753 /* search for the limit of this run */
2754 while((++limit<length) &&
2755 ((levels[limit]==level) ||
2756 (DIRPROP_FLAG(dirProps[limit])&MASK_BN_EXPLICIT))) {}
2758 /* get the correct level of the next run */
2760 nextLevel=levels[limit];
2762 nextLevel=GET_PARALEVEL(pBiDi, length-1);
2765 /* determine eor from max(level, nextLevel); sor is last run's eor */
2766 if(NO_OVERRIDE(level)<NO_OVERRIDE(nextLevel)) {
2767 eor=GET_LR_FROM_LEVEL(nextLevel);
2769 eor=GET_LR_FROM_LEVEL(level);
2772 /* if the run consists of overridden directional types, then there
2773 are no implicit types to be resolved */
2774 if(!(level&UBIDI_LEVEL_OVERRIDE)) {
2775 resolveImplicitLevels(pBiDi, start, limit, sor, eor);
2777 /* remove the UBIDI_LEVEL_OVERRIDE flags */
2779 levels[start++]&=~UBIDI_LEVEL_OVERRIDE;
2780 } while(start<limit);
2782 } while(limit<length);
2784 /* check if we got any memory shortage while adding insert points */
2785 if (U_FAILURE(pBiDi->insertPoints.errorCode))
2787 *pErrorCode=pBiDi->insertPoints.errorCode;
2790 /* reset the embedding levels for some non-graphic characters (L1), (X9) */
2791 adjustWSLevels(pBiDi);
2794 /* add RLM for inverse Bidi with contextual orientation resolving
2795 * to RTL which would not round-trip otherwise
2797 if((pBiDi->defaultParaLevel>0) &&
2798 (pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) &&
2799 ((pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_LIKE_DIRECT) ||
2800 (pBiDi->reorderingMode==UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) {
2801 int32_t i, j, start, last;
2804 for(i=0; i<pBiDi->paraCount; i++) {
2805 last=(pBiDi->paras[i].limit)-1;
2806 level=pBiDi->paras[i].level;
2808 continue; /* LTR paragraph */
2809 start= i==0 ? 0 : pBiDi->paras[i-1].limit;
2810 for(j=last; j>=start; j--) {
2811 dirProp=dirProps[j];
2814 while(dirProps[last]==B) {
2818 addPoint(pBiDi, last, RLM_BEFORE);
2821 if(DIRPROP_FLAG(dirProp) & MASK_R_AL) {
2828 if(pBiDi->reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) {
2829 pBiDi->resultLength -= pBiDi->controlCount;
2831 pBiDi->resultLength += pBiDi->insertPoints.size;
2833 setParaSuccess(pBiDi); /* mark successful setPara */
2836 U_CAPI void U_EXPORT2
2837 ubidi_orderParagraphsLTR(UBiDi *pBiDi, UBool orderParagraphsLTR) {
2839 pBiDi->orderParagraphsLTR=orderParagraphsLTR;
2843 U_CAPI UBool U_EXPORT2
2844 ubidi_isOrderParagraphsLTR(UBiDi *pBiDi) {
2846 return pBiDi->orderParagraphsLTR;
2852 U_CAPI UBiDiDirection U_EXPORT2
2853 ubidi_getDirection(const UBiDi *pBiDi) {
2854 if(IS_VALID_PARA_OR_LINE(pBiDi)) {
2855 return pBiDi->direction;
2861 U_CAPI const UChar * U_EXPORT2
2862 ubidi_getText(const UBiDi *pBiDi) {
2863 if(IS_VALID_PARA_OR_LINE(pBiDi)) {
2870 U_CAPI int32_t U_EXPORT2
2871 ubidi_getLength(const UBiDi *pBiDi) {
2872 if(IS_VALID_PARA_OR_LINE(pBiDi)) {
2873 return pBiDi->originalLength;
2879 U_CAPI int32_t U_EXPORT2
2880 ubidi_getProcessedLength(const UBiDi *pBiDi) {
2881 if(IS_VALID_PARA_OR_LINE(pBiDi)) {
2882 return pBiDi->length;
2888 U_CAPI int32_t U_EXPORT2
2889 ubidi_getResultLength(const UBiDi *pBiDi) {
2890 if(IS_VALID_PARA_OR_LINE(pBiDi)) {
2891 return pBiDi->resultLength;
2897 /* paragraphs API functions ------------------------------------------------- */
2899 U_CAPI UBiDiLevel U_EXPORT2
2900 ubidi_getParaLevel(const UBiDi *pBiDi) {
2901 if(IS_VALID_PARA_OR_LINE(pBiDi)) {
2902 return pBiDi->paraLevel;
2908 U_CAPI int32_t U_EXPORT2
2909 ubidi_countParagraphs(UBiDi *pBiDi) {
2910 if(!IS_VALID_PARA_OR_LINE(pBiDi)) {
2913 return pBiDi->paraCount;
2917 U_CAPI void U_EXPORT2
2918 ubidi_getParagraphByIndex(const UBiDi *pBiDi, int32_t paraIndex,
2919 int32_t *pParaStart, int32_t *pParaLimit,
2920 UBiDiLevel *pParaLevel, UErrorCode *pErrorCode) {
2923 /* check the argument values */
2924 RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
2925 RETURN_VOID_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode);
2926 RETURN_VOID_IF_BAD_RANGE(paraIndex, 0, pBiDi->paraCount, *pErrorCode);
2928 pBiDi=pBiDi->pParaBiDi; /* get Para object if Line object */
2930 paraStart=pBiDi->paras[paraIndex-1].limit;
2934 if(pParaStart!=NULL) {
2935 *pParaStart=paraStart;
2937 if(pParaLimit!=NULL) {
2938 *pParaLimit=pBiDi->paras[paraIndex].limit;
2940 if(pParaLevel!=NULL) {
2941 *pParaLevel=GET_PARALEVEL(pBiDi, paraStart);
2945 U_CAPI int32_t U_EXPORT2
2946 ubidi_getParagraph(const UBiDi *pBiDi, int32_t charIndex,
2947 int32_t *pParaStart, int32_t *pParaLimit,
2948 UBiDiLevel *pParaLevel, UErrorCode *pErrorCode) {
2951 /* check the argument values */
2952 /* pErrorCode will be checked by the call to ubidi_getParagraphByIndex */
2953 RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1);
2954 RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1);
2955 pBiDi=pBiDi->pParaBiDi; /* get Para object if Line object */
2956 RETURN_IF_BAD_RANGE(charIndex, 0, pBiDi->length, *pErrorCode, -1);
2958 for(paraIndex=0; charIndex>=pBiDi->paras[paraIndex].limit; paraIndex++);
2959 ubidi_getParagraphByIndex(pBiDi, paraIndex, pParaStart, pParaLimit, pParaLevel, pErrorCode);
2963 U_CAPI void U_EXPORT2
2964 ubidi_setClassCallback(UBiDi *pBiDi, UBiDiClassCallback *newFn,
2965 const void *newContext, UBiDiClassCallback **oldFn,
2966 const void **oldContext, UErrorCode *pErrorCode)
2968 RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode);
2970 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
2975 *oldFn = pBiDi->fnClassCallback;
2979 *oldContext = pBiDi->coClassCallback;
2981 pBiDi->fnClassCallback = newFn;
2982 pBiDi->coClassCallback = newContext;
2985 U_CAPI void U_EXPORT2
2986 ubidi_getClassCallback(UBiDi *pBiDi, UBiDiClassCallback **fn, const void **context)
2993 *fn = pBiDi->fnClassCallback;
2997 *context = pBiDi->coClassCallback;
3001 U_CAPI UCharDirection U_EXPORT2
3002 ubidi_getCustomizedClass(UBiDi *pBiDi, UChar32 c)
3006 if( pBiDi->fnClassCallback == NULL ||
3007 (dir = (*pBiDi->fnClassCallback)(pBiDi->coClassCallback, c)) == U_BIDI_CLASS_DEFAULT )
3009 dir = ubidi_getClass(pBiDi->bdp, c);
3011 if(dir >= U_CHAR_DIRECTION_COUNT) {