From 6f3b89e9f288116163bb49379004246de5c6cd3f Mon Sep 17 00:00:00 2001 From: Alexandr Miloslavskiy Date: Mon, 18 Dec 2023 22:59:11 +0300 Subject: [PATCH] Issue #932: Splitting out drawLineBackground() and drawLineForeground() Needed to paint entire background in next commit. Signed-off-by: Alexandr Miloslavskiy --- .../org/eclipse/swt/custom/StyledText.java | 14 ++- .../swt/custom/StyledTextRenderer.java | 91 ++++++++++++++----- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java index 96f6513e0dc..dd00b7ab2fd 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java @@ -5926,18 +5926,16 @@ void handlePaint(Event event) { if (event.width == 0 || event.height == 0) return; if (clientAreaWidth == 0 || clientAreaHeight == 0) return; - int startLine = getLineIndex(event.y); - int y = getLinePixel(startLine); - int endY = event.y + event.height; + final int endY = event.y + event.height; GC gc = event.gc; Color background = getBackground(); Color foreground = getForeground(); if (endY > 0) { - int lineCount = isSingleLine() ? 1 : content.getLineCount(); - int x = leftMargin - horizontalScrollOffset; - for (int i = startLine; y < endY && i < lineCount; i++) { - y += renderer.drawLine(i, x, y, gc, background, foreground); - } + final int startLine = getLineIndex(event.y); + final int endLine = isSingleLine() ? 1 : content.getLineCount(); + final int x = leftMargin - horizontalScrollOffset; + int y = getLinePixel(startLine); + y += renderer.drawLines(startLine, endLine, x, y, endY, gc, background, foreground); if (y < endY) { gc.setBackground(background); drawBackground(gc, 0, y, clientAreaWidth, endY - y); diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java index 2d4f3d413a9..648d79a7c69 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java @@ -183,6 +183,15 @@ public LineInfo(LineInfo info) { } } } + + private static class LineDrawInfo { + int index; + TextLayout layout; + String text; + int offset; + int height; + } + static int cap (TextLayout layout, int offset) { if (layout == null) return offset; return Math.min (layout.getText().length() -1, Math.max (0, offset)); @@ -452,32 +461,65 @@ void drawBullet(Bullet bullet, GC gc, int paintX, int paintY, int index, int lin layout.draw(gc, x, paintY); layout.dispose(); } -int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackground, Color widgetForeground) { - TextLayout layout = getTextLayout(lineIndex); - String line = content.getLine(lineIndex); - int lineOffset = content.getOffsetAtLine(lineIndex); - int lineLength = line.length(); + +/** + * Caches draw-related info that may be expensive to calculate twice when + * drawing first background and then foreground. + */ +private LineDrawInfo makeLineDrawInfo(int lineIndex) { + LineDrawInfo info = new LineDrawInfo(); + info.index = lineIndex; + info.layout = getTextLayout(lineIndex); + info.text = content.getLine(lineIndex); + info.offset = content.getOffsetAtLine(lineIndex); + info.height = info.layout.getBounds().height; + return info; +} + +int drawLines(int startLine, int endLine, int begX, int begY, int endY, GC gc, Color widgetBackground, Color widgetForeground) { + final boolean drawBackBeforeFore = false; + + if (drawBackBeforeFore) { + return 0; + } + + int y = begY; + for (int iLine = startLine; y < endY && iLine < endLine; iLine++) { + LineDrawInfo lineInfo = makeLineDrawInfo(iLine); + drawLineBackground(lineInfo, y, gc, widgetBackground); + drawLineForeground(lineInfo, begX, y, gc, widgetForeground); + disposeTextLayout(lineInfo.layout); + y += lineInfo.height; + } + return y - begY; +} + +private void drawLineBackground(LineDrawInfo lineInfo, int paintY, GC gc, Color widgetBackground) { Rectangle client = styledText.getClientArea(); - Color lineBackground = getLineBackground(lineIndex, null); - StyledTextEvent event = styledText.getLineBackgroundData(lineOffset, line); + Color lineBackground = getLineBackground(lineInfo.index, null); + StyledTextEvent event = styledText.getLineBackgroundData(lineInfo.offset, lineInfo.text); if (event != null && event.lineBackground != null) lineBackground = event.lineBackground; - int height = layout.getBounds().height; - int verticalIndent = layout.getVerticalIndent(); + int verticalIndent = lineInfo.layout.getVerticalIndent(); + if (lineBackground != null) { if (verticalIndent > 0) { gc.setBackground(widgetBackground); gc.fillRectangle(client.x, paintY, client.width, verticalIndent); } gc.setBackground(lineBackground); - gc.fillRectangle(client.x, paintY + verticalIndent, client.width, height - verticalIndent); + gc.fillRectangle(client.x, paintY + verticalIndent, client.width, lineInfo.height - verticalIndent); } else { gc.setBackground(widgetBackground); - styledText.drawBackground(gc, client.x, paintY, client.width, height); + styledText.drawBackground(gc, client.x, paintY, client.width, lineInfo.height); } +} + +private void drawLineForeground(LineDrawInfo lineInfo, int paintX, int paintY, GC gc, Color widgetForeground) { + int lineLength = lineInfo.text.length(); gc.setForeground(widgetForeground); - Point[] selection = intersectingRelativeNonEmptySelections(lineOffset, lineOffset + lineLength); + Point[] selection = intersectingRelativeNonEmptySelections(lineInfo.offset, lineInfo.offset + lineLength); if (styledText.getBlockSelection() || selection.length == 0) { - layout.draw(gc, paintX, paintY); + lineInfo.layout.draw(gc, paintX, paintY); } else { Color selectionFg = styledText.getSelectionForeground(); Color selectionBg = styledText.getSelectionBackground(); @@ -490,7 +532,7 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun flags |= SWT.LAST_LINE_SELECTION; } // TODO calling draw multiple times here prints line multiple times, overriding some colors - layout.draw(gc, paintX, paintY, start, end - 1, selectionFg, selectionBg, flags); + lineInfo.layout.draw(gc, paintX, paintY, start, end - 1, selectionFg, selectionBg, flags); } } @@ -499,7 +541,7 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun int bulletIndex = -1; if (bullets != null) { if (bulletsIndices != null) { - int index = lineIndex - topIndex; + int index = lineInfo.index - topIndex; if (0 <= index && index < CACHE_SIZE) { bullet = bullets[index]; bulletIndex = bulletsIndices[index]; @@ -507,40 +549,39 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun } else { for (Bullet b : bullets) { bullet = b; - bulletIndex = bullet.indexOf(lineIndex); + bulletIndex = bullet.indexOf(lineInfo.index); if (bulletIndex != -1) break; } } } if (bulletIndex != -1 && bullet != null) { - FontMetrics metrics = layout.getLineMetrics(0); + FontMetrics metrics = lineInfo.layout.getLineMetrics(0); int lineAscent = metrics.getAscent() + metrics.getLeading(); if (bullet.type == ST.BULLET_CUSTOM) { - bullet.style.start = lineOffset; + bullet.style.start = lineInfo.offset; styledText.paintObject(gc, paintX, paintY, lineAscent, metrics.getDescent(), bullet.style, bullet, bulletIndex); } else { drawBullet(bullet, gc, paintX, paintY, bulletIndex, lineAscent, metrics.getDescent()); } } - TextStyle[] styles = layout.getStyles(); + TextStyle[] styles = lineInfo.layout.getStyles(); int[] ranges = null; for (int i = 0; i < styles.length; i++) { if (styles[i].metrics != null) { - if (ranges == null) ranges = layout.getRanges(); + if (ranges == null) ranges = lineInfo.layout.getRanges(); int start = ranges[i << 1]; int length = ranges[(i << 1) + 1] - start + 1; - Point point = layout.getLocation(start, false); - FontMetrics metrics = layout.getLineMetrics(layout.getLineIndex(start)); + Point point = lineInfo.layout.getLocation(start, false); + FontMetrics metrics = lineInfo.layout.getLineMetrics(lineInfo.layout.getLineIndex(start)); StyleRange style = (StyleRange)((StyleRange)styles[i]).clone(); - style.start = start + lineOffset; + style.start = start + lineInfo.offset; style.length = length; int lineAscent = metrics.getAscent() + metrics.getLeading(); styledText.paintObject(gc, point.x + paintX, point.y + paintY, lineAscent, metrics.getDescent(), style, null, 0); } } - disposeTextLayout(layout); - return height; } + private Point[] intersectingRelativeNonEmptySelections(int fromOffset, int toOffset) { int[] selectionRanges = styledText.getSelectionRanges(); int lineLength = toOffset - fromOffset;