Skip to content

Commit c0dbf00

Browse files
tobias-melchermickaelistria
authored andcommitted
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 a7ee6ba commit c0dbf00

File tree

2 files changed

+82
-15
lines changed

2 files changed

+82
-15
lines changed

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

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,31 +1077,47 @@ void calculateTopIndex(int delta) {
10771077
}
10781078
}
10791079
} else {
1080+
int lineCount = content.getLineCount();
10801081
if (delta >= 0) {
10811082
delta -= topIndexY;
1082-
int lineIndex = topIndex;
1083-
int lineCount = content.getLineCount();
1083+
int lineIndex = Math.max(0, topIndex);
10841084
while (lineIndex < lineCount) {
10851085
if (delta <= 0) break;
1086-
delta -= renderer.getCachedLineHeight(lineIndex++);
1086+
delta -= renderer.getCachedLineHeight(lineIndex);
1087+
lineIndex++;
1088+
}
1089+
int lineHeight = 0;
1090+
if (lineExists(lineIndex)) {
1091+
lineHeight = renderer.getCachedLineHeight(lineIndex);
10871092
}
1088-
if (lineIndex < lineCount && -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
1093+
if (lineIndex < lineCount && -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) {
10891094
topIndex = lineIndex;
10901095
topIndexY = -delta;
10911096
} else {
10921097
topIndex = lineIndex - 1;
1093-
topIndexY = -renderer.getCachedLineHeight(topIndex) - delta;
1098+
if (lineExists(topIndex)) {
1099+
topIndexY = -renderer.getCachedLineHeight(topIndex);
1100+
}
1101+
topIndexY -= delta;
10941102
}
10951103
} else {
10961104
delta -= topIndexY;
10971105
int lineIndex = topIndex;
10981106
while (lineIndex > 0) {
1099-
int lineHeight = renderer.getCachedLineHeight(lineIndex - 1);
1107+
int previousLineIndex = lineIndex - 1;
1108+
int lineHeight = 0;
1109+
if (lineExists(previousLineIndex)) {
1110+
lineHeight = renderer.getCachedLineHeight(previousLineIndex);
1111+
}
11001112
if (delta + lineHeight > 0) break;
11011113
delta += lineHeight;
11021114
lineIndex--;
11031115
}
1104-
if (lineIndex == 0 || -delta + renderer.getCachedLineHeight(lineIndex) <= clientAreaHeight - topMargin - bottomMargin) {
1116+
int lineHeight = 0;
1117+
if (lineExists(lineIndex)) {
1118+
lineHeight = renderer.getCachedLineHeight(lineIndex);
1119+
}
1120+
if (lineIndex == 0 || -delta + lineHeight <= clientAreaHeight - topMargin - bottomMargin) {
11051121
topIndex = lineIndex;
11061122
topIndexY = - delta;
11071123
} else {
@@ -1379,14 +1395,24 @@ int getAvailableHeightAbove(int height) {
13791395
int lineIndex = topIndex - 1;
13801396
maxHeight = -topIndexY;
13811397
if (topIndexY > 0) {
1382-
maxHeight += renderer.getLineHeight(lineIndex--);
1398+
if (lineExists(lineIndex)) {
1399+
maxHeight += renderer.getLineHeight(lineIndex);
1400+
}
1401+
lineIndex--;
13831402
}
13841403
while (height > maxHeight && lineIndex >= 0) {
1385-
maxHeight += renderer.getLineHeight(lineIndex--);
1404+
if (lineExists(lineIndex)) {
1405+
maxHeight += renderer.getLineHeight(lineIndex);
1406+
}
1407+
lineIndex--;
13861408
}
13871409
}
13881410
return Math.min(height, maxHeight);
13891411
}
1412+
private boolean lineExists(int lineNumber) {
1413+
int lineCount = content.getLineCount();
1414+
return lineNumber >= 0 && lineNumber < lineCount;
1415+
}
13901416
int getAvailableHeightBellow(int height) {
13911417
int partialBottomIndex = getPartialBottomIndex();
13921418
int topY = getLinePixel(partialBottomIndex);
@@ -3876,11 +3902,13 @@ public int getLinePixel(int lineIndex) {
38763902
return topIndexY + topMargin;
38773903
int height = topIndexY;
38783904
if (lineIndex > topIndex) {
3879-
for (int i = topIndex; i < lineIndex; i++) {
3905+
for (int i = Math.max(topIndex, 0); i < Math.min(lineIndex, lineCount); i++) {
38803906
height += renderer.getLineHeight(i);
38813907
}
38823908
} else {
3883-
for (int i = topIndex - 1; i >= lineIndex; i--) {
3909+
int lastLineToConsider = Math.min(topIndex - 1, lineCount - 1);
3910+
int firstLineToConsider = Math.max(0, lineIndex);
3911+
for (int i = firstLineToConsider; i <= lastLineToConsider; i++) {
38843912
height -= renderer.getLineHeight(i);
38853913
}
38863914
}
@@ -3914,10 +3942,18 @@ public int getLineIndex(int y) {
39143942
}
39153943
} else {
39163944
int lineCount = content.getLineCount();
3917-
int lineHeight = renderer.getLineHeight(line);
3945+
int lineHeight = 0;
3946+
if (lineExists(line)) {
3947+
lineHeight = renderer.getLineHeight(line);
3948+
}
39183949
while (y - lineHeight >= topIndexY && line < lineCount - 1) {
39193950
y -= lineHeight;
3920-
lineHeight = renderer.getLineHeight(++line);
3951+
++line;
3952+
if (lineExists(line)) {
3953+
lineHeight = renderer.getLineHeight(line);
3954+
}else {
3955+
lineHeight = 0;
3956+
}
39213957
}
39223958
}
39233959
return line;
@@ -7818,7 +7854,7 @@ void resetCache(SortedSet<Integer> lines) {
78187854
int maxLineIndex = renderer.maxWidthLineIndex;
78197855
renderer.reset(lines);
78207856
renderer.calculateClientArea();
7821-
if (0 <= maxLineIndex && maxLineIndex < content.getLineCount()) {
7857+
if (lineExists(maxLineIndex)) {
78227858
renderer.calculate(maxLineIndex, 1);
78237859
}
78247860
setScrollBars(true);
@@ -7833,7 +7869,7 @@ void resetCache(int firstLine, int count) {
78337869
int maxLineIndex = renderer.maxWidthLineIndex;
78347870
renderer.reset(firstLine, count);
78357871
renderer.calculateClientArea();
7836-
if (0 <= maxLineIndex && maxLineIndex < content.getLineCount()) {
7872+
if (lineExists(maxLineIndex)) {
78377873
renderer.calculate(maxLineIndex, 1);
78387874
}
78397875
setScrollBars(true);

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)