void () { if (!myIsDirty && !(myLinePaintersWidth > myMaxWidth)) return; synchronized (this) { if (!myIsDirty) return; int lineCount = Math.min(myLineWidths.size(), myDocument.getLineCount()); if (myMaxWidth != -1 && myDocument.isInBulkUpdate()) { mySize = new Dimension(myMaxWidth, getLineHeight() * lineCount); myIsDirty = false; return; } final CharSequence text = myDocument.getImmutableCharSequence(); int documentLength = myDocument.getTextLength(); int x = 0; boolean lastLineLengthCalculated = false; List<? extends SoftWrap> softWraps = getSoftWrapModel().getRegisteredSoftWraps(); int softWrapsIndex = -1; CharWidthCache charWidthCache = new CharWidthCache(EditorImpl.this); for (int line = 0; line < lineCount; line++) { if (myLineWidths.getQuick(line) != -1) continue; if (line == lineCount - 1) { lastLineLengthCalculated = true; } x = 0; int offset = myDocument.getLineStartOffset(line); if (offset >= myDocument.getTextLength()) { myLineWidths.set(line, 0); maxCalculatedLine = Math.max(maxCalculatedLine, line); break; } if (softWrapsIndex < 0) { softWrapsIndex = getSoftWrapModel().getSoftWrapIndex(offset); if (softWrapsIndex < 0) { softWrapsIndex = -softWrapsIndex - 1; } } int endLine; if (maxCalculatedLine < line + 1) { endLine = lineCount; } else { for (endLine = line + 1; endLine < maxCalculatedLine; endLine++) { if (myLineWidths.getQuick(endLine) != -1) { break; } } } int endOffset = endLine >= lineCount ? documentLength : myDocument.getLineEndOffset(endLine); for ( FoldRegion region = myFoldingModel.getCollapsedRegionAtOffset(endOffset); region != null && endOffset < myDocument.getTextLength(); region = myFoldingModel.getCollapsedRegionAtOffset(endOffset)) { final int lineNumber = myDocument.getLineNumber(region.getEndOffset()); endOffset = myDocument.getLineEndOffset(lineNumber); } if (endOffset > myDocument.getTextLength()) { break; } IterationState state = new IterationState(EditorImpl.this, offset, endOffset, false); int fontType = state.getMergedAttributes().getFontType(); int maxPreviousSoftWrappedWidth = -1; while (offset < documentLength && line < lineCount) { char c = text.charAt(offset); if (offset >= state.getEndOffset()) { state.advance(); fontType = state.getMergedAttributes().getFontType(); } while (softWrapsIndex < softWraps.size() && line < lineCount) { SoftWrap softWrap = softWraps.get(softWrapsIndex); if (softWrap.getStart() > offset) { break; } softWrapsIndex++; if (softWrap.getStart() == offset) { maxPreviousSoftWrappedWidth = Math.max(maxPreviousSoftWrappedWidth, x); x = softWrap.getIndentInPixels(); } } FoldRegion collapsed = state.getCurrentFold(); if (collapsed != null) { String placeholder = collapsed.getPlaceholderText(); for (int i = 0; i < placeholder.length(); i++) { x += charWidthCache.charWidth(placeholder.charAt(i), fontType); } offset = collapsed.getEndOffset(); line = myDocument.getLineNumber(offset); } else if (c == '\t') { x = EditorUtil.nextTabStop(x, EditorImpl.this); offset++; } else if (c == '\n') { int width = Math.max(x, maxPreviousSoftWrappedWidth); myLineWidths.set(line, width); maxCalculatedLine = Math.max(maxCalculatedLine, line); if (line + 1 >= lineCount || myLineWidths.getQuick(line + 1) != -1) break; offset++; x = 0; //noinspection AssignmentToForLoopParameter line++; if (line == lineCount - 1) { lastLineLengthCalculated = true; } } else { x += charWidthCache.charWidth(c, fontType); offset++; } } } if (lineCount > 0 && lastLineLengthCalculated) { myLineWidths.set(lineCount - 1, x); // Last line can be non-zero length and won't be caught by in-loop procedure since latter only react on \n's maxCalculatedLine = Math.max(maxCalculatedLine, lineCount - 1); } // There is a following possible situation: // 1. Big document is opened at editor; // 2. Soft wraps are calculated for the current visible area; // 2. The user scrolled down; // 3. The user significantly reduced visible area width (say, reduced it twice); // 4. Soft wraps are calculated for the current visible area; // We need to consider only the widths for the logical lines that are completely shown at the current visible area then. // I.e. we shouldn't use widths of the lines that are not shown for max width calculation because previous widths are calculated // for another visible area width. int startToUse = 0; int endToUse = Math.min(lineCount, myLineWidths.size()); if (endToUse > 0 && getSoftWrapModel().isSoftWrappingEnabled()) { Rectangle visibleArea = getScrollingModel().getVisibleArea(); startToUse = EditorUtil.yPositionToLogicalLine(EditorImpl.this, visibleArea.getLocation()); endToUse = Math.min(endToUse, EditorUtil.yPositionToLogicalLine(EditorImpl.this, visibleArea.y + visibleArea.height)); if (endToUse <= startToUse) { // There is a possible case that there is the only soft-wrapped line, i.e. end == start. We still want to update the // size container's width then. endToUse = Math.min(myLineWidths.size(), startToUse + 1); } } int maxWidth = 0; for (int i = startToUse; i < endToUse; i++) { maxWidth = Math.max(maxWidth, myLineWidths.getQuick(i)); } mySize = new Dimension(maxWidth, getLineHeight() * Math.max(getVisibleLineCount(), 1)); myIsDirty = false; } }