mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
speed up editor opening - avoid unneeded/repetitive calculations
This commit is contained in:
+5
-5
@@ -73,7 +73,7 @@ class EditorCoordinateMapper {
|
||||
int visualLine = offsetToVisualLine(offset, beforeSoftWrap);
|
||||
int maxVisualColumn = 0;
|
||||
int maxLogicalColumn = 0;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap)) {
|
||||
if (!pos.leansForward && offset == fragment.getVisualLineStartOffset()) {
|
||||
return new VisualPosition(visualLine, fragment.getStartVisualColumn());
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class EditorCoordinateMapper {
|
||||
int maxVisualColumn = 0;
|
||||
int maxLogicalColumn = 0;
|
||||
int maxOffset = offset;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) {
|
||||
int minColumn = fragment.getStartVisualColumn();
|
||||
int maxColumn = fragment.getEndVisualColumn();
|
||||
if (column < minColumn || column == minColumn && !pos.leansRight) {
|
||||
@@ -240,7 +240,7 @@ class EditorCoordinateMapper {
|
||||
if (visualLine < myView.getEditor().getVisibleLineCount()) {
|
||||
int visualLineStartOffset = visualLineToOffset(visualLine);
|
||||
int maxOffset = 0;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false)) {
|
||||
if (p.x <= fragment.getStartX()) {
|
||||
int markerWidth = myView.getEditor().getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP);
|
||||
float indent = fragment.getStartX() - markerWidth;
|
||||
@@ -286,7 +286,7 @@ class EditorCoordinateMapper {
|
||||
if (visualLine < myView.getEditor().getVisibleLineCount()) {
|
||||
int visualLineStartOffset = visualLineToOffset(visualLine);
|
||||
int maxOffset = 0;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLineStartOffset, false)) {
|
||||
if (column < fragment.getStartVisualColumn()) {
|
||||
break;
|
||||
}
|
||||
@@ -317,7 +317,7 @@ class EditorCoordinateMapper {
|
||||
float x = getStartX(logicalLine);
|
||||
if (myDocument.getTextLength() > 0) {
|
||||
boolean firstFragment = true;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap)) {
|
||||
if (firstFragment && offset == visualLineStartOffset && !leanTowardsLargerOffsets) {
|
||||
x = fragment.getStartX();
|
||||
break;
|
||||
|
||||
@@ -589,7 +589,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
TFloatArrayList trailingRanges = adjustedLogicalRangeToVisualRanges(
|
||||
myView.visualPositionToOffset(new VisualPosition(endPosition.line, 0)), endOffset);
|
||||
if (!leadingRanges.isEmpty() && !trailingRanges.isEmpty()) {
|
||||
int maxWidth = Math.max(myView.getMaxWidthInLineRange(startPosition.line, endPosition.line - 1, null) - 1,
|
||||
int maxWidth = Math.max(myView.getMaxWidthInLineRange(startPosition.line, endPosition.line - 1) - 1,
|
||||
(int)trailingRanges.get(trailingRanges.size() - 1));
|
||||
boolean containsInnerLines = endPosition.line > startPosition.line + 1;
|
||||
int leadingTopY = myView.visualLineToY(startPosition.line);
|
||||
@@ -695,7 +695,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
result.add(0);
|
||||
}
|
||||
else {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, startOffset, false, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, startOffset, false)) {
|
||||
int minOffset = fragment.getMinOffset();
|
||||
int maxOffset = fragment.getMaxOffset();
|
||||
if (startOffset == endOffset) {
|
||||
@@ -777,7 +777,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
int targetVisualColumn = caret.getVisualPosition().column;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView,
|
||||
caret.getVisualLineStart(),
|
||||
false, null)) {
|
||||
false)) {
|
||||
int startVisualColumn = fragment.getStartVisualColumn();
|
||||
int endVisualColumn = fragment.getEndVisualColumn();
|
||||
if (startVisualColumn < targetVisualColumn && endVisualColumn > targetVisualColumn ||
|
||||
@@ -815,7 +815,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
int prevEndOffset = -1;
|
||||
boolean firstFragment = true;
|
||||
int maxColumn = 0;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false, null)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) {
|
||||
int fragmentStartOffset = fragment.getStartOffset();
|
||||
int start = fragmentStartOffset;
|
||||
int end = fragment.getEndOffset();
|
||||
|
||||
+38
-6
@@ -26,6 +26,7 @@ import com.intellij.openapi.editor.ex.FoldingListener;
|
||||
import com.intellij.openapi.editor.ex.PrioritizedDocumentListener;
|
||||
import com.intellij.openapi.editor.impl.EditorDocumentPriorities;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType;
|
||||
import com.intellij.openapi.editor.impl.softwrap.mapping.IncrementalCacheUpdateEvent;
|
||||
import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapAwareDocumentParsingListenerAdapter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -34,6 +35,7 @@ import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -195,26 +197,56 @@ class EditorSizeManager implements PrioritizedDocumentListener, Disposable, Fold
|
||||
}
|
||||
|
||||
private int calculatePreferredWidth() {
|
||||
int lineCount = myLineWidths.size();
|
||||
assert myLineWidths.size() == myEditor.getVisibleLineCount();
|
||||
VisualLinesIterator iterator = new VisualLinesIterator(myView, 0);
|
||||
int maxWidth = 0;
|
||||
for (int i = 0; i < lineCount; i++) {
|
||||
int width = myLineWidths.get(i);
|
||||
while (!iterator.atEnd()) {
|
||||
int visualLine = iterator.getVisualLine();
|
||||
int width = myLineWidths.get(visualLine);
|
||||
if (width == UNKNOWN_WIDTH) {
|
||||
final Ref<Boolean> approximateValue = new Ref<Boolean>(Boolean.FALSE);
|
||||
width = myView.getMaxWidthInLineRange(i, i, new Runnable() {
|
||||
width = getVisualLineWidth(iterator, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
approximateValue.set(Boolean.TRUE);
|
||||
}
|
||||
});
|
||||
if (approximateValue.get()) width = -width;
|
||||
myLineWidths.set(i, width);
|
||||
myLineWidths.set(visualLine, width);
|
||||
}
|
||||
maxWidth = Math.max(maxWidth, Math.abs(width));
|
||||
iterator.advance();
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
|
||||
int getVisualLineWidth(VisualLinesIterator visualLinesIterator, @Nullable Runnable quickEvaluationListener) {
|
||||
assert !visualLinesIterator.atEnd();
|
||||
int visualLine = visualLinesIterator.getVisualLine();
|
||||
FoldRegion[] topLevelRegions = myEditor.getFoldingModel().fetchTopLevel();
|
||||
if (quickEvaluationListener != null &&
|
||||
(topLevelRegions == null || topLevelRegions.length == 0) && myEditor.getSoftWrapModel().getRegisteredSoftWraps().isEmpty() &&
|
||||
!myView.getTextLayoutCache().hasCachedLayoutFor(visualLine)) {
|
||||
// fast path - speeds up editor opening
|
||||
quickEvaluationListener.run();
|
||||
return myView.getLogicalPositionCache().offsetToLogicalColumn(visualLine,
|
||||
myDocument.getLineEndOffset(visualLine) -
|
||||
myDocument.getLineStartOffset(visualLine)) *
|
||||
myView.getMaxCharWidth();
|
||||
}
|
||||
float x = 0;
|
||||
int maxOffset = visualLinesIterator.getVisualLineStartOffset();
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visualLinesIterator,
|
||||
quickEvaluationListener)) {
|
||||
x = fragment.getEndX();
|
||||
maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
|
||||
}
|
||||
if (myEditor.getSoftWrapModel().getSoftWrap(maxOffset) != null) {
|
||||
x += myEditor.getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
|
||||
}
|
||||
return (int)x;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert !myDocument.isInBulkUpdate();
|
||||
doInvalidateRange(0, myDocument.getTextLength());
|
||||
|
||||
@@ -28,13 +28,11 @@ import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.editor.impl.FontInfo;
|
||||
import com.intellij.openapi.editor.impl.TextDrawingCallback;
|
||||
import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
@@ -173,6 +171,12 @@ public class EditorView implements TextDrawingCallback, Disposable {
|
||||
return myMapper.offsetToVisualLine(offset, beforeSoftWrap);
|
||||
}
|
||||
|
||||
public int visualLineToOffset(int visualLine) {
|
||||
assertIsDispatchThread();
|
||||
myEditor.getSoftWrapModel().prepareToMapping();
|
||||
return myMapper.visualLineToOffset(visualLine);
|
||||
}
|
||||
|
||||
public int visualLineStartOffset(int visualLine) {
|
||||
assertIsDispatchThread();
|
||||
myEditor.getSoftWrapModel().prepareToMapping();
|
||||
@@ -240,52 +244,31 @@ public class EditorView implements TextDrawingCallback, Disposable {
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
assertIsDispatchThread();
|
||||
myEditor.getSoftWrapModel().prepareToMapping();
|
||||
return mySizeManager.getPreferredSize();
|
||||
}
|
||||
|
||||
public int getMaxWidthInRange(int startOffset, int endOffset) {
|
||||
assertIsDispatchThread();
|
||||
return getMaxWidthInLineRange(offsetToVisualLine(startOffset, false), offsetToVisualLine(endOffset, true), null);
|
||||
return getMaxWidthInLineRange(offsetToVisualLine(startOffset, false), offsetToVisualLine(endOffset, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* If <code>quickEvaluationListener</code> is provided, quick approximate size evaluation becomes enabled, listener will be invoked
|
||||
* if approximation will in fact be used during width calculation.
|
||||
*/
|
||||
int getMaxWidthInLineRange(int startVisualLine, int endVisualLine, @Nullable Runnable quickEvaluationListener) {
|
||||
int getMaxWidthInLineRange(int startVisualLine, int endVisualLine) {
|
||||
myEditor.getSoftWrapModel().prepareToMapping();
|
||||
int maxWidth = 0;
|
||||
endVisualLine = Math.min(endVisualLine, myEditor.getVisibleLineCount() - 1);
|
||||
for (int i = startVisualLine; i <= endVisualLine; i++) {
|
||||
int width = getVisualLineWidth(i, quickEvaluationListener);
|
||||
VisualLinesIterator iterator = new VisualLinesIterator(this, startVisualLine);
|
||||
while (!iterator.atEnd() && iterator.getVisualLine() <= endVisualLine) {
|
||||
int width = mySizeManager.getVisualLineWidth(iterator, null);
|
||||
maxWidth = Math.max(maxWidth, width);
|
||||
iterator.advance();
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
private int getVisualLineWidth(int visualLine, @Nullable Runnable quickEvaluationListener) {
|
||||
FoldRegion[] topLevelRegions = myEditor.getFoldingModel().fetchTopLevel();
|
||||
if (quickEvaluationListener != null &&
|
||||
(topLevelRegions == null || topLevelRegions.length == 0) && myEditor.getSoftWrapModel().getRegisteredSoftWraps().isEmpty() &&
|
||||
!myTextLayoutCache.hasCachedLayoutFor(visualLine)) {
|
||||
// fast path - speeds up editor opening
|
||||
quickEvaluationListener.run();
|
||||
return myMapper.offsetToLogicalPosition(myDocument.getLineEndOffset(visualLine)).column * getMaxCharWidth();
|
||||
}
|
||||
int startOffset = myMapper.visualLineToOffset(visualLine);
|
||||
float x = 0;
|
||||
int maxOffset = 0;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(this, startOffset, false,
|
||||
quickEvaluationListener)) {
|
||||
x = fragment.getEndX();
|
||||
maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
|
||||
}
|
||||
if (myEditor.getSoftWrapModel().getSoftWrap(maxOffset) != null) {
|
||||
x += myEditor.getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
|
||||
}
|
||||
return (int)x;
|
||||
}
|
||||
|
||||
public void reinitSettings() {
|
||||
assertIsDispatchThread();
|
||||
myPlainSpaceWidth = -1;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.impl.view;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.bidi.BidiRegionsSeparator;
|
||||
import com.intellij.openapi.editor.bidi.LanguageBidiRegionsSeparator;
|
||||
import com.intellij.openapi.editor.colors.FontPreferences;
|
||||
@@ -46,8 +47,8 @@ class LineLayout {
|
||||
/**
|
||||
* Creates a layout for a fragment of text from editor.
|
||||
*/
|
||||
LineLayout(@NotNull EditorView view, int startOffset, int endOffset, boolean skipBidiLayout) {
|
||||
this(createFragments(view, startOffset, endOffset, skipBidiLayout), false);
|
||||
LineLayout(@NotNull EditorView view, int line, boolean skipBidiLayout) {
|
||||
this(createFragments(view, line, skipBidiLayout), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +57,7 @@ class LineLayout {
|
||||
LineLayout(@NotNull EditorView view, @NotNull CharSequence text, @JdkConstants.FontStyle int fontStyle) {
|
||||
this(createFragments(view, text, fontStyle), true);
|
||||
}
|
||||
|
||||
|
||||
private LineLayout(@NotNull List<BidiRun> runs, boolean calculateWidth) {
|
||||
myBidiRunsInLogicalOrder = runs.toArray(new BidiRun[runs.size()]);
|
||||
myBidiRunsInVisualOrder = myBidiRunsInLogicalOrder.clone();
|
||||
@@ -65,7 +66,7 @@ class LineLayout {
|
||||
|
||||
myWidth = calculateWidth ? calculateWidth() : -1;
|
||||
}
|
||||
|
||||
|
||||
// runs are supposed to be in logical order initially
|
||||
private static void reorderRunsVisually(BidiRun[] bidiRuns) {
|
||||
if (bidiRuns.length > 1) {
|
||||
@@ -82,11 +83,14 @@ class LineLayout {
|
||||
return Bidi.requiresBidi(chars, 0, chars.length);
|
||||
}
|
||||
|
||||
private static List<BidiRun> createFragments(@NotNull EditorView view, int lineStartOffset, int lineEndOffset, boolean skipBidiLayout) {
|
||||
private static List<BidiRun> createFragments(@NotNull EditorView view, int line, boolean skipBidiLayout) {
|
||||
EditorImpl editor = view.getEditor();
|
||||
Document document = editor.getDocument();
|
||||
int lineStartOffset = document.getLineStartOffset(line);
|
||||
int lineEndOffset = document.getLineEndOffset(line);
|
||||
if (lineEndOffset <= lineStartOffset) return Collections.emptyList();
|
||||
if (skipBidiLayout) return Collections.singletonList(new BidiRun(lineEndOffset - lineStartOffset));
|
||||
EditorImpl editor = view.getEditor();
|
||||
CharSequence text = editor.getDocument().getImmutableCharSequence().subSequence(lineStartOffset, lineEndOffset);
|
||||
CharSequence text = document.getImmutableCharSequence().subSequence(lineStartOffset, lineEndOffset);
|
||||
char[] chars = CharArrayUtil.fromSequence(text);
|
||||
return createRuns(editor, chars, lineStartOffset);
|
||||
}
|
||||
@@ -240,8 +244,8 @@ class LineLayout {
|
||||
* If <code>quickEvaluationListener</code> is provided, quick approximate iteration becomes enabled, listener will be invoked
|
||||
* if approximation will in fact be used during width calculation.
|
||||
*/
|
||||
Iterable<VisualFragment> getFragmentsInVisualOrder(@NotNull final EditorView view,
|
||||
final int lineStartOffset,
|
||||
Iterator<VisualFragment> getFragmentsInVisualOrder(@NotNull final EditorView view,
|
||||
final int line,
|
||||
final float startX,
|
||||
final int startVisualColumn,
|
||||
final int startOffset,
|
||||
@@ -257,18 +261,13 @@ class LineLayout {
|
||||
for (BidiRun run : myBidiRunsInLogicalOrder) {
|
||||
if (run.endOffset <= startOffset) continue;
|
||||
if (run.startOffset >= endOffset) break;
|
||||
runList.add(run.subRun(view, lineStartOffset, startOffset, endOffset, quickEvaluationListener));
|
||||
runList.add(run.subRun(view, line, startOffset, endOffset, quickEvaluationListener));
|
||||
}
|
||||
runs = runList.toArray(new BidiRun[runList.size()]);
|
||||
reorderRunsVisually(runs);
|
||||
}
|
||||
final int startLogicalColumn = view.offsetToLogicalPosition(lineStartOffset + startOffset).column;
|
||||
return new Iterable<VisualFragment>() {
|
||||
@Override
|
||||
public Iterator<VisualFragment> iterator() {
|
||||
return new VisualOrderIterator(view, lineStartOffset, startX, startVisualColumn, startLogicalColumn, startOffset, runs);
|
||||
}
|
||||
};
|
||||
final int startLogicalColumn = view.getLogicalPositionCache().offsetToLogicalColumn(line, startOffset);
|
||||
return new VisualOrderIterator(view, line, startX, startVisualColumn, startLogicalColumn, startOffset, runs);
|
||||
}
|
||||
|
||||
boolean isLtr() {
|
||||
@@ -348,7 +347,7 @@ class LineLayout {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
private BidiRun subRun(@NotNull EditorView view, int lineStartOffset, int targetStartOffset, int targetEndOffset,
|
||||
private BidiRun subRun(@NotNull EditorView view, int line, int targetStartOffset, int targetEndOffset,
|
||||
@Nullable Runnable quickEvaluationListener) {
|
||||
assert targetStartOffset < endOffset;
|
||||
assert targetEndOffset > startOffset;
|
||||
@@ -359,7 +358,7 @@ class LineLayout {
|
||||
for (Chunk chunk : getChunks()) {
|
||||
if (chunk.endOffset <= start) continue;
|
||||
if (chunk.startOffset >= end) break;
|
||||
subChunks.add(chunk.subChunk(view, this, lineStartOffset, start, end, quickEvaluationListener));
|
||||
subChunks.add(chunk.subChunk(view, this, line, start, end, quickEvaluationListener));
|
||||
}
|
||||
subRun.chunks = subChunks.toArray(new Chunk[subChunks.size()]);
|
||||
return subRun;
|
||||
@@ -376,11 +375,12 @@ class LineLayout {
|
||||
this.endOffset = endOffset;
|
||||
}
|
||||
|
||||
private void ensureLayout(@NotNull EditorView view, BidiRun run, int lineStartOffset) {
|
||||
private void ensureLayout(@NotNull EditorView view, BidiRun run, int line) {
|
||||
if (isReal()) {
|
||||
view.getTextLayoutCache().onChunkAccess(this);
|
||||
}
|
||||
if (!fragments.isEmpty()) return;
|
||||
int lineStartOffset = view.getEditor().getDocument().getLineStartOffset(line);
|
||||
int start = lineStartOffset + startOffset;
|
||||
int end = lineStartOffset + endOffset;
|
||||
IterationState it = new IterationState(view.getEditor(), start, end, false, false, false, false);
|
||||
@@ -395,7 +395,7 @@ class LineLayout {
|
||||
assert !fragments.isEmpty();
|
||||
}
|
||||
|
||||
private Chunk subChunk(EditorView view, BidiRun run, int lineStartOffset, int targetStartOffset, int targetEndOffset,
|
||||
private Chunk subChunk(EditorView view, BidiRun run, int line, int targetStartOffset, int targetEndOffset,
|
||||
@Nullable Runnable quickEvaluationListener) {
|
||||
assert targetStartOffset < endOffset;
|
||||
assert targetEndOffset > startOffset;
|
||||
@@ -403,12 +403,12 @@ class LineLayout {
|
||||
int end = Math.min(endOffset, targetEndOffset);
|
||||
if (quickEvaluationListener != null && fragments.isEmpty()) {
|
||||
quickEvaluationListener.run();
|
||||
return new ApproximationChunk(view, lineStartOffset, start, end);
|
||||
return new ApproximationChunk(view, line, start, end);
|
||||
}
|
||||
if (start == startOffset && end == this.endOffset) {
|
||||
return this;
|
||||
}
|
||||
ensureLayout(view, run, lineStartOffset);
|
||||
ensureLayout(view, run, line);
|
||||
Chunk chunk = new Chunk(start, end);
|
||||
int offset = startOffset;
|
||||
for (LineFragment fragment : fragments) {
|
||||
@@ -432,10 +432,10 @@ class LineLayout {
|
||||
}
|
||||
|
||||
private static class ApproximationChunk extends Chunk {
|
||||
private ApproximationChunk(@NotNull EditorView view, int lineStartOffset, int start, int end) {
|
||||
private ApproximationChunk(@NotNull EditorView view, int line, int start, int end) {
|
||||
super(start, end);
|
||||
int startColumn = view.offsetToLogicalPosition(lineStartOffset + start).column;
|
||||
int endColumn = view.offsetToLogicalPosition(lineStartOffset + end).column;
|
||||
int startColumn = view.getLogicalPositionCache().offsetToLogicalColumn(line, start);
|
||||
int endColumn = view.getLogicalPositionCache().offsetToLogicalColumn(line, end);
|
||||
fragments.add(new ApproximationFragment(end - start, endColumn - startColumn, view.getMaxCharWidth()));
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ class LineLayout {
|
||||
|
||||
private static class VisualOrderIterator implements Iterator<VisualFragment> {
|
||||
private final EditorView myView;
|
||||
private final int myLineStartOffset;
|
||||
private final int myLine;
|
||||
private final BidiRun[] myRuns;
|
||||
private int myRunIndex = 0;
|
||||
private int myChunkIndex = 0;
|
||||
@@ -455,10 +455,10 @@ class LineLayout {
|
||||
private int myOffsetInsideRun = 0;
|
||||
private VisualFragment myFragment = new VisualFragment();
|
||||
|
||||
private VisualOrderIterator(EditorView view, int lineStartOffset,
|
||||
private VisualOrderIterator(EditorView view, int line,
|
||||
float startX, int startVisualColumn, int startLogicalColumn, int startOffset, BidiRun[] runsInVisualOrder) {
|
||||
myView = view;
|
||||
myLineStartOffset = lineStartOffset;
|
||||
myLine = line;
|
||||
myRuns = runsInVisualOrder;
|
||||
myFragment.startX = startX;
|
||||
myFragment.startVisualColumn = startVisualColumn;
|
||||
@@ -474,7 +474,7 @@ class LineLayout {
|
||||
if (myChunkIndex >= chunks.length) return false;
|
||||
Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex];
|
||||
if (myView != null) {
|
||||
chunk.ensureLayout(myView, run, myLineStartOffset);
|
||||
chunk.ensureLayout(myView, run, myLine);
|
||||
}
|
||||
return myFragmentIndex < chunk.fragments.size();
|
||||
}
|
||||
|
||||
+6
@@ -83,6 +83,12 @@ class LogicalPositionCache implements PrioritizedDocumentListener, Disposable {
|
||||
LineData lineData = getLineInfo(line);
|
||||
return new LogicalPosition(line, lineData.offsetToLogicalColumn(myDocument, line, myTabSize, offset));
|
||||
}
|
||||
|
||||
synchronized int offsetToLogicalColumn(int line, int intraLineOffset) {
|
||||
if (line < 0 || line >= myDocument.getLineCount()) return 0;
|
||||
LineData lineData = getLineInfo(line);
|
||||
return lineData.offsetToLogicalColumn(myDocument, line, myTabSize, myDocument.getLineStartOffset(line) + intraLineOffset);
|
||||
}
|
||||
|
||||
synchronized int logicalPositionToOffset(@NotNull LogicalPosition pos) {
|
||||
int line = pos.line;
|
||||
|
||||
+1
-8
@@ -127,7 +127,7 @@ class TextLayoutCache implements PrioritizedDocumentListener, Disposable {
|
||||
checkDisposed();
|
||||
LineLayout result = myLines.get(line);
|
||||
if (result == null || result == myBidiNotRequiredMarker) {
|
||||
result = createLineLayout(line, result == myBidiNotRequiredMarker);
|
||||
result = new LineLayout(myView, line, result == myBidiNotRequiredMarker);
|
||||
myLines.set(line, result);
|
||||
}
|
||||
return result;
|
||||
@@ -138,13 +138,6 @@ class TextLayoutCache implements PrioritizedDocumentListener, Disposable {
|
||||
return layout != null && layout != myBidiNotRequiredMarker;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LineLayout createLineLayout(int line, boolean skipBidiLayout) {
|
||||
int lineStart = myDocument.getLineStartOffset(line);
|
||||
int lineEnd = myDocument.getLineEndOffset(line);
|
||||
return new LineLayout(myView, lineStart, lineEnd, skipBidiLayout);
|
||||
}
|
||||
|
||||
private int getChunkCacheSizeLimit() {
|
||||
return myView.getEditor().getContentComponent().isShowing() ? MAX_CHUNKS_IN_ACTIVE_EDITOR : MAX_CHUNKS_IN_INACTIVE_EDITOR;
|
||||
}
|
||||
|
||||
+67
-28
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.ex.FoldingModelEx;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.editor.impl.SoftWrapModelImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -35,26 +36,35 @@ import java.util.NoSuchElementException;
|
||||
*/
|
||||
class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterator.Fragment> {
|
||||
|
||||
/**
|
||||
* If <code>quickEvaluationListener</code> is provided, quick approximate iteration mode becomes enabled, listener will be invoked
|
||||
* if approximation will in fact be used during width calculation.
|
||||
*/
|
||||
static Iterable<Fragment> create(final EditorView view, final int offset, final boolean beforeSoftWrap,
|
||||
@Nullable final Runnable quickEvaluationListener) {
|
||||
static Iterable<Fragment> create(final EditorView view, final int offset, final boolean beforeSoftWrap) {
|
||||
return new Iterable<Fragment>() {
|
||||
@Override
|
||||
public Iterator<Fragment> iterator() {
|
||||
return new VisualLineFragmentsIterator(view, offset, beforeSoftWrap, quickEvaluationListener);
|
||||
return new VisualLineFragmentsIterator(view, offset, beforeSoftWrap, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final EditorView myView;
|
||||
private final Document myDocument;
|
||||
private final FoldRegion[] myRegions;
|
||||
private final Fragment myFragment = new Fragment();
|
||||
private final int myVisualLineStartOffset;
|
||||
private final Runnable myQuickEvaluationListener;
|
||||
/**
|
||||
* If <code>quickEvaluationListener</code> is provided, quick approximate iteration mode becomes enabled, listener will be invoked
|
||||
* if approximation will in fact be used during width calculation.
|
||||
*/
|
||||
static Iterable<Fragment> create(final EditorView view, @NotNull final VisualLinesIterator visualLinesIterator,
|
||||
@Nullable final Runnable quickEvaluationListener) {
|
||||
return new Iterable<Fragment>() {
|
||||
@Override
|
||||
public Iterator<Fragment> iterator() {
|
||||
return new VisualLineFragmentsIterator(view, visualLinesIterator, quickEvaluationListener);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private EditorView myView;
|
||||
private Document myDocument;
|
||||
private FoldRegion[] myRegions;
|
||||
private Fragment myFragment = new Fragment();
|
||||
private int myVisualLineStartOffset;
|
||||
private Runnable myQuickEvaluationListener;
|
||||
|
||||
private int mySegmentStartOffset;
|
||||
private int mySegmentEndOffset;
|
||||
@@ -69,15 +79,9 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
|
||||
private int myNextWrapOffset;
|
||||
|
||||
private VisualLineFragmentsIterator(EditorView view, int offset, boolean beforeSoftWrap, @Nullable Runnable quickEvaluationListener) {
|
||||
myQuickEvaluationListener = quickEvaluationListener;
|
||||
myView = view;
|
||||
EditorImpl editor = view.getEditor();
|
||||
myDocument = editor.getDocument();
|
||||
FoldingModelEx foldingModel = editor.getFoldingModel();
|
||||
FoldRegion[] regions = foldingModel.fetchTopLevel();
|
||||
myRegions = regions == null ? FoldRegion.EMPTY_ARRAY : regions;
|
||||
int visualLineStartOffset = EditorUtil.getNotFoldedLineStartOffset(editor, offset);
|
||||
|
||||
|
||||
SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel();
|
||||
List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps();
|
||||
int currentOrPrevWrapIndex = softWrapModel.getSoftWrapIndex(offset);
|
||||
@@ -89,16 +93,51 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
|
||||
}
|
||||
SoftWrap currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null :
|
||||
softWraps.get(currentOrPrevWrapIndex);
|
||||
SoftWrap followingWrap = (currentOrPrevWrapIndex + 1) >= softWraps.size() ? null : softWraps.get(currentOrPrevWrapIndex + 1);
|
||||
|
||||
if (currentOrPrevWrap != null && currentOrPrevWrap.getStart() > visualLineStartOffset) {
|
||||
visualLineStartOffset = currentOrPrevWrap.getStart();
|
||||
}
|
||||
|
||||
myVisualLineStartOffset = mySegmentStartOffset = visualLineStartOffset;
|
||||
int nextFoldingIndex = editor.getFoldingModel().getLastCollapsedRegionBefore(visualLineStartOffset) + 1;
|
||||
|
||||
init(view,
|
||||
visualLineStartOffset,
|
||||
editor.getDocument().getLineNumber(visualLineStartOffset),
|
||||
currentOrPrevWrapIndex,
|
||||
nextFoldingIndex,
|
||||
quickEvaluationListener);
|
||||
}
|
||||
|
||||
myCurrentFoldRegionIndex = foldingModel.getLastCollapsedRegionBefore(mySegmentStartOffset) + 1;
|
||||
myCurrentEndLogicalLine = myDocument.getLineNumber(mySegmentStartOffset);
|
||||
public VisualLineFragmentsIterator(@NotNull EditorView view, @NotNull VisualLinesIterator visualLinesIterator,
|
||||
@Nullable Runnable quickEvaluationListener) {
|
||||
assert !visualLinesIterator.atEnd();
|
||||
init(view,
|
||||
visualLinesIterator.getVisualLineStartOffset(),
|
||||
visualLinesIterator.getStartLogicalLine(),
|
||||
visualLinesIterator.getStartOrPrevWrapIndex(),
|
||||
visualLinesIterator.getStartFoldingIndex(),
|
||||
quickEvaluationListener);
|
||||
}
|
||||
|
||||
private void init(EditorView view, int startOffset, int startLogicalLine, int currentOrPrevWrapIndex, int nextFoldingIndex,
|
||||
@Nullable Runnable quickEvaluationListener) {
|
||||
myQuickEvaluationListener = quickEvaluationListener;
|
||||
myView = view;
|
||||
EditorImpl editor = view.getEditor();
|
||||
myDocument = editor.getDocument();
|
||||
FoldingModelEx foldingModel = editor.getFoldingModel();
|
||||
FoldRegion[] regions = foldingModel.fetchTopLevel();
|
||||
myRegions = regions == null ? FoldRegion.EMPTY_ARRAY : regions;
|
||||
SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel();
|
||||
List<? extends SoftWrap> softWraps = softWrapModel.getRegisteredSoftWraps();
|
||||
SoftWrap currentOrPrevWrap = currentOrPrevWrapIndex < 0 || currentOrPrevWrapIndex >= softWraps.size() ? null :
|
||||
softWraps.get(currentOrPrevWrapIndex);
|
||||
SoftWrap followingWrap = (currentOrPrevWrapIndex + 1) < 0 || (currentOrPrevWrapIndex + 1) >= softWraps.size() ? null :
|
||||
softWraps.get(currentOrPrevWrapIndex + 1);
|
||||
|
||||
myVisualLineStartOffset = mySegmentStartOffset = startOffset;
|
||||
|
||||
myCurrentFoldRegionIndex = nextFoldingIndex;
|
||||
myCurrentEndLogicalLine = startLogicalLine;
|
||||
if (mySegmentStartOffset == 0) {
|
||||
myCurrentX = myView.getPrefixTextWidthInPixels();
|
||||
}
|
||||
@@ -117,9 +156,9 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
|
||||
mySegmentEndOffset = Math.min(myNextWrapOffset, Math.min(mySegmentEndOffset, myDocument.getLineEndOffset(line)));
|
||||
int lineStartOffset = myDocument.getLineStartOffset(line);
|
||||
myFragmentIterator = myView.getTextLayoutCache().getLineLayout(line).
|
||||
getFragmentsInVisualOrder(myView, lineStartOffset, myCurrentX, myCurrentVisualColumn,
|
||||
mySegmentStartOffset - lineStartOffset, mySegmentEndOffset - lineStartOffset,
|
||||
myQuickEvaluationListener).iterator();
|
||||
getFragmentsInVisualOrder(myView, line, myCurrentX, myCurrentVisualColumn,
|
||||
mySegmentStartOffset - lineStartOffset, mySegmentEndOffset - lineStartOffset,
|
||||
myQuickEvaluationListener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.editor.impl.view;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.FoldRegion;
|
||||
import com.intellij.openapi.editor.SoftWrap;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.editor.impl.SoftWrapModelImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class VisualLinesIterator {
|
||||
private final Document myDocument;
|
||||
private final FoldRegion[] myFoldRegions;
|
||||
private final List<? extends SoftWrap> mySoftWraps;
|
||||
|
||||
private int myVisualLine;
|
||||
private int myOffset;
|
||||
private int myLogicalLine = 1;
|
||||
private int myFoldRegion;
|
||||
private int mySoftWrap;
|
||||
|
||||
VisualLinesIterator(@NotNull EditorView view, int startVisualLine) {
|
||||
EditorImpl editor = view.getEditor();
|
||||
SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel();
|
||||
myDocument = editor.getDocument();
|
||||
FoldRegion[] regions = editor.getFoldingModel().fetchTopLevel();
|
||||
myFoldRegions = regions == null ? FoldRegion.EMPTY_ARRAY : regions;
|
||||
mySoftWraps = softWrapModel.getRegisteredSoftWraps();
|
||||
|
||||
if (startVisualLine < 0 || startVisualLine >= editor.getVisibleLineCount()) {
|
||||
myOffset = -1;
|
||||
}
|
||||
else if (startVisualLine > 0) {
|
||||
myVisualLine = startVisualLine;
|
||||
myOffset = startVisualLine >= 0 && startVisualLine < editor.getVisibleLineCount() ? view.visualLineToOffset(startVisualLine) : -1;
|
||||
myLogicalLine = myDocument.getLineNumber(myOffset) + 1;
|
||||
mySoftWrap = softWrapModel.getSoftWrapIndex(myOffset) + 1;
|
||||
if (mySoftWrap <= 0) {
|
||||
mySoftWrap = -mySoftWrap;
|
||||
}
|
||||
myFoldRegion = editor.getFoldingModel().getLastCollapsedRegionBefore(myOffset) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
boolean atEnd() {
|
||||
return myOffset == -1;
|
||||
}
|
||||
|
||||
void advance() {
|
||||
checkEnd();
|
||||
int nextWrapOffset = getNextSoftWrapOffset();
|
||||
int nextLineStart = getNextNotFoldedLineStartOffset();
|
||||
myOffset = Math.min(nextWrapOffset, nextLineStart);
|
||||
if (myOffset == Integer.MAX_VALUE) {
|
||||
myOffset = -1;
|
||||
}
|
||||
else if (myOffset == nextWrapOffset) {
|
||||
mySoftWrap++;
|
||||
}
|
||||
else {
|
||||
myLogicalLine++;
|
||||
}
|
||||
myVisualLine++;
|
||||
}
|
||||
|
||||
private int getNextSoftWrapOffset() {
|
||||
return mySoftWrap < mySoftWraps.size() ? mySoftWraps.get(mySoftWrap).getStart() : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private int getNextNotFoldedLineStartOffset() {
|
||||
while (myLogicalLine < myDocument.getLineCount()) {
|
||||
int lineStartOffset = myDocument.getLineStartOffset(myLogicalLine);
|
||||
if (!isCollapsed(lineStartOffset)) return lineStartOffset;
|
||||
myLogicalLine++;
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private boolean isCollapsed(int offset) {
|
||||
while (myFoldRegion < myFoldRegions.length) {
|
||||
FoldRegion foldRegion = myFoldRegions[myFoldRegion];
|
||||
if (offset <= foldRegion.getStartOffset()) return false;
|
||||
if (offset <= foldRegion.getEndOffset()) return true;
|
||||
myFoldRegion++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int getVisualLine() {
|
||||
checkEnd();
|
||||
return myVisualLine;
|
||||
}
|
||||
|
||||
int getVisualLineStartOffset() {
|
||||
checkEnd();
|
||||
return myOffset;
|
||||
}
|
||||
|
||||
int getStartLogicalLine() {
|
||||
checkEnd();
|
||||
return myLogicalLine - 1;
|
||||
}
|
||||
|
||||
int getStartOrPrevWrapIndex() {
|
||||
checkEnd();
|
||||
return mySoftWrap - 1;
|
||||
}
|
||||
|
||||
int getStartFoldingIndex() {
|
||||
checkEnd();
|
||||
return myFoldRegion;
|
||||
}
|
||||
|
||||
private void checkEnd() {
|
||||
if (atEnd()) throw new IllegalStateException("Iteration finished");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user