Skip to content

Commit 89c2e6a

Browse files
Merge pull request #690 from Jugen/Fix_replaceText_IOOBE_when_selection_present
Fix replaceText IOOBE
2 parents 3a20f59 + 1a295df commit 89c2e6a

File tree

3 files changed

+96
-6
lines changed

3 files changed

+96
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.fxmisc.richtext.api;
2+
3+
import org.fxmisc.richtext.InlineCssTextAreaAppTest;
4+
import org.junit.Test;
5+
6+
public class ReplaceTextTests extends InlineCssTextAreaAppTest {
7+
8+
@Test
9+
public void deselect_before_replaceText_does_not_cause_index_out_of_bounds_exception()
10+
{
11+
interact( () ->
12+
{
13+
area.replaceText( "1234567890\n\nabcdefghij\n\n1234567890\n\nabcdefghij" );
14+
15+
// Select last line of text
16+
area.requestFollowCaret();
17+
area.selectLine();
18+
19+
// Calling deselect, primes an IndexOutOfBoundsException to be thrown after replaceText
20+
area.deselect();
21+
22+
// An internal IndexOutOfBoundsException may occur in ParagraphText.getRangeShapeSafely
23+
area.replaceText( "1234567890\n\nabcdefghijklmno\n\n1234567890\n\nabcde" );
24+
25+
// This would fail if an exception occurred during ParagraphText.layoutChildren:updateSelectionShape()
26+
area.selectLine();
27+
});
28+
29+
}
30+
31+
@Test
32+
public void previous_selection_before_replaceText_does_not_cause_index_out_of_bounds_exception()
33+
{
34+
interact( () ->
35+
{
36+
// For this test to work the area MUST be at the end of the document
37+
area.requestFollowCaret();
38+
39+
// First text supplied by bug reporter: has 9 paragraphs, 344 characters
40+
area.replaceText( getTextA() );
41+
42+
// Any text can be selected anywhere in the document, this primed the exception
43+
area.selectWord();
44+
45+
// Second text supplied by bug reporter: has 9 paragraphs, 344 characters, and contains two Ä characters
46+
area.replaceText( getTextB() );
47+
48+
// An internal IndexOutOfBoundsException may occur in ParagraphText.getRangeShapeSafely
49+
area.replaceText( getTextA() );
50+
51+
// This would fail if an exception occurred during ParagraphText.layoutChildren:updateSelectionShape()
52+
area.selectLine();
53+
});
54+
}
55+
56+
57+
// Reduced text supplied by bug reporter: has 9 paragraphs, 344 characters
58+
private String getTextA()
59+
{
60+
return "<!DOCTYPE HTML>\n" +
61+
"\n" +
62+
" Parempaa kuvaa ja &auml;&auml;nentoistoa jo vuodesta 1981 - HifiStudio</title>\n" +
63+
"\n" +
64+
"<meta property=\"og:title\" content=\"HifiStudio - Parempaa kuvaa ja &auml;&auml;nentoistoa jo vuodesta 1981\" />\n" +
65+
"\n" +
66+
"<meta property=\"og:url\" content=\"https://www.hifistudio.fi/fi/\" />\n" +
67+
"\n" +
68+
" <li><a href=\"/fi/tuotteet/muut-hifil";
69+
}
70+
71+
72+
// Reduced text supplied by bug reporter: has 9 paragraphs, 344 characters, and contains two Ä characters
73+
private String getTextB()
74+
{
75+
return "<!DOCTYPE HTML>\n" +
76+
"\n" +
77+
" SEINÄTELINEET - HifiStudio</title>\n" +
78+
"\n" +
79+
"<meta property=\"og:title\" content=\"HifiStudio - SEINÄTELINEET\" />\n" +
80+
"\n" +
81+
"<meta property=\"og:url\" content=\"https://www.hifistudio.fi/fi/tuotteet/laitetelineet/seinatelineet/91052\" />\n" +
82+
"\n" +
83+
" <li><a href=\"/fi/tuotteet/muut-hifilaitteet/cd-soittimet/15035\" class=\"top-product";
84+
}
85+
}

richtextfx/src/main/java/org/fxmisc/richtext/ParagraphText.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,14 @@ private PathElement[] getRangeShapeSafely(int start, int end) {
366366
// We only need to adjust the top right and bottom right corners to extend to the
367367
// width/height of the line, simulating a full line selection.
368368
int length = shape.length;
369-
int bottomRightIndex = length - 3;
370-
int topRightIndex = bottomRightIndex - 1;
371-
LineTo lineToTopRight = (LineTo) shape[topRightIndex];
372-
shape[topRightIndex] = new LineTo(getWidth(), lineToTopRight.getY());
373-
shape[bottomRightIndex] = new LineTo(getWidth(), getHeight());
369+
if ( length > 3 ) // Prevent IndexOutOfBoundsException accessing shape[] issue #689
370+
{
371+
int bottomRightIndex = length - 3;
372+
int topRightIndex = bottomRightIndex - 1;
373+
LineTo lineToTopRight = (LineTo) shape[topRightIndex];
374+
shape[topRightIndex] = new LineTo(getWidth(), lineToTopRight.getY());
375+
shape[bottomRightIndex] = new LineTo(getWidth(), getHeight());
376+
}
374377
}
375378
}
376379

richtextfx/src/main/java/org/fxmisc/richtext/SelectionImpl.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ public SelectionImpl(String name, GenericStyledArea<PS, SEG, S> area, int startP
219219

220220
manageSubscription(area.plainTextChanges(), plainTextChange -> {
221221
int netLength = plainTextChange.getNetLength();
222-
if (netLength != 0) {
222+
//if (netLength != 0) Causes IndexOutOfBoundsException in ParagraphText.getRangeShapeSafely issue #689
223+
// but can be safely reimplemented if this causes other issues.
224+
{
223225
int indexOfChange = plainTextChange.getPosition();
224226
// in case of a replacement: "hello there" -> "hi."
225227
int endOfChange = indexOfChange + Math.abs(netLength);

0 commit comments

Comments
 (0)