On Thu, 16 Jan 2025 19:34:06 GMT, Andy Goryachev <ango...@openjdk.org> wrote:

>> Please refer to
>> 
>> https://github.com/andy-goryachev-oracle/Test/blob/main/doc/Text/LayoutInfo.md
>> 
>> The RichTextArea control 
>> ([JDK-8301121](https://bugs.openjdk.org/browse/JDK-8301121)), or any custom 
>> control that needs non-trivial navigation within complex or wrapped text 
>> needs a public API to get information about text layout.
>> 
>> This change fixes the missing functionality by adding a new public method to 
>> the `Text` and `TextFlow` classes.:
>> 
>> 
>>     /**
>>      * Obtains the snapshot of the current text layout information.
>>      * @return the layout information
>>      * @since 25
>>      */
>>     public final LayoutInfo getLayoutInfo()
>> 
>> 
>> The `LayoutInfo` provides a view into the text layout within 
>> `Text`/`TextFlow` nodes such as:
>> 
>> - caret information
>> - text lines: offsets and bounds
>> - overall layout bounds
>> - text selection geometry
>> - strike-through geometry
>> - underline geometry
>> 
>> 
>> This PR also adds the missing `strikeThroughShape()` method to complement 
>> the existing `underlineShape()` and `rangeShape()` for consistency sake:
>> 
>> 
>>     /**
>>      * Returns the shape for the strike-through in local coordinates.
>>      *
>>      * @param start the beginning character index for the range
>>      * @param end the end character index (non-inclusive) for the range
>>      * @return an array of {@code PathElement} which can be used to create a 
>> {@code Shape}
>>      * @since 25
>>      */
>>     public final PathElement[] strikeThroughShape(int start, int end)
>> 
>> 
>> 
>> 
>> ## WARNING
>> 
>> Presently, information obtained via certain Text/TextField methods is 
>> incorrect with non-zero padding and borders, see 
>> [JDK-8341438](https://bugs.openjdk.org/browse/JDK-8341438).
>> 
>> This PR provides correct answers in the new API, leaving the behavior of the 
>> existing methods unchanged (there is a compatibility risk associated with 
>> trying to fix [JDK-8341438](https://bugs.openjdk.org/browse/JDK-8341438) ).
>> 
>> 
>> 
>> ## Testing
>> 
>> The new APIs can be visually tested using the Monkey Tester on this branch:
>> https://github.com/andy-goryachev-oracle/MonkeyTest/tree/text.layout.api
>> 
>> in the Text and TextFlow pages:
>> ![Screenshot 2024-11-04 at 11 38 
>> 21](https://github.com/user-attachments/assets/2e17e55c-f819-4742-8a42-b9af2b6bac72)
>> 
>> Two very basic headful tests have been added.
>> 
>> 
>> ## See Also
>> 
>> https://github.com/FXMisc/RichTextFX/pull/1246
>
> Andy Goryachev has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   25 25

Overall it looks really good, the new API is quite useful in some scenarios. 
I've done some successful tests and left some comments and questions about the 
API.

modules/javafx.graphics/src/main/java/com/sun/javafx/scene/text/TextLayout.java 
line 83:

> 81:     @FunctionalInterface
> 82:     public static interface GeometryCallback {
> 83:         public void addRectangle(float left, float top, float right, 
> float bottom);

I understand that you use `float` here because all the calculations in 
`PrismTextLayout::getRange` use floats (from `TextRun`).
 
However, the calculations down the line to generate the `Rectangle2D` mix 
floats and doubles without any casting (`TextUtils::getRange` with implicit 
casts from double to float, `PrismLayoutInfo::getGeometry` with float and 
double sums).

Do you think we could use doubles here instead?

modules/javafx.graphics/src/main/java/com/sun/javafx/scene/text/TextLayout.java 
line 256:

> 254:      * @return the caret geometry
> 255:      */
> 256:     public float[] getCaretInf(int offset, boolean leading);

Is this a typo or is there a reason for naming this method `getCaretInf` 
instead of `getCaretInfo`?

modules/javafx.graphics/src/main/java/com/sun/javafx/scene/text/TextLayout.java 
line 268:

> 266:      * @param start the start offset
> 267:      * @param end the end offset
> 268:      * @param the type of the geometry

missing `type`after `@param`

modules/javafx.graphics/src/main/java/com/sun/javafx/text/PrismCaretInfo.java 
line 48:

> 46:     @Override
> 47:     public Rectangle2D getSegmentAt(int index) {
> 48:         return parts[index];

do we need a bound check here?

modules/javafx.graphics/src/main/java/com/sun/javafx/text/PrismLayoutInfo.java 
line 57:

> 55:     public Rectangle2D getBounds(boolean includeLineSpacing) {
> 56:         BaseBounds b = layout.getBounds();
> 57:         Insets m = insets();

See my comments below about adding the insets to the layout information. Maybe 
we could also add another boolean `includeInsets` for this?

modules/javafx.graphics/src/main/java/com/sun/javafx/text/PrismLayoutInfo.java 
line 127:

> 125: 
> 126:     private TextLine line(int ix) {
> 127:         return layout.getLines()[ix];

bound check? In any case, this private method is not used.

modules/javafx.graphics/src/main/java/com/sun/javafx/text/TextUtils.java line 
45:

> 43:     /**
> 44:      * Queries the range geometry of the range of text within the text 
> layout as
> 45:      * an array of {@code PathElement}s, for for one of the three 
> possible types:

typo `for for`

modules/javafx.graphics/src/main/java/com/sun/javafx/text/TextUtils.java line 
49:

> 47:      * <li>{@link #TYPE_STRIKETHROUGH} - strike-through shape
> 48:      * <li>{@link #TYPE_TEXT} - text selection shape
> 49:      * <li>{@link #TYPE_UNDERLINE} - underline shape

missing `TextLayout` before each type `#TYPE_...`

modules/javafx.graphics/src/main/java/javafx/scene/text/LayoutInfo.java line 91:

> 89:      * @return the immutable list of {@code Rectangle2D} objects
> 90:      */
> 91:     public abstract List<Rectangle2D> selectionShape(int start, int end, 
> boolean includeLineSpacing);

See my comment below about using `javafx.scene.shape.Rectangle` instead of 
`javafx.geometry.Rectangle2D`: otherwise the API is misleading: 
`selectionShape` doesn't return a `Shape` subclass.

modules/javafx.graphics/src/main/java/javafx/scene/text/LayoutInfo.java line 91:

> 89:      * @return the immutable list of {@code Rectangle2D} objects
> 90:      */
> 91:     public abstract List<Rectangle2D> selectionShape(int start, int end, 
> boolean includeLineSpacing);

I take that  `LayoutInfo::selectionShape` should match the existing API 
`TextFlow::rangeShape` for the same selection coordinates.
 
I wonder if you have tested this, with different insets. I take that with your 
current implementation, for `Rectangle2D` objects, it makes sense to have the 
insets of the TextFlow/Text node, but shapes don't include them.

modules/javafx.graphics/src/main/java/javafx/scene/text/TextLineInfo.java line 
56:

> 54:  * @since 25
> 55:  */
> 56: public record TextLineInfo(int start, int end, Rectangle2D bounds) {

I understand that you are using `javafx.geometry.Rectangle2D` for this PR to 
hold all caret/layout/line information related to bounds, and that seems to 
work fine so far.

However, given that the `TextFlow`/`Text` APIs already provide information 
using `javafx.scene.shape.PathElement`, and given that as a result of this PR 
users will be able to query either old and new APIs, I was wondering if another 
`Shape` subclass might be better for the new API instead of `Rectangle2D`: As 
is now, you can't easily combine `Rectangle2D` with `PathElement` objects (in 
fact you need to do a manual conversion in `TextUtils::getRange` or 
`TextUtils::toRectangle2D`).

Have you thought about using `javafx.scene.shape.Rectangle` instead? That would 
simplify your internal operations, and would be more easy to use for developers 
(for instance, drawing new shapes based the LayoutInfo, like in your 
MonkeyTester `LayoutInfoVisualizer` class).

-------------

PR Review: https://git.openjdk.org/jfx/pull/1596#pullrequestreview-2593730681
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1941724308
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1941708045
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1941712304
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1941998555
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1942916469
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1942017852
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1941714592
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1941717570
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1942752033
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1942895045
PR Review Comment: https://git.openjdk.org/jfx/pull/1596#discussion_r1942718447

Reply via email to