private int getLogicalColumn(int startLogicalColumn, int offset) {
   assert offset >= startOffset;
   assert offset <= endOffset;
   int currentStartOffset = startOffset;
   for (LineFragment fragment : fragments) {
     int currentEndOffset = currentStartOffset + fragment.getLength();
     startLogicalColumn =
         fragment.offsetToLogicalColumn(
             startLogicalColumn, Math.min(offset, currentEndOffset) - currentStartOffset);
     currentStartOffset = currentEndOffset;
     if (offset <= currentStartOffset) break;
   }
   return startLogicalColumn;
 }
 private BidiRun subRun(int targetStartOffset, int targetEndOffset) {
   assert targetStartOffset < endOffset;
   assert targetEndOffset > startOffset;
   if (targetStartOffset <= startOffset && targetEndOffset >= this.endOffset) {
     return this;
   }
   int start = Math.max(startOffset, targetStartOffset);
   int end = Math.min(endOffset, targetEndOffset);
   BidiRun run = new BidiRun(level, start, end);
   int offset = startOffset;
   for (LineFragment fragment : fragments) {
     if (end <= offset) break;
     int endOffset = offset + fragment.getLength();
     if (start < endOffset) {
       run.fragments.add(
           fragment.subFragment(
               Math.max(start, offset) - offset, Math.min(end, endOffset) - offset));
     }
     offset = endOffset;
   }
   return run;
 }
 int getLength() {
   return delegate.getLength();
 }