From e8fadb6c6f769d86f72c7ef2c3624ff4ce14f54c Mon Sep 17 00:00:00 2001 From: Symeon94 Date: Mon, 5 Jan 2026 09:28:52 +0100 Subject: [PATCH 1/4] Extracting code for UT --- .../fxmisc/richtext/GenericStyledArea.java | 18 +------- .../org/fxmisc/richtext/ScreenBounds.java | 36 +++++++++++++++ .../fxmisc/richtext/BoundsEvaluatorTest.java | 45 +++++++++++++++++++ 3 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java create mode 100644 richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java b/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java index 61453458..658136a1 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java @@ -2091,23 +2091,7 @@ private Bounds getParagraphBoundsOnScreen(Cell, ParagraphB Bounds nodeScreen = cell.getNode().localToScreen(nodeLocal); Bounds areaLocal = getBoundsInLocal(); Bounds areaScreen = localToScreen(areaLocal); - - // use area's minX if scrolled right and paragraph's left is not visible - double minX = nodeScreen.getMinX() < areaScreen.getMinX() - ? areaScreen.getMinX() - : nodeScreen.getMinX(); - // use area's minY if scrolled down vertically and paragraph's top is not visible - double minY = nodeScreen.getMinY() < areaScreen.getMinY() - ? areaScreen.getMinY() - : nodeScreen.getMinY(); - // use area's width whether paragraph spans outside of it or not - // so that short or long paragraph takes up the entire space - double width = areaScreen.getWidth(); - // use area's maxY if scrolled up vertically and paragraph's bottom is not visible - double maxY = nodeScreen.getMaxY() < areaScreen.getMaxY() - ? nodeScreen.getMaxY() - : areaScreen.getMaxY(); - return new BoundingBox(minX, minY, width, maxY - minY); + return new ScreenBounds(areaScreen).getParagraphBoundsFrom(nodeScreen); } private Optional getRangeBoundsOnScreen(int paragraphIndex, int from, int to) { diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java b/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java new file mode 100644 index 00000000..fd0625bc --- /dev/null +++ b/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java @@ -0,0 +1,36 @@ +package org.fxmisc.richtext; + +import javafx.geometry.BoundingBox; +import javafx.geometry.Bounds; + +public class ScreenBounds { + private final Bounds areaScreen; + + public ScreenBounds(Bounds areaScreen) { + this.areaScreen = areaScreen; + } + + /** + * Evaluate the paragraph node bounds in the area. + * @param nodeScreen the paragraph bound position on screen + * @return the bounds inside the area of the provided paragraph bounds. + */ + public Bounds getParagraphBoundsFrom(Bounds nodeScreen) { + // use area's minX if scrolled right and paragraph's left is not visible + double minX = nodeScreen.getMinX() < areaScreen.getMinX() + ? areaScreen.getMinX() + : nodeScreen.getMinX(); + // use area's minY if scrolled down vertically and paragraph's top is not visible + double minY = nodeScreen.getMinY() < areaScreen.getMinY() + ? areaScreen.getMinY() + : nodeScreen.getMinY(); + // use area's width whether paragraph spans outside of it or not + // so that short or long paragraph takes up the entire space + double width = areaScreen.getWidth(); + // use area's maxY if scrolled up vertically and paragraph's bottom is not visible + double maxY = nodeScreen.getMaxY() < areaScreen.getMaxY() + ? nodeScreen.getMaxY() + : areaScreen.getMaxY(); + return new BoundingBox(minX, minY, width, maxY - minY); + } +} diff --git a/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java b/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java new file mode 100644 index 00000000..c48956ed --- /dev/null +++ b/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java @@ -0,0 +1,45 @@ +package org.fxmisc.richtext; + +import javafx.geometry.BoundingBox; +import javafx.geometry.Bounds; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class BoundsEvaluatorTest { + private void checkBounds(Bounds bounds, double xMin, double yMin, double xMax, double yMax) { + assertEquals(xMin, bounds.getMinX(), "Invalid min X value"); + assertEquals(yMin, bounds.getMinY(), "Invalid min Y value"); + assertEquals(xMax, bounds.getMaxX(), "Invalid max X value"); + assertEquals(yMax, bounds.getMaxY(), "Invalid max Y value"); + } + + @Test + @DisplayName("Test") + void test() { + ScreenBounds boundsEvaluator = new ScreenBounds(new BoundingBox(20, 20, 100, 100)); + // Start < Screen ; End < Screen + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(10, 10, 50, 50)), + 20, 20, 120, 60); + // Start < Screen ; End > Screen + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(10, 10, 111, 111)), + 20, 20, 120, 120); + // Start > Screen ; End > Screen + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(21, 21, 100, 100)), + 21, 21, 121, 120); + // Start > Screen ; End < Screen + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(21, 21, 98, 98)), + 21, 21, 121, 119); + // Start = Screen ; End = Screen + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(20, 20, 100, 100)), + 20, 20, 120, 120); + // Miscellaneous + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(0, 0, 80, 80)), + 20, 20, 120, 80); + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(30, 30, 120, 120)), + 30, 30, 130, 120); + checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(110, 110, 130, 130)), + 110, 110, 210, 120); + } +} From 23c1bafd1416ecd2a8841749b741ab344c295368 Mon Sep 17 00:00:00 2001 From: Symeon94 Date: Mon, 5 Jan 2026 09:32:54 +0100 Subject: [PATCH 2/4] Rename test method --- .../test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java b/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java index c48956ed..91ba101c 100644 --- a/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java +++ b/richtextfx/src/test/java/org/fxmisc/richtext/BoundsEvaluatorTest.java @@ -16,8 +16,8 @@ private void checkBounds(Bounds bounds, double xMin, double yMin, double xMax, d } @Test - @DisplayName("Test") - void test() { + @DisplayName("Evaluate paragraph bounds on screen") + void evaluateParagraphBoundsOnScreen() { ScreenBounds boundsEvaluator = new ScreenBounds(new BoundingBox(20, 20, 100, 100)); // Start < Screen ; End < Screen checkBounds(boundsEvaluator.getParagraphBoundsFrom(new BoundingBox(10, 10, 50, 50)), From 1a08462f46bf0aa93db22d00aabdff0166762e63 Mon Sep 17 00:00:00 2001 From: Symeon94 Date: Mon, 5 Jan 2026 09:34:26 +0100 Subject: [PATCH 3/4] Refactor --- .../org/fxmisc/richtext/ScreenBounds.java | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java b/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java index fd0625bc..113dafe5 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java @@ -4,33 +4,26 @@ import javafx.geometry.Bounds; public class ScreenBounds { - private final Bounds areaScreen; + private final Bounds screen; - public ScreenBounds(Bounds areaScreen) { - this.areaScreen = areaScreen; + public ScreenBounds(Bounds screen) { + this.screen = screen; } /** * Evaluate the paragraph node bounds in the area. - * @param nodeScreen the paragraph bound position on screen + * @param paragraph the paragraph bound position on screen * @return the bounds inside the area of the provided paragraph bounds. */ - public Bounds getParagraphBoundsFrom(Bounds nodeScreen) { - // use area's minX if scrolled right and paragraph's left is not visible - double minX = nodeScreen.getMinX() < areaScreen.getMinX() - ? areaScreen.getMinX() - : nodeScreen.getMinX(); - // use area's minY if scrolled down vertically and paragraph's top is not visible - double minY = nodeScreen.getMinY() < areaScreen.getMinY() - ? areaScreen.getMinY() - : nodeScreen.getMinY(); + public Bounds getParagraphBoundsFrom(Bounds paragraph) { + // use area's minX,minY if scrolled right/down and paragraph's left/top is not visible + double minX = Math.max(paragraph.getMinX(), screen.getMinX()); + double minY = Math.max(paragraph.getMinY(), screen.getMinY()); // use area's width whether paragraph spans outside of it or not // so that short or long paragraph takes up the entire space - double width = areaScreen.getWidth(); + double width = screen.getWidth(); // use area's maxY if scrolled up vertically and paragraph's bottom is not visible - double maxY = nodeScreen.getMaxY() < areaScreen.getMaxY() - ? nodeScreen.getMaxY() - : areaScreen.getMaxY(); + double maxY = Math.min(paragraph.getMaxY(), screen.getMaxY()); return new BoundingBox(minX, minY, width, maxY - minY); } } From c733f211cca9a579310389df06b71659cff13d80 Mon Sep 17 00:00:00 2001 From: Symeon94 Date: Mon, 5 Jan 2026 09:34:53 +0100 Subject: [PATCH 4/4] ScreenBounds is not public --- richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java b/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java index 113dafe5..ab745f46 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/ScreenBounds.java @@ -3,7 +3,7 @@ import javafx.geometry.BoundingBox; import javafx.geometry.Bounds; -public class ScreenBounds { +class ScreenBounds { private final Bounds screen; public ScreenBounds(Bounds screen) {