Skip to content

Commit

Permalink
Fixed memory leak in ParagraphText (#886)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jugen authored Dec 29, 2019
1 parent 571a0ca commit a227e06
Showing 1 changed file with 32 additions and 17 deletions.
49 changes: 32 additions & 17 deletions richtextfx/src/main/java/org/fxmisc/richtext/ParagraphText.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import org.fxmisc.richtext.model.Paragraph;
import org.fxmisc.richtext.model.StyledSegment;
Expand Down Expand Up @@ -70,7 +71,8 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
return highlightTextFill;
}

private final Paragraph<PS, SEG, S> paragraph;
private Paragraph<PS, SEG, S> paragraph;
private Function<StyledSegment<SEG, S>, Node> nodeMaker;

private final CustomCssShapeHelper<Paint> backgroundShapeHelper;
private final CustomCssShapeHelper<BorderAttributes> borderShapeHelper;
Expand All @@ -88,7 +90,6 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
private int selectionShapeStartIndex = 0;

ParagraphText(Paragraph<PS, SEG, S> par, Function<StyledSegment<SEG, S>, Node> nodeFactory) {
this.paragraph = par;

getStyleClass().add("paragraph-text");

Expand Down Expand Up @@ -149,17 +150,6 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
// }
// });

// populate with text nodes
par.getStyledSegments().stream().map(nodeFactory).forEach(n -> {
if (n instanceof TextExt) {
TextExt t = (TextExt) n;
// XXX: binding selectionFill to textFill,
// see the note at highlightTextFill
JavaFXCompatibility.Text_selectionFillProperty(t).bind(t.fillProperty());
}
getChildren().add(n);
});

// set up custom css shape helpers
UnaryOperator<Path> configurePath = shape -> {
shape.setManaged(false);
Expand Down Expand Up @@ -218,20 +208,45 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
addToForeground,
clearUnusedShapes
);

// populate with text nodes
nodeMaker = nodeFactory;
setParagraph( par );
}

void dispose() {
// this removes listeners (in selections and carets listeners) and avoids memory leaks
selections.removeListener( selectionPathListener );
carets.removeListener( caretNodeListener );
selections.clear();
carets.clear();
selections.clear();
// this removes listeners (in selections and carets listeners) and avoids memory leaks
selections.removeListener( selectionPathListener );
carets.removeListener( caretNodeListener );
setParagraph( null );
}

public Paragraph<PS, SEG, S> getParagraph() {
return paragraph;
}

public void setParagraph(Paragraph<PS, SEG, S> par) {
getChildren().stream().filter( n -> n instanceof TextExt ).map( n -> (TextExt) n )
.forEach( t -> JavaFXCompatibility.Text_selectionFillProperty(t).unbind() );

getChildren().setAll( selections.values() );

if ( par != null ) getChildren().addAll( par.getStyledSegments().stream().map(nodeMaker)
.peek( n -> {
if (n instanceof TextExt) {
TextExt t = (TextExt) n;
// XXX: binding selectionFill to textFill,
// see the note at highlightTextFill
JavaFXCompatibility.Text_selectionFillProperty(t).bind(t.fillProperty());
}
}).collect( Collectors.toList() ) );

getChildren().addAll( carets );
paragraph = par;
}

public <T extends Node & Caret> double getCaretOffsetX(T caret) {
layout(); // ensure layout, is a no-op if not dirty
checkWithinParagraph(caret);
Expand Down

0 comments on commit a227e06

Please sign in to comment.