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);
     }
   };
 }
  private LineLayout(@NotNull List<BidiRun> runs, boolean calculateWidth) {
    myBidiRunsInLogicalOrder = runs.toArray(new BidiRun[runs.size()]);
    myBidiRunsInVisualOrder = myBidiRunsInLogicalOrder.clone();

    reorderRunsVisually(myBidiRunsInVisualOrder);

    myWidth = calculateWidth ? calculateWidth() : -1;
  }