diff options
author | Thomas Wolf | 2019-09-15 13:17:52 +0000 |
---|---|---|
committer | Thomas Wolf | 2019-09-19 16:01:02 +0000 |
commit | 58f91bfc319901c60999a9f6ac226d152fcde15d (patch) | |
tree | 59f45758429301298bf2c9ec7467a46292fd5ae8 | |
parent | b5b8714a943abd86bd55c942b73c3ab2544e16c1 (diff) | |
download | eclipse.platform.text-58f91bfc319901c60999a9f6ac226d152fcde15d.tar.gz eclipse.platform.text-58f91bfc319901c60999a9f6ac226d152fcde15d.tar.xz eclipse.platform.text-58f91bfc319901c60999a9f6ac226d152fcde15d.zip |
Bug 366471 - Speed up line number drawing
LineNumberRulerColumn re-drew all visible numbers every time. This is
a bit expensive since drawing strings is complicated business.
Improve performance by taking advantage of the double buffering. If
during scrolling the new range overlaps with the last range, just copy
the still valid pixels to the new location and re-draw only the new
lines.
Change-Id: I38a485c0ee092455fd4a72275bce175bc68c2895
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
-rw-r--r-- | org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java | 172 |
1 files changed, 112 insertions, 60 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java index 0f98abf8bbd..a35bcd88a8e 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java @@ -398,6 +398,14 @@ public class LineNumberRulerColumn implements IVerticalRulerColumn { private int fCachedNumberOfDigits= -1; /** Flag indicating whether a relayout is required */ private boolean fRelayoutRequired= false; + /** Last top pixel. */ + private int fLastTopPixel = -1; + /** Last top model line. */ + private int fLastTopModelLine; + /** Last number of lines visible. */ + private int fLastNumberOfLines; + /** Last bottom model line. */ + private int fLastBottomModelLine; /** * Redraw runnable lock * @since 3.0 @@ -689,84 +697,128 @@ public class LineNumberRulerColumn implements IVerticalRulerColumn { Point size= fCanvas.getSize(); - if (size.x <= 0 || size.y <= 0) + if (size.x <= 0 || size.y <= 0) { return; + } if (fBuffer != null) { Rectangle r= fBuffer.getBounds(); - if (IS_MAC_BUG_516293 || r.width != size.x || r.height != size.y) { + if (r.width != size.x || r.height != size.y) { fBuffer.dispose(); fBuffer= null; } } ILineRange visibleLines= JFaceTextUtil.getVisibleModelLines(fCachedTextViewer); - if (visibleLines == null) + if (visibleLines == null) { return; + } - if (IS_MAC_BUG_516293) { - /* FIXME: Workaround (bug 516293): - * Relies on SWT implementation detail that GC drawing on macOS only draws at 100% zoom level. - * For higher zoom levels (200%), we manually scale the font and drawing coordinates, - * and then use getImageData(100) to extract the high-resolution image data. */ - fBuffer= new Image(fCanvas.getDisplay(), (ImageDataProvider) zoom -> { - fZoom = zoom; - internalSetZoom(zoom); - int width= size.x * zoom / 100; - int height= size.y * zoom / 100; - Image gcImage= new Image(fCanvas.getDisplay(), width, height); - - GC gc= new GC(gcImage); - Font font= fCanvas.getFont(); - if (zoom != 100) { - if (fLastFont != null && font == fLastFont.get()) { - font= fLastZoomedFont; - } else { - fLastFont= new WeakReference<>(font); - FontData fontData= font.getFontData()[0]; - fontData.setHeight(fontData.getHeight() * zoom / 100); - font= new Font(font.getDevice(), fontData); - fLastZoomedFont= font; - } + boolean bufferStillValid = fBuffer != null; + if (fBuffer == null) { + fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); + } + GC bufferGC= new GC(fBuffer); + if (fForeground != null) { + bufferGC.setForeground(fForeground); + } + bufferGC.setBackground(getBackground(fCanvas.getDisplay())); + try { + int topPixel= fCachedTextWidget.getTopPixel(); + int bufferY= 0; + int bufferH= size.y; + int numberOfLines= visibleLines.getNumberOfLines(); + int dy= topPixel - fLastTopPixel; + if (dy != 0 && bufferStillValid && fLastTopPixel >= 0 && numberOfLines > 1 && numberOfLines == fLastNumberOfLines) { + if (dy > 0 && dy < size.y) { + bufferGC.copyArea(0, dy, size.x, size.y - dy, 0, 0); + bufferY= size.y - dy; + bufferH= size.y - bufferY; + } else if (dy < 0 && -dy < size.y) { + bufferGC.copyArea(0, 0, size.x, size.y + dy, 0, -dy); + bufferY= 0; + bufferH= -dy; + } else { + dy= 0; } - gc.setFont(font); - if (fForeground != null) - gc.setForeground(fForeground); + } else { + dy= 0; + } + // dy == 0 means now "draw everything", either because there was no overlap, or we indeed didn't move + // (refresh or other cases), or there was a resize, or it's the first time. + int topModelLine= visibleLines.getStartLine(); + int bottomModelLine= topModelLine + numberOfLines - 1; + if (dy != 0) { + // Reduce the line range. + if (dy > 0) { + visibleLines= new LineRange(fLastBottomModelLine, bottomModelLine - fLastBottomModelLine + 1); + } else { + visibleLines= new LineRange(topModelLine, fLastTopModelLine - topModelLine + 1); + } + } + fLastTopPixel= topPixel; + fLastTopModelLine= topModelLine; + fLastNumberOfLines= numberOfLines; + fLastBottomModelLine= bottomModelLine; + if (IS_MAC_BUG_516293) { + /* FIXME: Workaround (bug 516293): + * Relies on SWT implementation detail that GC drawing on macOS only draws at 100% zoom level. + * For higher zoom levels (200%), we manually scale the font and drawing coordinates, + * and then use getImageData(100) to extract the high-resolution image data. */ + ILineRange lines= visibleLines; + Image zoomedBuffer= new Image(fCanvas.getDisplay(), (ImageDataProvider) zoom -> { + fZoom= zoom; + internalSetZoom(zoom); + int width= size.x * zoom / 100; + int height= size.y * zoom / 100; + Image gcImage= new Image(fCanvas.getDisplay(), width, height); + + GC gc= new GC(gcImage); + Font font= fCanvas.getFont(); + if (zoom != 100) { + if (fLastFont != null && font == fLastFont.get()) { + font= fLastZoomedFont; + } else { + fLastFont= new WeakReference<>(font); + FontData fontData= font.getFontData()[0]; + fontData.setHeight(fontData.getHeight() * zoom / 100); + font= new Font(font.getDevice(), fontData); + fLastZoomedFont= font; + } + } + gc.setFont(font); + if (fForeground != null) { + gc.setForeground(fForeground); + } + try { + gc.setBackground(getBackground(fCanvas.getDisplay())); + gc.fillRectangle(0, 0, width, height); + + doPaint(gc, lines); + } finally { + gc.dispose(); + fZoom= 100; + } + ImageData imageData= gcImage.getImageData(100); + gcImage.dispose(); + return imageData; + }); try { - gc.setBackground(getBackground(fCanvas.getDisplay())); - gc.fillRectangle(0, 0, width, height); - - doPaint(gc, visibleLines); + bufferGC.drawImage(zoomedBuffer, 0, bufferY, size.x, bufferH, 0, bufferY, size.x, bufferH); } finally { - gc.dispose(); - fZoom= 100; + zoomedBuffer.dispose(); } + } else { + // Draw directly into the buffer + bufferGC.setFont(fCanvas.getFont()); + bufferGC.fillRectangle(0, bufferY, size.x, bufferH); - ImageData imageData= gcImage.getImageData(100); - gcImage.dispose(); - return imageData; - }); - - } else { - if (fBuffer == null) - fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); - - GC gc= new GC(fBuffer); - gc.setFont(fCanvas.getFont()); - if (fForeground != null) - gc.setForeground(fForeground); - - try { - gc.setBackground(getBackground(fCanvas.getDisplay())); - gc.fillRectangle(0, 0, size.x, size.y); - - doPaint(gc, visibleLines); - } finally { - gc.dispose(); + doPaint(bufferGC, visibleLines); } + } finally { + bufferGC.dispose(); } - dest.drawImage(fBuffer, 0, 0); } @@ -834,8 +886,8 @@ public class LineNumberRulerColumn implements IVerticalRulerColumn { void doPaint(GC gc, ILineRange visibleLines) { Display display= fCachedTextWidget.getDisplay(); - // draw diff info - int y= -JFaceTextUtil.getHiddenTopLinePixels(fCachedTextWidget); + int firstWidgetLineToDraw= JFaceTextUtil.modelLineToWidgetLine(fCachedTextViewer, visibleLines.getStartLine()); + int y= fCachedTextWidget.getLinePixel(firstWidgetLineToDraw); // add empty lines if line is wrapped boolean isWrapActive= fCachedTextWidget.getWordWrap(); |