U_CAPI UBiDiLevel U_EXPORT2 ubidi_getLevelAt(const UBiDi *pBiDi, int32_t charIndex) { /* return paraLevel if in the trailing WS run, otherwise the real level */ if(!IS_VALID_PARA_OR_LINE(pBiDi) || charIndex<0 || pBiDi->length<=charIndex) { return 0; } else if(pBiDi->direction!=UBIDI_MIXED || charIndex>=pBiDi->trailingWSStart) { return GET_PARALEVEL(pBiDi, charIndex); } else { return pBiDi->levels[charIndex]; } }
U_CAPI void U_EXPORT2 ubidi_getLogicalRun(const UBiDi * pBiDi, int32_t logicalPosition, int32_t * pLogicalLimit, UBiDiLevel * pLevel) { UErrorCode errorCode; int32_t runCount, visualStart, logicalLimit, logicalFirst, i; Run iRun; errorCode = U_ZERO_ERROR; RETURN_VOID_IF_BAD_RANGE(logicalPosition, 0, pBiDi->length, errorCode); /* ubidi_countRuns will check VALID_PARA_OR_LINE */ runCount = ubidi_countRuns((UBiDi *)pBiDi, &errorCode); if (U_FAILURE(errorCode)) { return; } /* this is done based on runs rather than on levels since levels have a special interpretation when UBIDI_REORDER_RUNS_ONLY */ visualStart = logicalLimit = 0; iRun = pBiDi->runs[0]; for (i = 0; i < runCount; i++) { iRun = pBiDi->runs[i]; logicalFirst = GET_INDEX(iRun.logicalStart); logicalLimit = logicalFirst + iRun.visualLimit - visualStart; if ((logicalPosition >= logicalFirst) && (logicalPosition < logicalLimit)) { break; } visualStart = iRun.visualLimit; } if (pLogicalLimit) { *pLogicalLimit = logicalLimit; } if (pLevel) { if (pBiDi->reorderingMode == UBIDI_REORDER_RUNS_ONLY) { *pLevel = (UBiDiLevel)GET_ODD_BIT(iRun.logicalStart); } else if (pBiDi->direction != UBIDI_MIXED || logicalPosition >= pBiDi->trailingWSStart) { *pLevel = GET_PARALEVEL(pBiDi, logicalPosition); } else { *pLevel = pBiDi->levels[logicalPosition]; } } }
U_CAPI void U_EXPORT2 ubidi_setLine(const UBiDi *pParaBiDi, int32_t start, int32_t limit, UBiDi *pLineBiDi, UErrorCode *pErrorCode) { int32_t length; /* check the argument values */ RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode); RETURN_VOID_IF_NOT_VALID_PARA(pParaBiDi, *pErrorCode); RETURN_VOID_IF_BAD_RANGE(start, 0, limit, *pErrorCode); RETURN_VOID_IF_BAD_RANGE(limit, 0, pParaBiDi->length+1, *pErrorCode); if(pLineBiDi==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return; } if(ubidi_getParagraph(pParaBiDi, start, NULL, NULL, NULL, pErrorCode) != ubidi_getParagraph(pParaBiDi, limit-1, NULL, NULL, NULL, pErrorCode)) { /* the line crosses a paragraph boundary */ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return; } /* set the values in pLineBiDi from its pParaBiDi parent */ pLineBiDi->pParaBiDi=NULL; /* mark unfinished setLine */ pLineBiDi->text=pParaBiDi->text+start; length=pLineBiDi->length=limit-start; pLineBiDi->resultLength=pLineBiDi->originalLength=length; pLineBiDi->paraLevel=GET_PARALEVEL(pParaBiDi, start); pLineBiDi->paraCount=pParaBiDi->paraCount; pLineBiDi->runs=NULL; pLineBiDi->flags=0; pLineBiDi->reorderingMode=pParaBiDi->reorderingMode; pLineBiDi->reorderingOptions=pParaBiDi->reorderingOptions; pLineBiDi->controlCount=0; if(pParaBiDi->controlCount>0) { int32_t j; for(j=start; j<limit; j++) { if(IS_BIDI_CONTROL_CHAR(pParaBiDi->text[j])) { pLineBiDi->controlCount++; } } pLineBiDi->resultLength-=pLineBiDi->controlCount; } pLineBiDi->dirProps=pParaBiDi->dirProps+start; pLineBiDi->levels=pParaBiDi->levels+start; pLineBiDi->runCount=-1; if(pParaBiDi->direction!=UBIDI_MIXED) { /* the parent is already trivial */ pLineBiDi->direction=pParaBiDi->direction; /* * The parent's levels are all either * implicitly or explicitly ==paraLevel; * do the same here. */ if(pParaBiDi->trailingWSStart<=start) { pLineBiDi->trailingWSStart=0; } else if(pParaBiDi->trailingWSStart<limit) { pLineBiDi->trailingWSStart=pParaBiDi->trailingWSStart-start; } else { pLineBiDi->trailingWSStart=length; } } else { const UBiDiLevel *levels=pLineBiDi->levels; int32_t i, trailingWSStart; UBiDiLevel level; setTrailingWSStart(pLineBiDi); trailingWSStart=pLineBiDi->trailingWSStart; /* recalculate pLineBiDi->direction */ if(trailingWSStart==0) { /* all levels are at paraLevel */ pLineBiDi->direction=(UBiDiDirection)(pLineBiDi->paraLevel&1); } else { /* get the level of the first character */ level=(UBiDiLevel)(levels[0]&1); /* if there is anything of a different level, then the line is mixed */ if(trailingWSStart<length && (pLineBiDi->paraLevel&1)!=level) { /* the trailing WS is at paraLevel, which differs from levels[0] */ pLineBiDi->direction=UBIDI_MIXED; } else { /* see if levels[1..trailingWSStart-1] have the same direction as levels[0] and paraLevel */ i=1; for(;;) { if(i==trailingWSStart) { /* the direction values match those in level */ pLineBiDi->direction=(UBiDiDirection)level; break; } else if((levels[i]&1)!=level) { pLineBiDi->direction=UBIDI_MIXED; break; } ++i; } } } switch(pLineBiDi->direction) { case UBIDI_LTR: /* make sure paraLevel is even */ pLineBiDi->paraLevel=(UBiDiLevel)((pLineBiDi->paraLevel+1)&~1); /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */ pLineBiDi->trailingWSStart=0; break; case UBIDI_RTL: /* make sure paraLevel is odd */ pLineBiDi->paraLevel|=1; /* all levels are implicitly at paraLevel (important for ubidi_getLevels()) */ pLineBiDi->trailingWSStart=0; break; default: break; } } pLineBiDi->pParaBiDi=pParaBiDi; /* mark successful setLine */ return; }