Iterable<VisualFragment> getFragmentsInVisualOrder(
     final float startX, final int startVisualColumn, final int startOffset, int endOffset) {
   assert startOffset <= endOffset;
   final BidiRun[] runs;
   int startLogicalColumn = 0;
   if (startOffset == endOffset) {
     runs = new BidiRun[0];
   } else {
     List<BidiRun> runList = new ArrayList<BidiRun>();
     for (BidiRun run : myBidiRunsInLogicalOrder) {
       if (run.startOffset < startOffset) {
         startLogicalColumn =
             run.getLogicalColumn(startLogicalColumn, Math.min(startOffset, run.endOffset));
       }
       if (run.endOffset <= startOffset) continue;
       if (run.startOffset >= endOffset) break;
       runList.add(run.subRun(startOffset, endOffset));
     }
     runs = runList.toArray(new BidiRun[runList.size()]);
     reorderRunsVisually(runs);
   }
   final int finalStartLogicalColumn = startLogicalColumn;
   return new Iterable<VisualFragment>() {
     @Override
     public Iterator<VisualFragment> iterator() {
       return new VisualOrderIterator(
           startX, startVisualColumn, finalStartLogicalColumn, startOffset, runs);
     }
   };
 }
 boolean isRtlLocation(int offset, boolean leanForward) {
   if (offset == 0 && !leanForward) return false;
   for (BidiRun run : myBidiRunsInLogicalOrder) {
     if (offset < run.endOffset || offset == run.endOffset && !leanForward) return run.isRtl();
   }
   return false;
 }
 private static void addFragments(
     BidiRun run,
     char[] text,
     int start,
     int end,
     int fontStyle,
     FontPreferences fontPreferences,
     FontRenderContext fontRenderContext,
     @Nullable TabFragment tabFragment) {
   Font currentFont = null;
   int currentIndex = start;
   for (int i = start; i < end; i++) {
     char c = text[i];
     if (c == '\t' && tabFragment != null) {
       assert run.level == 0;
       addTextFragmentIfNeeded(
           run, text, currentIndex, i, currentFont, fontRenderContext, run.isRtl());
       run.fragments.add(tabFragment);
       currentFont = null;
       currentIndex = i + 1;
     } else {
       Font font =
           ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontStyle, fontPreferences)
               .getFont();
       if (!font.equals(currentFont)) {
         addTextFragmentIfNeeded(
             run, text, currentIndex, i, currentFont, fontRenderContext, run.isRtl());
         currentFont = font;
         currentIndex = i;
       }
     }
   }
   addTextFragmentIfNeeded(
       run, text, currentIndex, end, currentFont, fontRenderContext, run.isRtl());
 }
    @Override
    public VisualFragment next() {
      if (!hasNext()) {
        throw new NoSuchElementException();
      }
      BidiRun run = myRuns[myRunIndex];

      if (myRunIndex == 0 && myFragmentIndex == 0) {
        myFragment.startLogicalColumn +=
            (run.isRtl() ? run.endOffset : run.startOffset) - myFragment.startOffset;
      } else {
        myFragment.startLogicalColumn = myFragment.getEndLogicalColumn();
        if (myFragmentIndex == 0) {
          myFragment.startLogicalColumn +=
              (run.isRtl() ? run.endOffset : run.startOffset) - myFragment.getEndOffset();
        }
        myFragment.startVisualColumn = myFragment.getEndVisualColumn();
        myFragment.startX = myFragment.getEndX();
      }

      myFragment.isRtl = run.isRtl();
      myFragment.delegate =
          run.fragments.get(
              run.isRtl() ? run.fragments.size() - 1 - myFragmentIndex : myFragmentIndex);
      myFragment.startOffset =
          run.isRtl() ? run.endOffset - myOffsetInsideRun : run.startOffset + myOffsetInsideRun;

      myOffsetInsideRun += myFragment.getLength();
      myFragmentIndex++;
      if (myFragmentIndex >= run.fragments.size()) {
        myFragmentIndex = 0;
        myOffsetInsideRun = 0;
        myRunIndex++;
      }

      return myFragment;
    }