mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
optimize editor painting - do not invoke costly visualPositionTofOffset conversions
This commit is contained in:
+17
-8
@@ -135,14 +135,17 @@ class EditorPainter implements TextDrawingCallback {
|
||||
private void paintBackground(Graphics2D g, Rectangle clip, int startVisualLine, int endVisualLine) {
|
||||
int lineCount = myEditor.getVisibleLineCount();
|
||||
final Map<Integer, Couple<Integer>> virtualSelectionMap = createVirtualSelectionMap(startVisualLine, endVisualLine);
|
||||
for (int visualLine = startVisualLine; visualLine <= endVisualLine; visualLine++) {
|
||||
VisualLinesIterator visLinesIterator = new VisualLinesIterator(myView, startVisualLine);
|
||||
while (!visLinesIterator.atEnd()) {
|
||||
int visualLine = visLinesIterator.getVisualLine();
|
||||
if (visualLine > endVisualLine) break;
|
||||
int y = myView.visualLineToY(visualLine);
|
||||
LineLayout prefixLayout = myView.getPrefixLayout();
|
||||
if (visualLine == 0 && prefixLayout != null) {
|
||||
paintBackground(g, myView.getPrefixAttributes(), 0, y, prefixLayout.getWidth());
|
||||
}
|
||||
if (visualLine >= lineCount) break;
|
||||
paintLineFragments(g, clip, visualLine, y, new LineFragmentPainter() {
|
||||
paintLineFragments(g, clip, visLinesIterator, y, new LineFragmentPainter() {
|
||||
@Override
|
||||
public void paintBeforeLineStart(Graphics2D g, TextAttributes attributes, int columnEnd, float xEnd, int y) {
|
||||
paintBackground(g, attributes, 0, y, xEnd);
|
||||
@@ -168,6 +171,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
}
|
||||
}
|
||||
});
|
||||
visLinesIterator.advance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +324,10 @@ class EditorPainter implements TextDrawingCallback {
|
||||
final CharSequence text = myDocument.getImmutableCharSequence();
|
||||
final EditorImpl.LineWhitespacePaintingStrategy whitespacePaintingStrategy = myEditor.new LineWhitespacePaintingStrategy();
|
||||
int lineCount = myEditor.getVisibleLineCount();
|
||||
for (int visualLine = startVisualLine; visualLine <= endVisualLine; visualLine++) {
|
||||
VisualLinesIterator visLinesIterator = new VisualLinesIterator(myView, startVisualLine);
|
||||
while (!visLinesIterator.atEnd()) {
|
||||
int visualLine = visLinesIterator.getVisualLine();
|
||||
if (visualLine > endVisualLine) break;
|
||||
int y = myView.visualLineToY(visualLine) + myView.getAscent();
|
||||
LineLayout prefixLayout = myView.getPrefixLayout();
|
||||
if (visualLine == 0 && prefixLayout != null) {
|
||||
@@ -332,7 +339,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
|
||||
final int[] currentLogicalLine = new int[] {-1};
|
||||
|
||||
paintLineFragments(g, clip, visualLine, y, new LineFragmentPainter() {
|
||||
paintLineFragments(g, clip, visLinesIterator, y, new LineFragmentPainter() {
|
||||
@Override
|
||||
public void paintBeforeLineStart(Graphics2D g, TextAttributes attributes, int columnEnd, float xEnd, int y) {
|
||||
SoftWrapModelImpl softWrapModel = myEditor.getSoftWrapModel();
|
||||
@@ -374,6 +381,7 @@ class EditorPainter implements TextDrawingCallback {
|
||||
}
|
||||
}
|
||||
});
|
||||
visLinesIterator.advance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,15 +815,16 @@ class EditorPainter implements TextDrawingCallback {
|
||||
}
|
||||
}
|
||||
|
||||
private void paintLineFragments(Graphics2D g, Rectangle clip, int visualLine, int y, LineFragmentPainter painter) {
|
||||
private void paintLineFragments(Graphics2D g, Rectangle clip, VisualLinesIterator visLineIterator, int y, LineFragmentPainter painter) {
|
||||
int visualLine = visLineIterator.getVisualLine();
|
||||
float x = visualLine == 0 ? myView.getPrefixTextWidthInPixels() : 0;
|
||||
int offset = myView.visualPositionToOffset(new VisualPosition(visualLine, 0));
|
||||
int visualLineEndOffset = myView.visualPositionToOffset(new VisualPosition(visualLine, Integer.MAX_VALUE, true));
|
||||
int offset = visLineIterator.getVisualLineStartOffset();
|
||||
int visualLineEndOffset = visLineIterator.getVisualLineEndOffset();
|
||||
IterationState it = null;
|
||||
int prevEndOffset = -1;
|
||||
boolean firstFragment = true;
|
||||
int maxColumn = 0;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, false)) {
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, visLineIterator, null)) {
|
||||
int fragmentStartOffset = fragment.getStartOffset();
|
||||
int start = fragmentStartOffset;
|
||||
int end = fragment.getEndOffset();
|
||||
|
||||
+108
-61
@@ -25,108 +25,155 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
class VisualLinesIterator {
|
||||
private final EditorView myView;
|
||||
private final EditorImpl myEditor;
|
||||
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;
|
||||
@NotNull
|
||||
private Location myLocation;
|
||||
private Location myNextLocation;
|
||||
|
||||
VisualLinesIterator(@NotNull EditorView view, int startVisualLine) {
|
||||
EditorImpl editor = view.getEditor();
|
||||
SoftWrapModelImpl softWrapModel = editor.getSoftWrapModel();
|
||||
myDocument = editor.getDocument();
|
||||
FoldRegion[] regions = editor.getFoldingModel().fetchTopLevel();
|
||||
myView = view;
|
||||
myEditor = view.getEditor();
|
||||
SoftWrapModelImpl softWrapModel = myEditor.getSoftWrapModel();
|
||||
myDocument = myEditor.getDocument();
|
||||
FoldRegion[] regions = myEditor.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;
|
||||
}
|
||||
|
||||
myLocation = new Location(startVisualLine);
|
||||
}
|
||||
|
||||
boolean atEnd() {
|
||||
return myOffset == -1;
|
||||
return myLocation.atEnd();
|
||||
}
|
||||
|
||||
void advance() {
|
||||
checkEnd();
|
||||
int nextWrapOffset = getNextSoftWrapOffset();
|
||||
myOffset = getNextVisualLineStartOffset(nextWrapOffset);
|
||||
if (myOffset == Integer.MAX_VALUE) {
|
||||
myOffset = -1;
|
||||
if (myNextLocation == null) {
|
||||
myLocation.advance();
|
||||
}
|
||||
else if (myOffset == nextWrapOffset) {
|
||||
mySoftWrap++;
|
||||
else {
|
||||
myLocation = myNextLocation;
|
||||
myNextLocation = null;
|
||||
}
|
||||
myVisualLine++;
|
||||
while (myFoldRegion < myFoldRegions.length && myFoldRegions[myFoldRegion].getStartOffset() < myOffset) myFoldRegion++;
|
||||
}
|
||||
|
||||
private int getNextSoftWrapOffset() {
|
||||
return mySoftWrap < mySoftWraps.size() ? mySoftWraps.get(mySoftWrap).getStart() : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private int getNextVisualLineStartOffset(int nextWrapOffset) {
|
||||
while (myLogicalLine < myDocument.getLineCount()) {
|
||||
int lineStartOffset = myDocument.getLineStartOffset(myLogicalLine);
|
||||
if (lineStartOffset > nextWrapOffset) return nextWrapOffset;
|
||||
myLogicalLine++;
|
||||
if (!isCollapsed(lineStartOffset)) return lineStartOffset;
|
||||
}
|
||||
return nextWrapOffset;
|
||||
}
|
||||
|
||||
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;
|
||||
return myLocation.visualLine;
|
||||
}
|
||||
|
||||
int getVisualLineStartOffset() {
|
||||
checkEnd();
|
||||
return myOffset;
|
||||
return myLocation.offset;
|
||||
}
|
||||
|
||||
int getVisualLineEndOffset() {
|
||||
checkEnd();
|
||||
if (myNextLocation == null) {
|
||||
myNextLocation = myLocation.clone();
|
||||
myNextLocation.advance();
|
||||
}
|
||||
return myNextLocation.atEnd() ? myDocument.getTextLength() :
|
||||
myNextLocation.softWrap == myLocation.softWrap ? myDocument.getLineEndOffset(myNextLocation.logicalLine - 2) :
|
||||
myNextLocation.offset;
|
||||
}
|
||||
|
||||
int getStartLogicalLine() {
|
||||
checkEnd();
|
||||
return myLogicalLine - 1;
|
||||
return myLocation.logicalLine - 1;
|
||||
}
|
||||
|
||||
int getStartOrPrevWrapIndex() {
|
||||
checkEnd();
|
||||
return mySoftWrap - 1;
|
||||
return myLocation.softWrap - 1;
|
||||
}
|
||||
|
||||
int getStartFoldingIndex() {
|
||||
checkEnd();
|
||||
return myFoldRegion;
|
||||
return myLocation.foldRegion;
|
||||
}
|
||||
|
||||
private void checkEnd() {
|
||||
if (atEnd()) throw new IllegalStateException("Iteration finished");
|
||||
}
|
||||
|
||||
private final class Location implements Cloneable {
|
||||
private int visualLine; // current visual line
|
||||
private int offset; // start offset of the current visual line
|
||||
private int logicalLine = 1; // 1 + start logical line of the current visual line
|
||||
private int foldRegion; // index of the first folding region on current or following visual lines
|
||||
private int softWrap; // index of the first soft wrap after the start of current visual line
|
||||
|
||||
private Location(int startVisualLine) {
|
||||
if (startVisualLine < 0 || startVisualLine >= myEditor.getVisibleLineCount()) {
|
||||
offset = -1;
|
||||
}
|
||||
else if (startVisualLine > 0) {
|
||||
visualLine = startVisualLine;
|
||||
offset = myView.visualLineToOffset(startVisualLine);
|
||||
logicalLine = myDocument.getLineNumber(offset) + 1;
|
||||
softWrap = myEditor.getSoftWrapModel().getSoftWrapIndex(offset) + 1;
|
||||
if (softWrap <= 0) {
|
||||
softWrap = -softWrap;
|
||||
}
|
||||
foldRegion = myEditor.getFoldingModel().getLastCollapsedRegionBefore(offset) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void advance() {
|
||||
int nextWrapOffset = getNextSoftWrapOffset();
|
||||
offset = getNextVisualLineStartOffset(nextWrapOffset);
|
||||
if (offset == Integer.MAX_VALUE) {
|
||||
offset = -1;
|
||||
}
|
||||
else if (offset == nextWrapOffset) {
|
||||
softWrap++;
|
||||
}
|
||||
visualLine++;
|
||||
while (foldRegion < myFoldRegions.length && myFoldRegions[foldRegion].getStartOffset() < offset) foldRegion++;
|
||||
}
|
||||
|
||||
private int getNextSoftWrapOffset() {
|
||||
return softWrap < mySoftWraps.size() ? mySoftWraps.get(softWrap).getStart() : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private int getNextVisualLineStartOffset(int nextWrapOffset) {
|
||||
while (logicalLine < myDocument.getLineCount()) {
|
||||
int lineStartOffset = myDocument.getLineStartOffset(logicalLine);
|
||||
if (lineStartOffset > nextWrapOffset) return nextWrapOffset;
|
||||
logicalLine++;
|
||||
if (!isCollapsed(lineStartOffset)) return lineStartOffset;
|
||||
}
|
||||
return nextWrapOffset;
|
||||
}
|
||||
|
||||
private boolean isCollapsed(int offset) {
|
||||
while (foldRegion < myFoldRegions.length) {
|
||||
FoldRegion region = myFoldRegions[foldRegion];
|
||||
if (offset <= region.getStartOffset()) return false;
|
||||
if (offset <= region.getEndOffset()) return true;
|
||||
foldRegion++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean atEnd() {
|
||||
return offset == -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Location clone() {
|
||||
try {
|
||||
return (Location)super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user