Skip to content

Commit 4b1f261

Browse files
Fix replaceTextRange logic for unfocused StyledText with variable line
height - Updated productive code to prevent IllegalArgumentException when replacing text in a StyledText control with variable line height and no focus, by adding boundary checks. - Added a regression test to validate the fix: ensures no exception is thrown when replacing the full text range under these conditions. Fixes: #2302
1 parent 95b46b6 commit 4b1f261

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,31 +1077,50 @@ void calculateTopIndex(int delta) {
10771077
}
10781078
}
10791079
} else {
1080+
int lineCount = content.getLineCount();
10801081
if (delta >= 0) {
10811082
delta -= topIndexY;
10821083
int lineIndex = topIndex;
1083-
int lineCount = content.getLineCount();
10841084
while (lineIndex < lineCount) {
10851085
if (delta <= 0) break;
1086-
delta -= renderer.getCachedLineHeight(lineIndex++);
1086+
if (lineIndex >= 0 && lineIndex < lineCount) {
1087+
delta -= renderer.getCachedLineHeight(lineIndex);
1088+
}
1089+
lineIndex++;
10871090
}
1088-
if (lineIndex < lineCount && -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
1091+
int lineHeight = 0;
1092+
if (lineIndex >= 0 && lineIndex < lineCount) {
1093+
lineHeight = renderer.getCachedLineHeight(lineIndex);
1094+
}
1095+
if (lineIndex < lineCount && -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) {
10891096
topIndex = lineIndex;
10901097
topIndexY = -delta;
10911098
} else {
10921099
topIndex = lineIndex - 1;
1093-
topIndexY = -renderer.getCachedLineHeight(topIndex) - delta;
1100+
int topIndexHeight = 0;
1101+
if (topIndex >= 0 && topIndex < lineCount) {
1102+
topIndexHeight = renderer.getCachedLineHeight(topIndex);
1103+
}
1104+
topIndexY = -topIndexHeight - delta;
10941105
}
10951106
} else {
10961107
delta -= topIndexY;
10971108
int lineIndex = topIndex;
10981109
while (lineIndex > 0) {
1099-
int lineHeight = renderer.getCachedLineHeight(lineIndex - 1);
1110+
int previousLineIndex = lineIndex - 1;
1111+
int lineHeight = 0;
1112+
if (previousLineIndex >= 0 && previousLineIndex < lineCount) {
1113+
lineHeight = renderer.getCachedLineHeight(previousLineIndex);
1114+
}
11001115
if (delta + lineHeight > 0) break;
11011116
delta += lineHeight;
11021117
lineIndex--;
11031118
}
1104-
if (lineIndex == 0 || -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
1119+
int lineHeight = 0;
1120+
if (lineIndex >= 0 && lineIndex < lineCount) {
1121+
lineHeight = renderer.getCachedLineHeight(lineIndex);
1122+
}
1123+
if (lineIndex == 0 || -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) {
11051124
topIndex = lineIndex;
11061125
topIndexY = - delta;
11071126
} else {
@@ -1378,11 +1397,18 @@ int getAvailableHeightAbove(int height) {
13781397
if (maxHeight == -1) {
13791398
int lineIndex = topIndex - 1;
13801399
maxHeight = -topIndexY;
1400+
int lineCount = content.getLineCount();
13811401
if (topIndexY > 0) {
1382-
maxHeight += renderer.getLineHeight(lineIndex--);
1402+
if (lineIndex >= 0 && lineIndex < lineCount) {
1403+
maxHeight += renderer.getLineHeight(lineIndex);
1404+
}
1405+
lineIndex--;
13831406
}
13841407
while (height > maxHeight && lineIndex >= 0) {
1385-
maxHeight += renderer.getLineHeight(lineIndex--);
1408+
if (lineIndex >= 0 && lineIndex < lineCount) {
1409+
maxHeight += renderer.getLineHeight(lineIndex);
1410+
}
1411+
lineIndex--;
13861412
}
13871413
}
13881414
return Math.min(height, maxHeight);
@@ -3877,10 +3903,16 @@ public int getLinePixel(int lineIndex) {
38773903
int height = topIndexY;
38783904
if (lineIndex > topIndex) {
38793905
for (int i = topIndex; i < lineIndex; i++) {
3906+
if (i < 0 || i >= lineCount) {
3907+
continue;
3908+
}
38803909
height += renderer.getLineHeight(i);
38813910
}
38823911
} else {
38833912
for (int i = topIndex - 1; i >= lineIndex; i--) {
3913+
if (i < 0 || i >= lineCount) {
3914+
continue;
3915+
}
38843916
height -= renderer.getLineHeight(i);
38853917
}
38863918
}
@@ -3914,10 +3946,18 @@ public int getLineIndex(int y) {
39143946
}
39153947
} else {
39163948
int lineCount = content.getLineCount();
3917-
int lineHeight = renderer.getLineHeight(line);
3949+
int lineHeight = 0;
3950+
if (line>=0 && line<lineCount) {
3951+
lineHeight = renderer.getLineHeight(line);
3952+
}
39183953
while (y - lineHeight >= topIndexY && line < lineCount - 1) {
39193954
y -= lineHeight;
3920-
lineHeight = renderer.getLineHeight(++line);
3955+
++line;
3956+
if (line >= 0 && line < lineCount) {
3957+
lineHeight = renderer.getLineHeight(line);
3958+
}else {
3959+
lineHeight = 0;
3960+
}
39213961
}
39223962
}
39233963
return line;

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_custom_StyledText.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,15 @@
7070
import org.eclipse.swt.graphics.RGB;
7171
import org.eclipse.swt.graphics.Rectangle;
7272
import org.eclipse.swt.internal.BidiUtil;
73+
import org.eclipse.swt.layout.FillLayout;
7374
import org.eclipse.swt.layout.GridData;
7475
import org.eclipse.swt.layout.GridLayout;
7576
import org.eclipse.swt.printing.Printer;
7677
import org.eclipse.swt.widgets.Caret;
7778
import org.eclipse.swt.widgets.Display;
7879
import org.eclipse.swt.widgets.Event;
7980
import org.eclipse.swt.widgets.ScrollBar;
81+
import org.eclipse.swt.widgets.Text;
8082
import org.eclipse.swt.widgets.Widget;
8183
import org.junit.Assume;
8284
import org.junit.Before;
@@ -195,6 +197,35 @@ public void test_getTextBounds() {
195197
}
196198
}
197199

200+
@Test
201+
public void test_replaceTextRangeWithVariableHeight() {
202+
shell.setLayout(new FillLayout());
203+
StyledText styledText = new StyledText(shell, SWT.BORDER | SWT.V_SCROLL);
204+
Text text = new Text(shell, SWT.BORDER);
205+
try {
206+
String lines = IntStream.range(0, 10)
207+
.collect(StringBuilder::new, (s, i) -> s.append("line " + (i + 1) + "\n"), StringBuilder::append).toString();
208+
styledText.setText(lines);
209+
StyleRange style = new StyleRange();
210+
style.start = 0;
211+
style.length = lines.length();
212+
style.font = styledText.getFont(); // To make the line-height non-fixed
213+
styledText.setStyleRange(style);
214+
215+
shell.setSize(100, 3 * styledText.getLineHeight());
216+
shell.open();
217+
218+
text.setFocus();
219+
styledText.setTopIndex(styledText.getLineCount() - 1);
220+
assertFalse(styledText.isFocusControl());
221+
// ensure no IllegalArgumentException is thrown when styledText control has not the focus and the text is replaced
222+
styledText.replaceTextRange(0, styledText.getCharCount(), "");
223+
}finally {
224+
styledText.dispose();
225+
text.dispose();
226+
}
227+
}
228+
198229
@Test
199230
public void test_addExtendedModifyListenerLorg_eclipse_swt_custom_ExtendedModifyListener() {
200231
final String line = "Line1";

0 commit comments

Comments
 (0)