31 package com.sun.javafx.scene.control.skin;
32
33 import com.sun.javafx.scene.control.behavior.TextBinding;
34 import com.sun.javafx.scene.text.TextLayout;
35 import com.sun.javafx.tk.Toolkit;
36 import javafx.application.ConditionalFeature;
37 import javafx.application.Platform;
38 import javafx.beans.InvalidationListener;
39 import javafx.beans.Observable;
40 import javafx.beans.value.ObservableValue;
41 import javafx.collections.ObservableList;
42 import javafx.geometry.Bounds;
43 import javafx.geometry.HPos;
44 import javafx.geometry.Point2D;
45 import javafx.geometry.VPos;
46 import javafx.scene.Scene;
47 import javafx.scene.control.ContextMenu;
48 import javafx.scene.control.MenuItem;
49 import javafx.scene.control.OverrunStyle;
50 import com.sun.javafx.scene.control.ContextMenuContent;
51 import java.net.URL;
52 import javafx.scene.input.KeyCombination;
53 import javafx.scene.input.Mnemonic;
54 import javafx.scene.paint.Color;
55 import javafx.scene.text.Font;
56 import javafx.scene.text.Text;
57 import javafx.scene.text.TextBoundsType;
58 import javafx.scene.text.HitInfo;
59
60 import java.text.Bidi;
61 import java.util.Locale;
62 import java.util.function.Consumer;
63
64 import static javafx.scene.control.OverrunStyle.CENTER_ELLIPSIS;
65 import static javafx.scene.control.OverrunStyle.CENTER_WORD_ELLIPSIS;
66 import static javafx.scene.control.OverrunStyle.CLIP;
67 import static javafx.scene.control.OverrunStyle.ELLIPSIS;
68 import static javafx.scene.control.OverrunStyle.LEADING_ELLIPSIS;
69 import static javafx.scene.control.OverrunStyle.LEADING_WORD_ELLIPSIS;
70 import static javafx.scene.control.OverrunStyle.WORD_ELLIPSIS;
79 public class Utils {
80
81 static final Text helper = new Text();
82 static final double DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth();
83 static final double DEFAULT_LINE_SPACING = helper.getLineSpacing();
84 static final String DEFAULT_TEXT = helper.getText();
85 static final TextBoundsType DEFAULT_BOUNDS_TYPE = helper.getBoundsType();
86
87 /* Using TextLayout directly for simple text measurement.
88 * Instead of restoring the TextLayout attributes to default values
89 * (each renders the TextLayout unable to efficiently cache layout data).
90 * It always sets all the attributes pertinent to calculation being performed.
91 * Note that lineSpacing and boundsType are important when computing the height
92 * but irrelevant when computing the width.
93 *
94 * Note: This code assumes that TextBoundsType#VISUAL is never used by controls.
95 * */
96 static final TextLayout layout = Toolkit.getToolkit().getTextLayoutFactory().createLayout();
97
98 public static double getAscent(Font font, TextBoundsType boundsType) {
99 layout.setContent("", font.impl_getNativeFont());
100 layout.setWrapWidth(0);
101 layout.setLineSpacing(0);
102 if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
103 layout.setBoundsType(TextLayout.BOUNDS_CENTER);
104 } else {
105 layout.setBoundsType(0);
106 }
107 return -layout.getBounds().getMinY();
108 }
109
110 public static double getLineHeight(Font font, TextBoundsType boundsType) {
111 layout.setContent("", font.impl_getNativeFont());
112 layout.setWrapWidth(0);
113 layout.setLineSpacing(0);
114 if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
115 layout.setBoundsType(TextLayout.BOUNDS_CENTER);
116 } else {
117 layout.setBoundsType(0);
118 }
119
120 // RT-37092: Use the line bounds specifically, to include font leading.
121 return layout.getLines()[0].getBounds().getHeight();
122 }
123
124 public static double computeTextWidth(Font font, String text, double wrappingWidth) {
125 layout.setContent(text != null ? text : "", font.impl_getNativeFont());
126 layout.setWrapWidth((float)wrappingWidth);
127 return layout.getBounds().getWidth();
128 }
129
130 public static double computeTextHeight(Font font, String text, double wrappingWidth, TextBoundsType boundsType) {
131 return computeTextHeight(font, text, wrappingWidth, 0, boundsType);
132 }
133
134 @SuppressWarnings("deprecation")
135 public static double computeTextHeight(Font font, String text, double wrappingWidth, double lineSpacing, TextBoundsType boundsType) {
136 layout.setContent(text != null ? text : "", font.impl_getNativeFont());
137 layout.setWrapWidth((float)wrappingWidth);
138 layout.setLineSpacing((float)lineSpacing);
139 if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
140 layout.setBoundsType(TextLayout.BOUNDS_CENTER);
141 } else {
142 layout.setBoundsType(0);
143 }
144 return layout.getBounds().getHeight();
145 }
146
147 public static int computeTruncationIndex(Font font, String text, double width) {
148 helper.setText(text);
149 helper.setFont(font);
150 helper.setWrappingWidth(0);
151 helper.setLineSpacing(0);
152 // The -2 is a fudge to make sure the result more often matches
153 // what we get from using computeTextWidth instead. It's not yet
154 // clear what causes the small discrepancies.
155 Bounds bounds = helper.getLayoutBounds();
156 Point2D endPoint = new Point2D(width - 2, bounds.getMinY() + bounds.getHeight() / 2);
|
31 package com.sun.javafx.scene.control.skin;
32
33 import com.sun.javafx.scene.control.behavior.TextBinding;
34 import com.sun.javafx.scene.text.TextLayout;
35 import com.sun.javafx.tk.Toolkit;
36 import javafx.application.ConditionalFeature;
37 import javafx.application.Platform;
38 import javafx.beans.InvalidationListener;
39 import javafx.beans.Observable;
40 import javafx.beans.value.ObservableValue;
41 import javafx.collections.ObservableList;
42 import javafx.geometry.Bounds;
43 import javafx.geometry.HPos;
44 import javafx.geometry.Point2D;
45 import javafx.geometry.VPos;
46 import javafx.scene.Scene;
47 import javafx.scene.control.ContextMenu;
48 import javafx.scene.control.MenuItem;
49 import javafx.scene.control.OverrunStyle;
50 import com.sun.javafx.scene.control.ContextMenuContent;
51 import com.sun.javafx.text.FontHelper;
52 import java.net.URL;
53 import javafx.scene.input.KeyCombination;
54 import javafx.scene.input.Mnemonic;
55 import javafx.scene.paint.Color;
56 import javafx.scene.text.Font;
57 import javafx.scene.text.Text;
58 import javafx.scene.text.TextBoundsType;
59 import javafx.scene.text.HitInfo;
60
61 import java.text.Bidi;
62 import java.util.Locale;
63 import java.util.function.Consumer;
64
65 import static javafx.scene.control.OverrunStyle.CENTER_ELLIPSIS;
66 import static javafx.scene.control.OverrunStyle.CENTER_WORD_ELLIPSIS;
67 import static javafx.scene.control.OverrunStyle.CLIP;
68 import static javafx.scene.control.OverrunStyle.ELLIPSIS;
69 import static javafx.scene.control.OverrunStyle.LEADING_ELLIPSIS;
70 import static javafx.scene.control.OverrunStyle.LEADING_WORD_ELLIPSIS;
71 import static javafx.scene.control.OverrunStyle.WORD_ELLIPSIS;
80 public class Utils {
81
82 static final Text helper = new Text();
83 static final double DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth();
84 static final double DEFAULT_LINE_SPACING = helper.getLineSpacing();
85 static final String DEFAULT_TEXT = helper.getText();
86 static final TextBoundsType DEFAULT_BOUNDS_TYPE = helper.getBoundsType();
87
88 /* Using TextLayout directly for simple text measurement.
89 * Instead of restoring the TextLayout attributes to default values
90 * (each renders the TextLayout unable to efficiently cache layout data).
91 * It always sets all the attributes pertinent to calculation being performed.
92 * Note that lineSpacing and boundsType are important when computing the height
93 * but irrelevant when computing the width.
94 *
95 * Note: This code assumes that TextBoundsType#VISUAL is never used by controls.
96 * */
97 static final TextLayout layout = Toolkit.getToolkit().getTextLayoutFactory().createLayout();
98
99 public static double getAscent(Font font, TextBoundsType boundsType) {
100 layout.setContent("", FontHelper.getNativeFont(font));
101 layout.setWrapWidth(0);
102 layout.setLineSpacing(0);
103 if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
104 layout.setBoundsType(TextLayout.BOUNDS_CENTER);
105 } else {
106 layout.setBoundsType(0);
107 }
108 return -layout.getBounds().getMinY();
109 }
110
111 public static double getLineHeight(Font font, TextBoundsType boundsType) {
112 layout.setContent("", FontHelper.getNativeFont(font));
113 layout.setWrapWidth(0);
114 layout.setLineSpacing(0);
115 if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
116 layout.setBoundsType(TextLayout.BOUNDS_CENTER);
117 } else {
118 layout.setBoundsType(0);
119 }
120
121 // RT-37092: Use the line bounds specifically, to include font leading.
122 return layout.getLines()[0].getBounds().getHeight();
123 }
124
125 public static double computeTextWidth(Font font, String text, double wrappingWidth) {
126 layout.setContent(text != null ? text : "", FontHelper.getNativeFont(font));
127 layout.setWrapWidth((float)wrappingWidth);
128 return layout.getBounds().getWidth();
129 }
130
131 public static double computeTextHeight(Font font, String text, double wrappingWidth, TextBoundsType boundsType) {
132 return computeTextHeight(font, text, wrappingWidth, 0, boundsType);
133 }
134
135 @SuppressWarnings("deprecation")
136 public static double computeTextHeight(Font font, String text, double wrappingWidth, double lineSpacing, TextBoundsType boundsType) {
137 layout.setContent(text != null ? text : "", FontHelper.getNativeFont(font));
138 layout.setWrapWidth((float)wrappingWidth);
139 layout.setLineSpacing((float)lineSpacing);
140 if (boundsType == TextBoundsType.LOGICAL_VERTICAL_CENTER) {
141 layout.setBoundsType(TextLayout.BOUNDS_CENTER);
142 } else {
143 layout.setBoundsType(0);
144 }
145 return layout.getBounds().getHeight();
146 }
147
148 public static int computeTruncationIndex(Font font, String text, double width) {
149 helper.setText(text);
150 helper.setFont(font);
151 helper.setWrappingWidth(0);
152 helper.setLineSpacing(0);
153 // The -2 is a fudge to make sure the result more often matches
154 // what we get from using computeTextWidth instead. It's not yet
155 // clear what causes the small discrepancies.
156 Bounds bounds = helper.getLayoutBounds();
157 Point2D endPoint = new Point2D(width - 2, bounds.getMinY() + bounds.getHeight() / 2);
|