private static LineData create(@NotNull Document document, int line, int tabSize) {
      int start = document.getLineStartOffset(line);
      int end = document.getLineEndOffset(line);
      int cacheSize = (end - start) / CACHE_FREQUENCY;
      int[] cache = ArrayUtil.newIntArray(cacheSize);
      CharSequence text = document.getImmutableCharSequence();
      int column = 0;
      boolean hasTabsOrSurrogates = false;
      for (int i = start; i < end; i++) {
        if (i > start && (i - start) % CACHE_FREQUENCY == 0) {
          cache[(i - start) / CACHE_FREQUENCY - 1] = column;
        }
        char c = text.charAt(i);
        if (c == '\t') {
          column = (column / tabSize + 1) * tabSize;
          hasTabsOrSurrogates = true;
        }
        else {
          if (Character.isHighSurrogate(c)) {
            hasTabsOrSurrogates = true;
            if (i + 1 < text.length() && Character.isLowSurrogate(text.charAt(i + 1))) continue;
          }
          else {
            hasTabsOrSurrogates |= Character.isLowSurrogate(c);
          }
          column++;
        }
      }
      if (cacheSize > 0 && (end - start) % CACHE_FREQUENCY == 0) cache[cacheSize - 1] = column;
      return hasTabsOrSurrogates ? new LineData(cache) : TRIVIAL;
    }
private static LineData create(@NotNull Document document, int line, int tabSize)