/* * Compute the runs array from the levels array. * After ubidi_getRuns() returns TRUE, runCount is guaranteed to be >0 * and the runs are reordered. * Odd-level runs have visualStart on their visual right edge and * they progress visually to the left. * If option UBIDI_OPTION_INSERT_MARKS is set, insertRemove will contain the * sum of appropriate LRM/RLM_BEFORE/AFTER flags. * If option UBIDI_OPTION_REMOVE_CONTROLS is set, insertRemove will contain the * negative number of BiDi control characters within this run. */ U_CFUNC UBool ubidi_getRuns(UBiDi *pBiDi, UErrorCode *pErrorCode) { /* * This method returns immediately if the runs are already set. This * includes the case of length==0 (handled in setPara).. */ if (pBiDi->runCount>=0) { return TRUE; } if(pBiDi->direction!=UBIDI_MIXED) { /* simple, single-run case - this covers length==0 */ /* pBiDi->paraLevel is ok even for contextual multiple paragraphs */ getSingleRun(pBiDi, pBiDi->paraLevel); } else /* UBIDI_MIXED, length>0 */ { /* mixed directionality */ int32_t length=pBiDi->length, limit; UBiDiLevel *levels=pBiDi->levels; int32_t i, runCount; UBiDiLevel level=UBIDI_DEFAULT_LTR; /* initialize with no valid level */ /* * If there are WS characters at the end of the line * and the run preceding them has a level different from * paraLevel, then they will form their own run at paraLevel (L1). * Count them separately. * We need some special treatment for this in order to not * modify the levels array which a line UBiDi object shares * with its paragraph parent and its other line siblings. * In other words, for the trailing WS, it may be * levels[]!=paraLevel but we have to treat it like it were so. */ limit=pBiDi->trailingWSStart; /* count the runs, there is at least one non-WS run, and limit>0 */ runCount=0; for(i=0; i<limit; ++i) { /* increment runCount at the start of each run */ if(levels[i]!=level) { ++runCount; level=levels[i]; } } /* * We don't need to see if the last run can be merged with a trailing * WS run because setTrailingWSStart() would have done that. */ if(runCount==1 && limit==length) { /* There is only one non-WS run and no trailing WS-run. */ getSingleRun(pBiDi, levels[0]); } else /* runCount>1 || limit<length */ { /* allocate and set the runs */ Run *runs; int32_t runIndex, start; UBiDiLevel minLevel=UBIDI_MAX_EXPLICIT_LEVEL+1, maxLevel=0; /* now, count a (non-mergeable) WS run */ if(limit<length) { ++runCount; } /* runCount>1 */ if(getRunsMemory(pBiDi, runCount)) { runs=pBiDi->runsMemory; } else { return FALSE; } /* set the runs */ /* FOOD FOR THOUGHT: this could be optimized, e.g.: * 464->444, 484->444, 575->555, 595->555 * However, that would take longer. Check also how it would * interact with BiDi control removal and inserting Marks. */ runIndex=0; /* search for the run limits and initialize visualLimit values with the run lengths */ i=0; do { /* prepare this run */ start=i; level=levels[i]; if(level<minLevel) { minLevel=level; } if(level>maxLevel) { maxLevel=level; } /* look for the run limit */ while(++i<limit && levels[i]==level) {} /* i is another run limit */ runs[runIndex].logicalStart=start; runs[runIndex].visualLimit=i-start; runs[runIndex].insertRemove=0; ++runIndex; } while(i<limit); if(limit<length) { /* there is a separate WS run */ runs[runIndex].logicalStart=limit; runs[runIndex].visualLimit=length-limit; /* For the trailing WS run, pBiDi->paraLevel is ok even if contextual multiple paragraphs. */ if(pBiDi->paraLevel<minLevel) { minLevel=pBiDi->paraLevel; } } /* set the object fields */ pBiDi->runs=runs; pBiDi->runCount=runCount; reorderLine(pBiDi, minLevel, maxLevel); /* now add the direction flags and adjust the visualLimit's to be just that */ /* this loop will also handle the trailing WS run */ limit=0; for(i=0; i<runCount; ++i) { ADD_ODD_BIT_FROM_LEVEL(runs[i].logicalStart, levels[runs[i].logicalStart]); limit+=runs[i].visualLimit; runs[i].visualLimit=limit; } /* Set the "odd" bit for the trailing WS run. */ /* For a RTL paragraph, it will be the *first* run in visual order. */ /* For the trailing WS run, pBiDi->paraLevel is ok even if contextual multiple paragraphs. */ if(runIndex<runCount) { int32_t trailingRun = ((pBiDi->paraLevel & 1) != 0)? 0 : runIndex; ADD_ODD_BIT_FROM_LEVEL(runs[trailingRun].logicalStart, pBiDi->paraLevel); } } } /* handle insert LRM/RLM BEFORE/AFTER run */ if(pBiDi->insertPoints.size>0) { Point *point, *start=pBiDi->insertPoints.points, *limit=start+pBiDi->insertPoints.size; int32_t runIndex; for(point=start; point<limit; point++) { runIndex=getRunFromLogicalIndex(pBiDi, point->pos, pErrorCode); pBiDi->runs[runIndex].insertRemove|=point->flag; } } /* handle remove BiDi control characters */ if(pBiDi->controlCount>0) { int32_t runIndex; const UChar *start=pBiDi->text, *limit=start+pBiDi->length, *pu; for(pu=start; pu<limit; pu++) { if(IS_BIDI_CONTROL_CHAR(*pu)) { runIndex=getRunFromLogicalIndex(pBiDi, (int32_t)(pu-start), pErrorCode); pBiDi->runs[runIndex].insertRemove--; } } } return TRUE; }
/* * Compute the runs array from the levels array. * After ubidi_getRuns() returns TRUE, runCount is guaranteed to be >0 * and the runs are reordered. * Odd-level runs have visualStart on their visual right edge and * they progress visually to the left. */ U_CFUNC bool_t ubidi_getRuns(UBiDi *pBiDi) { if(pBiDi->direction!=UBIDI_MIXED) { /* simple, single-run case - this covers length==0 */ getSingleRun(pBiDi, pBiDi->paraLevel); } else /* UBIDI_MIXED, length>0 */ { /* mixed directionality */ int32_t length=pBiDi->length, limit; /* * If there are WS characters at the end of the line * and the run preceding them has a level different from * paraLevel, then they will form their own run at paraLevel (L1). * Count them separately. * We need some special treatment for this in order to not * modify the levels array which a line UBiDi object shares * with its paragraph parent and its other line siblings. * In other words, for the trailing WS, it may be * levels[]!=paraLevel but we have to treat it like it were so. */ limit=pBiDi->trailingWSStart; if(limit==0) { /* there is only WS on this line */ getSingleRun(pBiDi, pBiDi->paraLevel); } else { UBiDiLevel *levels=pBiDi->levels; int32_t i, runCount; UBiDiLevel level=UBIDI_DEFAULT_LTR; /* initialize with no valid level */ /* count the runs, there is at least one non-WS run, and limit>0 */ runCount=0; for(i=0; i<limit; ++i) { /* increment runCount at the start of each run */ if(levels[i]!=level) { ++runCount; level=levels[i]; } } /* * We don't need to see if the last run can be merged with a trailing * WS run because setTrailingWSStart() would have done that. */ if(runCount==1 && limit==length) { /* There is only one non-WS run and no trailing WS-run. */ getSingleRun(pBiDi, levels[0]); } else /* runCount>1 || limit<length */ { /* allocate and set the runs */ Run *runs; int32_t runIndex, start; UBiDiLevel minLevel=UBIDI_MAX_EXPLICIT_LEVEL+1, maxLevel=0; /* now, count a (non-mergable) WS run */ if(limit<length) { ++runCount; } /* runCount>1 */ if(getRunsMemory(pBiDi, runCount)) { runs=pBiDi->runsMemory; } else { return FALSE; } /* set the runs */ /* this could be optimized, e.g.: 464->444, 484->444, 575->555, 595->555 */ /* however, that would take longer and make other functions more complicated */ runIndex=0; /* search for the run limits and initialize visualLimit values with the run lengths */ i=0; do { /* prepare this run */ start=i; level=levels[i]; if(level<minLevel) { minLevel=level; } if(level>maxLevel) { maxLevel=level; } /* look for the run limit */ while(++i<limit && levels[i]==level) {} /* i is another run limit */ runs[runIndex].logicalStart=start; runs[runIndex].visualLimit=i-start; ++runIndex; } while(i<limit); if(limit<length) { /* there is a separate WS run */ runs[runIndex].logicalStart=limit; runs[runIndex].visualLimit=length-limit; if(pBiDi->paraLevel<minLevel) { minLevel=pBiDi->paraLevel; } } /* set the object fields */ pBiDi->runs=runs; pBiDi->runCount=runCount; reorderLine(pBiDi, minLevel, maxLevel); /* now add the direction flags and adjust the visualLimit's to be just that */ ADD_ODD_BIT_FROM_LEVEL(runs[0].logicalStart, levels[runs[0].logicalStart]); limit=runs[0].visualLimit; for(i=1; i<runIndex; ++i) { ADD_ODD_BIT_FROM_LEVEL(runs[i].logicalStart, levels[runs[i].logicalStart]); limit=runs[i].visualLimit+=limit; } /* same for the trailing WS run */ if(runIndex<runCount) { ADD_ODD_BIT_FROM_LEVEL(runs[i].logicalStart, pBiDi->paraLevel); runs[runIndex].visualLimit+=limit; } } } } return TRUE; }