U_CAPI void U_EXPORT2 ubidi_getVisualMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) { /* ubidi_countRuns() checks all of its and our arguments */ if(ubidi_countRuns(pBiDi, pErrorCode)<=0) { /* no op */ } else if(indexMap==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; } else { /* fill a visual-to-logical index map using the runs[] */ Run *runs=pBiDi->runs, *runsLimit=runs+pBiDi->runCount; int32_t logicalStart, visualStart, visualLimit; visualStart=0; for(; runs<runsLimit; ++runs) { logicalStart=runs->logicalStart; visualLimit=runs->visualLimit; if(IS_EVEN_RUN(logicalStart)) { do { /* LTR */ *indexMap++ = logicalStart++; } while(++visualStart<visualLimit); } else { REMOVE_ODD_BIT(logicalStart); logicalStart+=visualLimit-visualStart; /* logicalLimit */ do { /* RTL */ *indexMap++ = --logicalStart; } while(++visualStart<visualLimit); } /* visualStart==visualLimit; */ } } }
U_CAPI int32_t U_EXPORT2 ubidi_getLogicalIndex(UBiDi *pBiDi, int32_t visualIndex, UErrorCode *pErrorCode) { Run *runs; int32_t i, runCount, start; RETURN_IF_NULL_OR_FAILING_ERRCODE(pErrorCode, -1); RETURN_IF_NOT_VALID_PARA_OR_LINE(pBiDi, *pErrorCode, -1); RETURN_IF_BAD_RANGE(visualIndex, 0, pBiDi->resultLength, *pErrorCode, -1); /* we can do the trivial cases without the runs array */ if(pBiDi->insertPoints.size==0 && pBiDi->controlCount==0) { if(pBiDi->direction==UBIDI_LTR) { return visualIndex; } else if(pBiDi->direction==UBIDI_RTL) { return pBiDi->length-visualIndex-1; } } if(!ubidi_getRuns(pBiDi, pErrorCode)) { *pErrorCode=U_MEMORY_ALLOCATION_ERROR; return -1; } runs=pBiDi->runs; runCount=pBiDi->runCount; if(pBiDi->insertPoints.size>0) { /* handle inserted LRM/RLM */ int32_t markFound=0, insertRemove; int32_t visualStart=0, length; runs=pBiDi->runs; /* subtract number of marks until visual index */ for(i=0; ; i++, visualStart+=length) { length=runs[i].visualLimit-visualStart; insertRemove=runs[i].insertRemove; if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) { if(visualIndex<=(visualStart+markFound)) { return UBIDI_MAP_NOWHERE; } markFound++; } /* is adjusted visual index within this run? */ if(visualIndex<(runs[i].visualLimit+markFound)) { visualIndex-=markFound; break; } if(insertRemove&(LRM_AFTER|RLM_AFTER)) { if(visualIndex==(visualStart+length+markFound)) { return UBIDI_MAP_NOWHERE; } markFound++; } } } else if(pBiDi->controlCount>0) { /* handle removed BiDi control characters */ int32_t controlFound=0, insertRemove, length; int32_t logicalStart, logicalEnd, visualStart=0, j, k; UChar uchar; UBool evenRun; /* add number of controls until visual index */ for(i=0; ; i++, visualStart+=length) { length=runs[i].visualLimit-visualStart; insertRemove=runs[i].insertRemove; /* is adjusted visual index beyond current run? */ if(visualIndex>=(runs[i].visualLimit-controlFound+insertRemove)) { controlFound-=insertRemove; continue; } /* adjusted visual index is within current run */ if(insertRemove==0) { visualIndex+=controlFound; break; } /* count non-control chars until visualIndex */ logicalStart=runs[i].logicalStart; evenRun=IS_EVEN_RUN(logicalStart); REMOVE_ODD_BIT(logicalStart); logicalEnd=logicalStart+length-1; for(j=0; j<length; j++) { k= evenRun ? logicalStart+j : logicalEnd-j; uchar=pBiDi->text[k]; if(IS_BIDI_CONTROL_CHAR(uchar)) { controlFound++; } if((visualIndex+controlFound)==(visualStart+j)) { break; } } visualIndex+=controlFound; break; } } /* handle all cases */ if(runCount<=10) { /* linear search for the run */ for(i=0; visualIndex>=runs[i].visualLimit; ++i) {} } else { /* binary search for the run */ int32_t begin=0, limit=runCount; /* the middle if() is guaranteed to find the run, we don't need a loop limit */ for(;;) { i=(begin+limit)/2; if(visualIndex>=runs[i].visualLimit) { begin=i+1; } else if(i==0 || visualIndex>=runs[i-1].visualLimit) { break; } else { limit=i; } } } start=runs[i].logicalStart; if(IS_EVEN_RUN(start)) { /* LTR */ /* the offset in runs[i] is visualIndex-runs[i-1].visualLimit */ if(i>0) { visualIndex-=runs[i-1].visualLimit; } return start+visualIndex; } else { /* RTL */ return GET_INDEX(start)+runs[i].visualLimit-visualIndex-1; } }
U_CAPI void U_EXPORT2 ubidi_getVisualMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) { RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode); if(indexMap==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return; } /* ubidi_countRuns() checks for VALID_PARA_OR_LINE */ ubidi_countRuns(pBiDi, pErrorCode); if(U_SUCCESS(*pErrorCode)) { /* fill a visual-to-logical index map using the runs[] */ Run *runs=pBiDi->runs, *runsLimit=runs+pBiDi->runCount; int32_t logicalStart, visualStart, visualLimit, *pi=indexMap; if (pBiDi->resultLength<=0) { return; } visualStart=0; for(; runs<runsLimit; ++runs) { logicalStart=runs->logicalStart; visualLimit=runs->visualLimit; if(IS_EVEN_RUN(logicalStart)) { do { /* LTR */ *pi++ = logicalStart++; } while(++visualStart<visualLimit); } else { REMOVE_ODD_BIT(logicalStart); logicalStart+=visualLimit-visualStart; /* logicalLimit */ do { /* RTL */ *pi++ = --logicalStart; } while(++visualStart<visualLimit); } /* visualStart==visualLimit; */ } if(pBiDi->insertPoints.size>0) { int32_t markFound=0, runCount=pBiDi->runCount; int32_t insertRemove, i, j, k; runs=pBiDi->runs; /* count all inserted marks */ for(i=0; i<runCount; i++) { insertRemove=runs[i].insertRemove; if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) { markFound++; } if(insertRemove&(LRM_AFTER|RLM_AFTER)) { markFound++; } } /* move back indexes by number of preceding marks */ k=pBiDi->resultLength; for(i=runCount-1; i>=0 && markFound>0; i--) { insertRemove=runs[i].insertRemove; if(insertRemove&(LRM_AFTER|RLM_AFTER)) { indexMap[--k]= UBIDI_MAP_NOWHERE; markFound--; } visualStart= i>0 ? runs[i-1].visualLimit : 0; for(j=runs[i].visualLimit-1; j>=visualStart && markFound>0; j--) { indexMap[--k]=indexMap[j]; } if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) { indexMap[--k]= UBIDI_MAP_NOWHERE; markFound--; } } } else if(pBiDi->controlCount>0) { int32_t runCount=pBiDi->runCount, logicalEnd; int32_t insertRemove, length, i, j, k, m; UChar uchar; UBool evenRun; runs=pBiDi->runs; visualStart=0; /* move forward indexes by number of preceding controls */ k=0; for(i=0; i<runCount; i++, visualStart+=length) { length=runs[i].visualLimit-visualStart; insertRemove=runs[i].insertRemove; /* if no control found yet, nothing to do in this run */ if((insertRemove==0)&&(k==visualStart)) { k+=length; continue; } /* if no control in this run */ if(insertRemove==0) { visualLimit=runs[i].visualLimit; for(j=visualStart; j<visualLimit; j++) { indexMap[k++]=indexMap[j]; } continue; } logicalStart=runs[i].logicalStart; evenRun=IS_EVEN_RUN(logicalStart); REMOVE_ODD_BIT(logicalStart); logicalEnd=logicalStart+length-1; for(j=0; j<length; j++) { m= evenRun ? logicalStart+j : logicalEnd-j; uchar=pBiDi->text[m]; if(!IS_BIDI_CONTROL_CHAR(uchar)) { indexMap[k++]=m; } } } } } }
U_CAPI void U_EXPORT2 ubidi_getLogicalMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode) { RETURN_VOID_IF_NULL_OR_FAILING_ERRCODE(pErrorCode); /* ubidi_countRuns() checks for VALID_PARA_OR_LINE */ ubidi_countRuns(pBiDi, pErrorCode); if(U_FAILURE(*pErrorCode)) { /* no op */ } else if(indexMap==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; } else { /* fill a logical-to-visual index map using the runs[] */ int32_t visualStart, visualLimit, i, j, k; int32_t logicalStart, logicalLimit; Run *runs=pBiDi->runs; if (pBiDi->length<=0) { return; } if (pBiDi->length>pBiDi->resultLength) { uprv_memset(indexMap, 0xFF, pBiDi->length*sizeof(int32_t)); } visualStart=0; for(j=0; j<pBiDi->runCount; ++j) { logicalStart=GET_INDEX(runs[j].logicalStart); visualLimit=runs[j].visualLimit; if(IS_EVEN_RUN(runs[j].logicalStart)) { do { /* LTR */ indexMap[logicalStart++]=visualStart++; } while(visualStart<visualLimit); } else { logicalStart+=visualLimit-visualStart; /* logicalLimit */ do { /* RTL */ indexMap[--logicalStart]=visualStart++; } while(visualStart<visualLimit); } /* visualStart==visualLimit; */ } if(pBiDi->insertPoints.size>0) { int32_t markFound=0, runCount=pBiDi->runCount; int32_t length, insertRemove; visualStart=0; /* add number of marks found until each index */ for(i=0; i<runCount; i++, visualStart+=length) { length=runs[i].visualLimit-visualStart; insertRemove=runs[i].insertRemove; if(insertRemove&(LRM_BEFORE|RLM_BEFORE)) { markFound++; } if(markFound>0) { logicalStart=GET_INDEX(runs[i].logicalStart); logicalLimit=logicalStart+length; for(j=logicalStart; j<logicalLimit; j++) { indexMap[j]+=markFound; } } if(insertRemove&(LRM_AFTER|RLM_AFTER)) { markFound++; } } } else if(pBiDi->controlCount>0) { int32_t controlFound=0, runCount=pBiDi->runCount; int32_t length, insertRemove; UBool evenRun; UChar uchar; visualStart=0; /* subtract number of controls found until each index */ for(i=0; i<runCount; i++, visualStart+=length) { length=runs[i].visualLimit-visualStart; insertRemove=runs[i].insertRemove; /* no control found within previous runs nor within this run */ if((controlFound-insertRemove)==0) { continue; } logicalStart=runs[i].logicalStart; evenRun=IS_EVEN_RUN(logicalStart); REMOVE_ODD_BIT(logicalStart); logicalLimit=logicalStart+length; /* if no control within this run */ if(insertRemove==0) { for(j=logicalStart; j<logicalLimit; j++) { indexMap[j]-=controlFound; } continue; } for(j=0; j<length; j++) { k= evenRun ? logicalStart+j : logicalLimit-j-1; uchar=pBiDi->text[k]; if(IS_BIDI_CONTROL_CHAR(uchar)) { controlFound++; indexMap[k]=UBIDI_MAP_NOWHERE; continue; } indexMap[k]-=controlFound; } } } } }