Skip to content

Commit 04c5e40

Browse files
author
Andy Goryachev
committed
8357594: Additional geometry-based Text/TextFlow APIs
Reviewed-by: kcr, mstrauss
1 parent 203c049 commit 04c5e40

File tree

5 files changed

+538
-34
lines changed

5 files changed

+538
-34
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,16 @@ public final class TextUtils {
5555
* @param type the type of geometry to query
5656
* @param dx the x offset to add to each path element
5757
* @param dy the y offset to add to each path element
58+
* @param lineSpacing the line spacing (applies only to TYPE_TEXT)
5859
* @return the array of {@code PathElement}s
5960
*/
60-
public static PathElement[] getRange(TextLayout layout, int start, int end, int type, double dx, double dy) {
61+
public static PathElement[] getRange(TextLayout layout, int start, int end, int type, double dx, double dy, double lineSpacing) {
6162
ArrayList<PathElement> a = new ArrayList<>();
6263
layout.getRange(start, end, type, (left, top, right, bottom) -> {
6364
double leftEdge = left + dx;
6465
double rightEdge = right + dx;
6566
double topEdge = top + dy;
66-
double bottomEdge = bottom + dy;
67+
double bottomEdge = bottom + dy + lineSpacing;
6768
a.add(new MoveTo(leftEdge, topEdge));
6869
a.add(new LineTo(rightEdge, topEdge));
6970
a.add(new LineTo(rightEdge, bottomEdge));

modules/javafx.graphics/src/main/java/javafx/scene/text/Text.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,13 +1056,13 @@ private int findFirstRunStart() {
10561056
return start;
10571057
}
10581058

1059-
private PathElement[] getRange(int start, int end, int type) {
1059+
private PathElement[] getRange(int start, int end, int type, double lineSpacing) {
10601060
int length = getTextInternal().length();
10611061
if (0 <= start && start < end && end <= length) {
10621062
TextLayout layout = getTextLayout();
10631063
double dx = getX();
10641064
double dy = getY() - getYRendering();
1065-
return TextUtils.getRange(layout, start, end, type, dx, dy);
1065+
return TextUtils.getRange(layout, start, end, type, dx, dy, lineSpacing);
10661066
}
10671067
return EMPTY_PATH_ELEMENT_ARRAY;
10681068
}
@@ -1088,14 +1088,31 @@ public final PathElement[] caretShape(int charIndex, boolean caretBias) {
10881088

10891089
/**
10901090
* Returns the shape for the range of the text in local coordinates.
1091+
* The returned value does not include line spacing.
10911092
*
10921093
* @param start the beginning character index for the range
10931094
* @param end the end character index (non-inclusive) for the range
10941095
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
10951096
* @since 9
1097+
* @see #getRangeShape(int, int, boolean)
10961098
*/
10971099
public final PathElement[] rangeShape(int start, int end) {
1098-
return getRange(start, end, TextLayout.TYPE_TEXT);
1100+
return getRange(start, end, TextLayout.TYPE_TEXT, 0.0);
1101+
}
1102+
1103+
/**
1104+
* Returns the shape for the range of the text in local coordinates,
1105+
* with or without line spacing.
1106+
*
1107+
* @param start the beginning character index for the range
1108+
* @param end the end character index (non-inclusive) for the range
1109+
* @param includeLineSpacing whether the shapes include line spacing
1110+
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
1111+
* @since 25
1112+
*/
1113+
public final PathElement[] getRangeShape(int start, int end, boolean includeLineSpacing) {
1114+
double lineSpacing = includeLineSpacing ? getLineSpacing() : 0.0;
1115+
return getRange(start, end, TextLayout.TYPE_TEXT, lineSpacing);
10991116
}
11001117

11011118
/**
@@ -1107,7 +1124,19 @@ public final PathElement[] rangeShape(int start, int end) {
11071124
* @since 9
11081125
*/
11091126
public final PathElement[] underlineShape(int start, int end) {
1110-
return getRange(start, end, TextLayout.TYPE_UNDERLINE);
1127+
return getRange(start, end, TextLayout.TYPE_UNDERLINE, 0.0);
1128+
}
1129+
1130+
/**
1131+
* Returns the shape for the strike-through in local coordinates.
1132+
*
1133+
* @param start the beginning character index for the range
1134+
* @param end the end character index (non-inclusive) for the range
1135+
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
1136+
* @since 25
1137+
*/
1138+
public final PathElement[] getStrikeThroughShape(int start, int end) {
1139+
return getRange(start, end, TextLayout.TYPE_STRIKETHROUGH, 0.0);
11111140
}
11121141

11131142
private float getYAdjustment(BaseBounds bounds) {
@@ -1769,7 +1798,7 @@ final ReadOnlyObjectProperty<PathElement[]> selectionShapeProperty() {
17691798
@Override protected PathElement[] computeValue() {
17701799
int start = getSelectionStart();
17711800
int end = getSelectionEnd();
1772-
return getRange(start, end, TextLayout.TYPE_TEXT);
1801+
return getRange(start, end, TextLayout.TYPE_TEXT, 0.0);
17731802
}
17741803
};
17751804
selectionShape = new SimpleObjectProperty<>(Text.this, "selectionShape");

modules/javafx.graphics/src/main/java/javafx/scene/text/TextFlow.java

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,15 @@ private void checkOrientation() {
193193

194194
/**
195195
* Maps local point to {@link HitInfo} in the content.
196+
* <p>
197+
* NOTE: this method does not take border or padding into account.
196198
*
197199
* @param point the specified point to be tested
198200
* @return a {@code HitInfo} representing the character index found
199201
* @since 9
202+
* @deprecated replaced by {@link #getHitInfo(javafx.geometry.Point2D)}
200203
*/
204+
@Deprecated(since="25")
201205
public final HitInfo hitTest(javafx.geometry.Point2D point) {
202206
if (point != null) {
203207
TextLayout layout = getTextLayout();
@@ -210,42 +214,132 @@ public final HitInfo hitTest(javafx.geometry.Point2D point) {
210214
}
211215
}
212216

217+
/**
218+
* Maps local point to {@link HitInfo} in the content.
219+
*
220+
* @param point the specified point to be tested
221+
* @return a {@code HitInfo} representing the character index found
222+
* @since 25
223+
*/
224+
public final HitInfo getHitInfo(javafx.geometry.Point2D point) {
225+
if (point != null) {
226+
TextLayout layout = getTextLayout();
227+
double x = point.getX() - snappedLeftInset();
228+
double y = point.getY() - snappedTopInset();
229+
TextLayout.Hit h = layout.getHitInfo((float)x, (float)y);
230+
return new HitInfo(h.getCharIndex(), h.getInsertionIndex(), h.isLeading());
231+
} else {
232+
return null;
233+
}
234+
}
235+
213236
/**
214237
* Returns shape of caret in local coordinates.
238+
* <p>
239+
* NOTE: this method does not take border or padding into account.
215240
*
216241
* @param charIndex the character index for the caret
217242
* @param leading whether the caret is biased on the leading edge of the character
218243
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
219244
* @since 9
245+
* @deprecated replaced by {@link #getCaretShape(int, boolean)}
220246
*/
247+
@Deprecated(since="25")
221248
public PathElement[] caretShape(int charIndex, boolean leading) {
222249
TextLayout.CaretGeometry g = getTextLayout().getCaretGeometry(charIndex, leading);
223-
// TODO padding JDK-8341438?
224250
return TextUtils.getCaretPathElements(g, 0.0, 0.0);
225251
}
226252

253+
/**
254+
* Returns shape of caret in local coordinates.
255+
*
256+
* @param charIndex the character index for the caret
257+
* @param leading whether the caret is biased on the leading edge of the character
258+
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
259+
* @since 25
260+
*/
261+
public PathElement[] getCaretShape(int charIndex, boolean leading) {
262+
TextLayout.CaretGeometry g = getTextLayout().getCaretGeometry(charIndex, leading);
263+
double dx = snappedLeftInset();
264+
double dy = snappedTopInset();
265+
return TextUtils.getCaretPathElements(g, dx, dy);
266+
}
267+
227268
/**
228269
* Returns shape for the range of the text in local coordinates.
270+
* <p>
271+
* NOTES:
272+
* <ul>
273+
* <li>this method does not take border or padding into account
274+
* <li>the shapes returned do not include line spacing
275+
* </ul>
229276
*
230277
* @param start the beginning character index for the range
231278
* @param end the end character index (non-inclusive) for the range
232279
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
233280
* @since 9
281+
* @deprecated replaced by {@link #getRangeShape(int, int, boolean)}
234282
*/
283+
@Deprecated(since="25")
235284
public final PathElement[] rangeShape(int start, int end) {
236-
return getRange(start, end, TextLayout.TYPE_TEXT);
285+
return getRange(start, end, TextLayout.TYPE_TEXT, false, 0.0);
286+
}
287+
288+
/**
289+
* Returns shape for the range of the text in local coordinates.
290+
*
291+
* @param start the beginning character index for the range
292+
* @param end the end character index (non-inclusive) for the range
293+
* @param includeLineSpacing determines whether the result includes the line spacing
294+
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
295+
* @since 25
296+
* @see LayoutInfo#getSelectionGeometry(int, int, boolean)
297+
*/
298+
public final PathElement[] getRangeShape(int start, int end, boolean includeLineSpacing) {
299+
double lineSpacing = includeLineSpacing ? getLineSpacing() : 0.0;
300+
return getRange(start, end, TextLayout.TYPE_TEXT, true, lineSpacing);
237301
}
238302

239303
/**
240304
* Returns the shape for the underline in local coordinates.
305+
* <p>
306+
* NOTE: this method does not take border or padding into account.
241307
*
242308
* @param start the beginning character index for the range
243309
* @param end the end character index (non-inclusive) for the range
244310
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
245311
* @since 21
312+
* @deprecated replaced by {@link #getUnderlineShape(int, int)}
246313
*/
314+
@Deprecated(since="25")
247315
public final PathElement[] underlineShape(int start, int end) {
248-
return getRange(start, end, TextLayout.TYPE_UNDERLINE);
316+
return getRange(start, end, TextLayout.TYPE_UNDERLINE, false, 0.0);
317+
}
318+
319+
/**
320+
* Returns the shape for the underline in local coordinates.
321+
*
322+
* @param start the beginning character index for the range
323+
* @param end the end character index (non-inclusive) for the range
324+
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
325+
* @since 25
326+
* @see LayoutInfo#getUnderlineGeometry(int, int)
327+
*/
328+
public final PathElement[] getUnderlineShape(int start, int end) {
329+
return getRange(start, end, TextLayout.TYPE_UNDERLINE, true, 0.0);
330+
}
331+
332+
/**
333+
* Returns the shape for the strike-through in local coordinates.
334+
*
335+
* @param start the beginning character index for the range
336+
* @param end the end character index (non-inclusive) for the range
337+
* @return an array of {@code PathElement} which can be used to create a {@code Shape}
338+
* @since 25
339+
* @see LayoutInfo#getStrikeThroughGeometry(int, int)
340+
*/
341+
public final PathElement[] getStrikeThroughShape(int start, int end) {
342+
return getRange(start, end, TextLayout.TYPE_STRIKETHROUGH, true, 0.0);
249343
}
250344

251345
@Override
@@ -368,9 +462,18 @@ public boolean usesMirroring() {
368462
inLayout = false;
369463
}
370464

371-
private PathElement[] getRange(int start, int end, int type) {
465+
private PathElement[] getRange(int start, int end, int type, boolean accountForInsets, double lineSpacing) {
466+
double dx;
467+
double dy;
468+
if (accountForInsets) {
469+
dx = snappedLeftInset();
470+
dy = snappedTopInset();
471+
} else {
472+
dx = 0.0;
473+
dy = 0.0;
474+
}
372475
TextLayout layout = getTextLayout();
373-
return TextUtils.getRange(layout, start, end, type, 0, 0);
476+
return TextUtils.getRange(layout, start, end, type, dx, dy, lineSpacing);
374477
}
375478

376479
private static class EmbeddedSpan implements TextSpan {

0 commit comments

Comments
 (0)