void rebuild() {
    ArrayList<FoldRegion> topLevels = new ArrayList<FoldRegion>(myRegions.size() / 2);
    ArrayList<FoldRegion> visible = new ArrayList<FoldRegion>(myRegions.size());
    FoldRegion[] regions = myRegions.toArray(new FoldRegion[myRegions.size()]);
    FoldRegion currentToplevel = null;
    for (FoldRegion region : regions) {
      if (region.isValid()) {
        visible.add(region);
        if (!region.isExpanded()) {
          if (currentToplevel == null || currentToplevel.getEndOffset() < region.getStartOffset()) {
            currentToplevel = region;
            topLevels.add(region);
          }
        }
      }
    }

    myCachedTopLevelRegions =
        topLevels.isEmpty()
            ? FoldRegion.EMPTY_ARRAY
            : topLevels.toArray(new FoldRegion[topLevels.size()]);

    Arrays.sort(myCachedTopLevelRegions, BY_END_OFFSET);

    FoldRegion[] visibleArrayed = visible.toArray(new FoldRegion[visible.size()]);
    for (FoldRegion visibleRegion : visibleArrayed) {
      for (FoldRegion topLevelRegion : myCachedTopLevelRegions) {
        if (contains(topLevelRegion, visibleRegion)) {
          visible.remove(visibleRegion);
          break;
        }
      }
    }

    myCachedVisible = visible.toArray(new FoldRegion[visible.size()]);

    Arrays.sort(myCachedVisible, BY_END_OFFSET_REVERSE);

    updateCachedOffsets();
  }
 private void updateCachedOffsets() {
   myFoldTree.updateCachedOffsets();
 }