Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorConrad Groth2020-03-14 20:29:16 -0400
committerMickael Istria2020-03-30 15:45:20 -0400
commit2abb22fa4db3f7c87fc38290f55d0d8c4d4a4465 (patch)
tree6693bf9400d6b4c177c8edf0167bc1535b7c4785
parent235c551e987a8901900fccf6cc362cf3f0529bde (diff)
downloadeclipse.platform.swt-2abb22fa4db3f7c87fc38290f55d0d8c4d4a4465.tar.gz
eclipse.platform.swt-2abb22fa4db3f7c87fc38290f55d0d8c4d4a4465.tar.xz
eclipse.platform.swt-2abb22fa4db3f7c87fc38290f55d0d8c4d4a4465.zip
Bug 168557 - [StyledText] StyledText is very slow with long string +
word wrap Avoid the synchronous calculation of the line height in the UI thread and let the idle job do it. For scrolling and resizing, especially when huge amounts of line heights are not yet calculated, the average line height is good enough. Change-Id: I4a7a25d78597e08efc379b53ba7985adccab0eec Signed-off-by: Conrad Groth <info@conrad-groth.de>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java52
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledTextRenderer.java25
-rw-r--r--examples/org.eclipse.swt.snippets/previews/Snippet376.pngbin0 -> 120502 bytes
-rw-r--r--examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet376.java60
4 files changed, 98 insertions, 39 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 1a1f1fad94..12fd00148f 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
@@ -1587,30 +1587,30 @@ void calculateTopIndex(int delta) {
int lineCount = content.getLineCount();
while (lineIndex < lineCount) {
if (delta <= 0) break;
- delta -= renderer.getLineHeight(lineIndex++);
+ delta -= renderer.getCachedLineHeight(lineIndex++);
}
- if (lineIndex < lineCount && -delta + renderer.getLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
+ if (lineIndex < lineCount && -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
topIndex = lineIndex;
topIndexY = -delta;
} else {
topIndex = lineIndex - 1;
- topIndexY = -renderer.getLineHeight(topIndex) - delta;
+ topIndexY = -renderer.getCachedLineHeight(topIndex) - delta;
}
} else {
delta -= topIndexY;
int lineIndex = topIndex;
while (lineIndex > 0) {
- int lineHeight = renderer.getLineHeight(lineIndex - 1);
+ int lineHeight = renderer.getCachedLineHeight(lineIndex - 1);
if (delta + lineHeight > 0) break;
delta += lineHeight;
lineIndex--;
}
- if (lineIndex == 0 || -delta + renderer.getLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
+ if (lineIndex == 0 || -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
topIndex = lineIndex;
topIndexY = - delta;
} else {
topIndex = lineIndex - 1;
- topIndexY = - renderer.getLineHeight(topIndex) - delta;
+ topIndexY = - renderer.getCachedLineHeight(topIndex) - delta;
}
}
}
@@ -5397,7 +5397,7 @@ int getVerticalScrollOffset() {
renderer.calculate(0, topIndex);
int height = 0;
for (int i = 0; i < topIndex; i++) {
- height += renderer.getLineHeight(i);
+ height += renderer.getCachedLineHeight(i);
}
height -= topIndexY;
verticalScrollOffset = height;
@@ -8227,7 +8227,11 @@ boolean scrollVertical(int pixels, boolean adjustScrollBar) {
calculateTopIndex(pixels);
super.redraw();
}
- setCaretLocation();
+ Caret caret = getCaret();
+ if (caret != null) {
+ Point caretLocation = caret.getLocation();
+ setCaretLocation(new Point(caretLocation.x, caretLocation.y - pixels), getCaretDirection());
+ }
return true;
}
void scrollText(int srcY, int destY) {
@@ -8715,35 +8719,11 @@ void setCaretLocation(final Point location, int direction) {
getStyleRangeAtOffset(caretOffset) :
getStyleRangeAtOffset(content.getCharCount() - 1)) : // caret after last char: use last char style
null;
- final int caretLine = getCaretLine();
-
- int graphicalLineHeight = getLineHeight();
- final int lineStartOffset = getOffsetAtLine(caretLine);
- int graphicalLineFirstOffset = lineStartOffset;
- final int lineEndOffset = lineStartOffset + getLine(caretLine).length();
- int graphicalLineLastOffset = lineEndOffset;
- if (caretLine < getLineCount() && renderer.getLineHeight(caretLine) != getLineHeight()) { // word wrap, metrics, styles...
- graphicalLineHeight = getLineHeight(caretOffset);
- final Rectangle characterBounds = getBoundsAtOffset(caretOffset);
- graphicalLineFirstOffset = getOffsetAtPoint(new Point(leftMargin, characterBounds.y));
- graphicalLineLastOffset = getOffsetAtPoint(new Point(leftMargin, characterBounds.y + graphicalLineHeight)) - 1;
- if (graphicalLineLastOffset < graphicalLineFirstOffset) {
- graphicalLineLastOffset = getCharCount();
- }
- }
+ int graphicalLineHeight = getLineHeight(caretOffset);
int caretHeight = getLineHeight();
- boolean isTextAlignedAtBottom = true;
- if (graphicalLineFirstOffset >= 0) {
- for (StyleRange style : getStyleRanges(graphicalLineFirstOffset, graphicalLineLastOffset - graphicalLineFirstOffset)) {
- isTextAlignedAtBottom &= (
- (style.font == null || Objects.equals(style.font, getFont())) &&
- style.rise >= 0 &&
- (style.metrics == null || style.metrics.descent <= 0)
- );
- }
- }
- if (!isTextAlignedAtBottom || (styleAtOffset != null && styleAtOffset.isVariableHeight())) {
+
+ if (styleAtOffset != null && styleAtOffset.isVariableHeight()) {
if (isDefaultCaret) {
direction = SWT.DEFAULT;
caretHeight = graphicalLineHeight;
@@ -8751,7 +8731,7 @@ void setCaretLocation(final Point location, int direction) {
caretHeight = caret.getSize().y;
}
}
- if (isTextAlignedAtBottom && caretHeight < graphicalLineHeight) {
+ if (caretHeight < graphicalLineHeight) {
location.y += (graphicalLineHeight - caretHeight);
}
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 20eec0ab03..7a9d8de766 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
@@ -51,6 +51,8 @@ class StyledTextRenderer {
LineInfo[] lines;
int maxWidth;
int maxWidthLineIndex;
+ float averageLineHeight;
+ int linesInAverageLineHeight;
boolean idleRunning;
/* Bullet */
@@ -297,6 +299,7 @@ void calculate(int startLine, int lineCount) {
Rectangle rect = layout.getBounds();
line.width = rect.width + hTrim;
line.height = rect.height;
+ averageLineHeight += (line.height - Math.round(averageLineHeight)) / ++linesInAverageLineHeight;
disposeTextLayout(layout);
}
if (line.width > maxWidth) {
@@ -544,6 +547,9 @@ int drawLine(int lineIndex, int paintX, int paintY, GC gc, Color widgetBackgroun
int getBaseline() {
return ascent;
}
+int getCachedLineHeight(int lineIndex) {
+ return getLineHeight(lineIndex, false);
+}
Font getFont(int style) {
switch (style) {
case SWT.BOLD:
@@ -655,12 +661,19 @@ int getLineHeight() {
return ascent + descent;
}
int getLineHeight(int lineIndex) {
+ return getLineHeight(lineIndex, true);
+}
+int getLineHeight(int lineIndex, boolean exact) {
LineSizeInfo line = getLineSize(lineIndex);
if (line.needsRecalculateHeight()) {
- // here we are in "variable line height", the call of calculate which uses TextLayout can be very slow
- // check if line can use the default line height.
+ // here we are in "variable line height", the call of calculate which uses TextLayout is very slow
+ // so use the average line height of all calculated lines when many heights are needed e.g. for scrolling.
if (isVariableHeight(lineIndex)) {
- calculate(lineIndex, 1);
+ if (exact) {
+ calculate(lineIndex, 1);
+ } else {
+ return Math.round(averageLineHeight);
+ }
} else {
line.height = getLineHeight() + getLineSpacing(lineIndex);
}
@@ -1327,6 +1340,12 @@ void reset(Set<Integer> lines) {
getLineSize(line.intValue()).resetSize();
}
}
+ if (linesInAverageLineHeight > resetLineCount) {
+ linesInAverageLineHeight -= resetLineCount;
+ } else {
+ linesInAverageLineHeight = 0;
+ averageLineHeight = 0.0f;
+ }
if (lines.contains(Integer.valueOf(maxWidthLineIndex))) {
maxWidth = 0;
maxWidthLineIndex = -1;
diff --git a/examples/org.eclipse.swt.snippets/previews/Snippet376.png b/examples/org.eclipse.swt.snippets/previews/Snippet376.png
new file mode 100644
index 0000000000..388d213458
--- /dev/null
+++ b/examples/org.eclipse.swt.snippets/previews/Snippet376.png
Binary files differ
diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet376.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet376.java
new file mode 100644
index 0000000000..fe8447672b
--- /dev/null
+++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet376.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Conrad Groth and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Conrad Groth - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.snippets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Example snippet: Styled Text Widget with 50000 lines of text and line wrap.
+ *
+ * For a list of all SWT example snippets see
+ * http://www.eclipse.org/swt/snippets/
+ *
+ * @since 3.114
+ */
+public class Snippet376 {
+
+ private static final int LINES = 500000;
+ private static final int WORDS_PER_LINE = 10;
+ private static final String WORD = "123456789 ";
+
+ public static void main(String[] args) {
+ Display display = new Display();
+ Shell shell = new Shell(display);
+ shell.setBounds(10, 10, 300, 300);
+ shell.setLayout(new FillLayout());
+ final StyledText text = new StyledText(shell, SWT.MULTI | SWT.V_SCROLL | SWT.WRAP);
+
+ StringBuilder buffer = new StringBuilder(LINES * WORDS_PER_LINE * WORD.length() * 2);
+ for (int i = 0; i < LINES ; i++) {
+ buffer.append("Line " + i + ": ");
+ for (int j = 0; j < WORDS_PER_LINE; j++) {
+ buffer.append(WORD);
+ }
+ buffer.append("\n");
+ }
+
+ shell.open();
+ text.setText(buffer.toString());
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ }
+} \ No newline at end of file

Back to the top