35 import static sun.swing.SwingUtilities2.IMPLIED_CR;
36
37 /**
38 * A GlyphView is a styled chunk of text that represents a view
39 * mapped over an element in the text model. This view is generally
40 * responsible for displaying text glyphs using character level
41 * attributes in some way.
42 * An implementation of the GlyphPainter class is used to do the
43 * actual rendering and model/view translations. This separates
44 * rendering from layout and management of the association with
45 * the model.
46 * <p>
47 * The view supports breaking for the purpose of formatting.
48 * The fragments produced by breaking share the view that has
49 * primary responsibility for the element (i.e. they are nested
50 * classes and carry only a small amount of state of their own)
51 * so they can share its resources.
52 * <p>
53 * Since this view
54 * represents text that may have tabs embedded in it, it implements the
55 * <code>TabableView</code> interface. Tabs will only be
56 * expanded if this view is embedded in a container that does
57 * tab expansion. ParagraphView is an example of a container
58 * that does tab expansion.
59 *
60 * @since 1.3
61 *
62 * @author Timothy Prinzing
63 */
64 public class GlyphView extends View implements TabableView, Cloneable {
65
66 /**
67 * Constructs a new view wrapped on an element.
68 *
69 * @param elem the element
70 */
71 public GlyphView(Element elem) {
72 super(elem);
73 offset = 0;
74 length = 0;
75 Element parent = elem.getParentElement();
107 public GlyphPainter getGlyphPainter() {
108 return painter;
109 }
110
111 /**
112 * Sets the painter to use for rendering glyphs.
113 * @param p the painter to use for rendering glyphs
114 */
115 public void setGlyphPainter(GlyphPainter p) {
116 painter = p;
117 }
118
119 /**
120 * Fetch a reference to the text that occupies
121 * the given range. This is normally used by
122 * the GlyphPainter to determine what characters
123 * it should render glyphs for.
124 *
125 * @param p0 the starting document offset >= 0
126 * @param p1 the ending document offset >= p0
127 * @return the <code>Segment</code> containing the text
128 */
129 public Segment getText(int p0, int p1) {
130 // When done with the returned Segment it should be released by
131 // invoking:
132 // SegmentCache.releaseSharedSegment(segment);
133 Segment text = SegmentCache.getSharedSegment();
134 try {
135 Document doc = getDocument();
136 doc.getText(p0, p1 - p0, text);
137 } catch (BadLocationException bl) {
138 throw new StateInvariantError("GlyphView: Stale view: " + bl);
139 }
140 return text;
141 }
142
143 /**
144 * Fetch the background color to use to render the
145 * glyphs. If there is no background color, null should
146 * be returned. This is implemented to call
147 * <code>StyledDocument.getBackground</code> if the associated
148 * document is a styled document, otherwise it returns null.
149 * @return the background color to use to render the glyphs
150 */
151 public Color getBackground() {
152 Document doc = getDocument();
153 if (doc instanceof StyledDocument) {
154 AttributeSet attr = getAttributes();
155 if (attr.isDefined(StyleConstants.Background)) {
156 return ((StyledDocument)doc).getBackground(attr);
157 }
158 }
159 return null;
160 }
161
162 /**
163 * Fetch the foreground color to use to render the
164 * glyphs. If there is no foreground color, null should
165 * be returned. This is implemented to call
166 * <code>StyledDocument.getBackground</code> if the associated
167 * document is a StyledDocument. If the associated document
168 * is not a StyledDocument, the associated components foreground
169 * color is used. If there is no associated component, null
170 * is returned.
171 * @return the foreground color to use to render the glyphs
172 */
173 public Color getForeground() {
174 Document doc = getDocument();
175 if (doc instanceof StyledDocument) {
176 AttributeSet attr = getAttributes();
177 return ((StyledDocument)doc).getForeground(attr);
178 }
179 Component c = getContainer();
180 if (c != null) {
181 return c.getForeground();
182 }
183 return null;
184 }
185
186 /**
187 * Fetch the font that the glyphs should be based
188 * upon. This is implemented to call
189 * <code>StyledDocument.getFont</code> if the associated
190 * document is a StyledDocument. If the associated document
191 * is not a StyledDocument, the associated components font
192 * is used. If there is no associated component, null
193 * is returned.
194 * @return the font that the glyphs should be based upon
195 */
196 public Font getFont() {
197 Document doc = getDocument();
198 if (doc instanceof StyledDocument) {
199 AttributeSet attr = getAttributes();
200 return ((StyledDocument)doc).getFont(attr);
201 }
202 Component c = getContainer();
203 if (c != null) {
204 return c.getFont();
205 }
206 return null;
207 }
208
209 /**
633 float a = painter.getAscent(this);
634 float align;
635 if (sup) {
636 align = 1.0f;
637 } else if (sub) {
638 align = (h > 0) ? (h - (d + (a / 2))) / h : 0;
639 } else {
640 align = (h > 0) ? (h - d) / h : 0;
641 }
642 return align;
643 }
644 return super.getAlignment(axis);
645 }
646
647 /**
648 * Provides a mapping from the document model coordinate space
649 * to the coordinate space of the view mapped to it.
650 *
651 * @param pos the position to convert >= 0
652 * @param a the allocated region to render into
653 * @param b either <code>Position.Bias.Forward</code>
654 * or <code>Position.Bias.Backward</code>
655 * @return the bounding box of the given position
656 * @exception BadLocationException if the given position does not represent a
657 * valid location in the associated document
658 * @see View#modelToView
659 */
660 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
661 checkPainter();
662 return painter.modelToView(this, pos, b, a);
663 }
664
665 /**
666 * Provides a mapping from the view coordinate space to the logical
667 * coordinate space of the model.
668 *
669 * @param x the X coordinate >= 0
670 * @param y the Y coordinate >= 0
671 * @param a the allocated region to render into
672 * @param biasReturn either <code>Position.Bias.Forward</code>
673 * or <code>Position.Bias.Backward</code> is returned as the
674 * zero-th element of this array
675 * @return the location within the model that best represents the
676 * given point of view >= 0
677 * @see View#viewToModel
678 */
679 public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) {
680 checkPainter();
681 return painter.viewToModel(this, x, y, a, biasReturn);
682 }
683
684 /**
685 * Determines how attractive a break opportunity in
686 * this view is. This can be used for determining which
687 * view is the most attractive to call <code>breakView</code>
688 * on in the process of formatting. The
689 * higher the weight, the more attractive the break. A
690 * value equal to or lower than <code>View.BadBreakWeight</code>
691 * should not be considered for a break. A value greater
692 * than or equal to <code>View.ForcedBreakWeight</code> should
693 * be broken.
694 * <p>
695 * This is implemented to forward to the superclass for
696 * the Y_AXIS. Along the X_AXIS the following values
697 * may be returned.
698 * <dl>
699 * <dt><b>View.ExcellentBreakWeight</b>
700 * <dd>if there is whitespace proceeding the desired break
701 * location.
702 * <dt><b>View.BadBreakWeight</b>
703 * <dd>if the desired break location results in a break
704 * location of the starting offset.
705 * <dt><b>View.GoodBreakWeight</b>
706 * <dd>if the other conditions don't occur.
707 * </dl>
708 * This will normally result in the behavior of breaking
709 * on a whitespace location if one can be found, otherwise
710 * breaking between characters.
711 *
712 * @param axis may be either View.X_AXIS or View.Y_AXIS
1186 * @param v the {@code GlyphView}
1187 * @return of the descent
1188 */
1189 public abstract float getDescent(GlyphView v);
1190
1191 /**
1192 * Paint the glyphs representing the given range.
1193 * @param v the {@code GlyphView}
1194 * @param g the graphics context
1195 * @param a the current allocation of the view
1196 * @param p0 the beginning position
1197 * @param p1 the ending position
1198 */
1199 public abstract void paint(GlyphView v, Graphics g, Shape a, int p0, int p1);
1200
1201 /**
1202 * Provides a mapping from the document model coordinate space
1203 * to the coordinate space of the view mapped to it.
1204 * This is shared by the broken views.
1205 *
1206 * @param v the <code>GlyphView</code> containing the
1207 * destination coordinate space
1208 * @param pos the position to convert
1209 * @param bias either <code>Position.Bias.Forward</code>
1210 * or <code>Position.Bias.Backward</code>
1211 * @param a Bounds of the View
1212 * @return the bounding box of the given position
1213 * @exception BadLocationException if the given position does not represent a
1214 * valid location in the associated document
1215 * @see View#modelToView
1216 */
1217 public abstract Shape modelToView(GlyphView v,
1218 int pos, Position.Bias bias,
1219 Shape a) throws BadLocationException;
1220
1221 /**
1222 * Provides a mapping from the view coordinate space to the logical
1223 * coordinate space of the model.
1224 *
1225 * @param v the <code>GlyphView</code> to provide a mapping for
1226 * @param x the X coordinate
1227 * @param y the Y coordinate
1228 * @param a the allocated region to render into
1229 * @param biasReturn either <code>Position.Bias.Forward</code>
1230 * or <code>Position.Bias.Backward</code>
1231 * is returned as the zero-th element of this array
1232 * @return the location within the model that best represents the
1233 * given point of view
1234 * @see View#viewToModel
1235 */
1236 public abstract int viewToModel(GlyphView v,
1237 float x, float y, Shape a,
1238 Position.Bias[] biasReturn);
1239
1240 /**
1241 * Determines the model location that represents the
1242 * maximum advance that fits within the given span.
1243 * This could be used to break the given view. The result
1244 * should be a location just shy of the given advance. This
1245 * differs from viewToModel which returns the closest
1246 * position which might be proud of the maximum advance.
1247 *
1248 * @param v the view to find the model location to break at.
1249 * @param p0 the location in the model where the
1250 * fragment should start it's representation >= 0.
1251 * @param x the graphic location along the axis that the
1252 * broken view would occupy >= 0. This may be useful for
1253 * things like tab calculations.
1254 * @param len specifies the distance into the view
1255 * where a potential break is desired >= 0.
1256 * @return the maximum model location possible for a break.
1257 * @see View#breakView
1258 */
1259 public abstract int getBoundedPosition(GlyphView v, int p0, float x, float len);
1260
1261 /**
1262 * Create a painter to use for the given GlyphView. If
1263 * the painter carries state it can create another painter
1264 * to represent a new GlyphView that is being created. If
1265 * the painter doesn't hold any significant state, it can
1266 * return itself. The default behavior is to return itself.
1267 * @param v the <code>GlyphView</code> to provide a painter for
1268 * @param p0 the starting document offset >= 0
1269 * @param p1 the ending document offset >= p0
1270 * @return a painter to use for the given GlyphView
1271 */
1272 public GlyphPainter getPainter(GlyphView v, int p0, int p1) {
1273 return this;
1274 }
1275
1276 /**
1277 * Provides a way to determine the next visually represented model
1278 * location that one might place a caret. Some views may not be
1279 * visible, they might not be in the same order found in the model, or
1280 * they just might not allow access to some of the locations in the
1281 * model.
1282 *
1283 * @param v the view to use
1284 * @param pos the position to convert >= 0
1285 * @param b either <code>Position.Bias.Forward</code>
1286 * or <code>Position.Bias.Backward</code>
1287 * @param a the allocated region to render into
1288 * @param direction the direction from the current position that can
1289 * be thought of as the arrow keys typically found on a keyboard.
1290 * This may be SwingConstants.WEST, SwingConstants.EAST,
1291 * SwingConstants.NORTH, or SwingConstants.SOUTH.
1292 * @param biasRet either <code>Position.Bias.Forward</code>
1293 * or <code>Position.Bias.Backward</code>
1294 * is returned as the zero-th element of this array
1295 * @return the location within the model that best represents the next
1296 * location visual position.
1297 * @exception BadLocationException for a bad location within a document model
1298 * @exception IllegalArgumentException for an invalid direction
1299 */
1300 public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b, Shape a,
1301 int direction,
1302 Position.Bias[] biasRet)
1303 throws BadLocationException {
1304
1305 int startOffset = v.getStartOffset();
1306 int endOffset = v.getEndOffset();
1307 Segment text;
1308
1309 switch (direction) {
1310 case View.NORTH:
1311 case View.SOUTH:
1312 if (pos != -1) {
1313 // Presumably pos is between startOffset and endOffset,
|
35 import static sun.swing.SwingUtilities2.IMPLIED_CR;
36
37 /**
38 * A GlyphView is a styled chunk of text that represents a view
39 * mapped over an element in the text model. This view is generally
40 * responsible for displaying text glyphs using character level
41 * attributes in some way.
42 * An implementation of the GlyphPainter class is used to do the
43 * actual rendering and model/view translations. This separates
44 * rendering from layout and management of the association with
45 * the model.
46 * <p>
47 * The view supports breaking for the purpose of formatting.
48 * The fragments produced by breaking share the view that has
49 * primary responsibility for the element (i.e. they are nested
50 * classes and carry only a small amount of state of their own)
51 * so they can share its resources.
52 * <p>
53 * Since this view
54 * represents text that may have tabs embedded in it, it implements the
55 * {@code TabableView} interface. Tabs will only be
56 * expanded if this view is embedded in a container that does
57 * tab expansion. ParagraphView is an example of a container
58 * that does tab expansion.
59 *
60 * @since 1.3
61 *
62 * @author Timothy Prinzing
63 */
64 public class GlyphView extends View implements TabableView, Cloneable {
65
66 /**
67 * Constructs a new view wrapped on an element.
68 *
69 * @param elem the element
70 */
71 public GlyphView(Element elem) {
72 super(elem);
73 offset = 0;
74 length = 0;
75 Element parent = elem.getParentElement();
107 public GlyphPainter getGlyphPainter() {
108 return painter;
109 }
110
111 /**
112 * Sets the painter to use for rendering glyphs.
113 * @param p the painter to use for rendering glyphs
114 */
115 public void setGlyphPainter(GlyphPainter p) {
116 painter = p;
117 }
118
119 /**
120 * Fetch a reference to the text that occupies
121 * the given range. This is normally used by
122 * the GlyphPainter to determine what characters
123 * it should render glyphs for.
124 *
125 * @param p0 the starting document offset >= 0
126 * @param p1 the ending document offset >= p0
127 * @return the {@code Segment} containing the text
128 */
129 public Segment getText(int p0, int p1) {
130 // When done with the returned Segment it should be released by
131 // invoking:
132 // SegmentCache.releaseSharedSegment(segment);
133 Segment text = SegmentCache.getSharedSegment();
134 try {
135 Document doc = getDocument();
136 doc.getText(p0, p1 - p0, text);
137 } catch (BadLocationException bl) {
138 throw new StateInvariantError("GlyphView: Stale view: " + bl);
139 }
140 return text;
141 }
142
143 /**
144 * Fetch the background color to use to render the
145 * glyphs. If there is no background color, null should
146 * be returned. This is implemented to call
147 * {@code StyledDocument.getBackground} if the associated
148 * document is a styled document, otherwise it returns null.
149 * @return the background color to use to render the glyphs
150 */
151 public Color getBackground() {
152 Document doc = getDocument();
153 if (doc instanceof StyledDocument) {
154 AttributeSet attr = getAttributes();
155 if (attr.isDefined(StyleConstants.Background)) {
156 return ((StyledDocument)doc).getBackground(attr);
157 }
158 }
159 return null;
160 }
161
162 /**
163 * Fetch the foreground color to use to render the
164 * glyphs. If there is no foreground color, null should
165 * be returned. This is implemented to call
166 * {@code StyledDocument.getBackground} if the associated
167 * document is a StyledDocument. If the associated document
168 * is not a StyledDocument, the associated components foreground
169 * color is used. If there is no associated component, null
170 * is returned.
171 * @return the foreground color to use to render the glyphs
172 */
173 public Color getForeground() {
174 Document doc = getDocument();
175 if (doc instanceof StyledDocument) {
176 AttributeSet attr = getAttributes();
177 return ((StyledDocument)doc).getForeground(attr);
178 }
179 Component c = getContainer();
180 if (c != null) {
181 return c.getForeground();
182 }
183 return null;
184 }
185
186 /**
187 * Fetch the font that the glyphs should be based
188 * upon. This is implemented to call
189 * {@code StyledDocument.getFont} if the associated
190 * document is a StyledDocument. If the associated document
191 * is not a StyledDocument, the associated components font
192 * is used. If there is no associated component, null
193 * is returned.
194 * @return the font that the glyphs should be based upon
195 */
196 public Font getFont() {
197 Document doc = getDocument();
198 if (doc instanceof StyledDocument) {
199 AttributeSet attr = getAttributes();
200 return ((StyledDocument)doc).getFont(attr);
201 }
202 Component c = getContainer();
203 if (c != null) {
204 return c.getFont();
205 }
206 return null;
207 }
208
209 /**
633 float a = painter.getAscent(this);
634 float align;
635 if (sup) {
636 align = 1.0f;
637 } else if (sub) {
638 align = (h > 0) ? (h - (d + (a / 2))) / h : 0;
639 } else {
640 align = (h > 0) ? (h - d) / h : 0;
641 }
642 return align;
643 }
644 return super.getAlignment(axis);
645 }
646
647 /**
648 * Provides a mapping from the document model coordinate space
649 * to the coordinate space of the view mapped to it.
650 *
651 * @param pos the position to convert >= 0
652 * @param a the allocated region to render into
653 * @param b either {@code Position.Bias.Forward}
654 * or {@code Position.Bias.Backward}
655 * @return the bounding box of the given position
656 * @exception BadLocationException if the given position does not represent a
657 * valid location in the associated document
658 * @see View#modelToView
659 */
660 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
661 checkPainter();
662 return painter.modelToView(this, pos, b, a);
663 }
664
665 /**
666 * Provides a mapping from the view coordinate space to the logical
667 * coordinate space of the model.
668 *
669 * @param x the X coordinate >= 0
670 * @param y the Y coordinate >= 0
671 * @param a the allocated region to render into
672 * @param biasReturn either {@code Position.Bias.Forward}
673 * or {@code Position.Bias.Backward} is returned as the
674 * zero-th element of this array
675 * @return the location within the model that best represents the
676 * given point of view >= 0
677 * @see View#viewToModel
678 */
679 public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) {
680 checkPainter();
681 return painter.viewToModel(this, x, y, a, biasReturn);
682 }
683
684 /**
685 * Determines how attractive a break opportunity in
686 * this view is. This can be used for determining which
687 * view is the most attractive to call {@code breakView}
688 * on in the process of formatting. The
689 * higher the weight, the more attractive the break. A
690 * value equal to or lower than {@code View.BadBreakWeight}
691 * should not be considered for a break. A value greater
692 * than or equal to {@code View.ForcedBreakWeight} should
693 * be broken.
694 * <p>
695 * This is implemented to forward to the superclass for
696 * the Y_AXIS. Along the X_AXIS the following values
697 * may be returned.
698 * <dl>
699 * <dt><b>View.ExcellentBreakWeight</b>
700 * <dd>if there is whitespace proceeding the desired break
701 * location.
702 * <dt><b>View.BadBreakWeight</b>
703 * <dd>if the desired break location results in a break
704 * location of the starting offset.
705 * <dt><b>View.GoodBreakWeight</b>
706 * <dd>if the other conditions don't occur.
707 * </dl>
708 * This will normally result in the behavior of breaking
709 * on a whitespace location if one can be found, otherwise
710 * breaking between characters.
711 *
712 * @param axis may be either View.X_AXIS or View.Y_AXIS
1186 * @param v the {@code GlyphView}
1187 * @return of the descent
1188 */
1189 public abstract float getDescent(GlyphView v);
1190
1191 /**
1192 * Paint the glyphs representing the given range.
1193 * @param v the {@code GlyphView}
1194 * @param g the graphics context
1195 * @param a the current allocation of the view
1196 * @param p0 the beginning position
1197 * @param p1 the ending position
1198 */
1199 public abstract void paint(GlyphView v, Graphics g, Shape a, int p0, int p1);
1200
1201 /**
1202 * Provides a mapping from the document model coordinate space
1203 * to the coordinate space of the view mapped to it.
1204 * This is shared by the broken views.
1205 *
1206 * @param v the {@code GlyphView} containing the
1207 * destination coordinate space
1208 * @param pos the position to convert
1209 * @param bias either {@code Position.Bias.Forward}
1210 * or {@code Position.Bias.Backward}
1211 * @param a Bounds of the View
1212 * @return the bounding box of the given position
1213 * @exception BadLocationException if the given position does not represent a
1214 * valid location in the associated document
1215 * @see View#modelToView
1216 */
1217 public abstract Shape modelToView(GlyphView v,
1218 int pos, Position.Bias bias,
1219 Shape a) throws BadLocationException;
1220
1221 /**
1222 * Provides a mapping from the view coordinate space to the logical
1223 * coordinate space of the model.
1224 *
1225 * @param v the {@code GlyphView} to provide a mapping for
1226 * @param x the X coordinate
1227 * @param y the Y coordinate
1228 * @param a the allocated region to render into
1229 * @param biasReturn either {@code Position.Bias.Forward}
1230 * or {@code Position.Bias.Backward}
1231 * is returned as the zero-th element of this array
1232 * @return the location within the model that best represents the
1233 * given point of view
1234 * @see View#viewToModel
1235 */
1236 public abstract int viewToModel(GlyphView v,
1237 float x, float y, Shape a,
1238 Position.Bias[] biasReturn);
1239
1240 /**
1241 * Determines the model location that represents the
1242 * maximum advance that fits within the given span.
1243 * This could be used to break the given view. The result
1244 * should be a location just shy of the given advance. This
1245 * differs from viewToModel which returns the closest
1246 * position which might be proud of the maximum advance.
1247 *
1248 * @param v the view to find the model location to break at.
1249 * @param p0 the location in the model where the
1250 * fragment should start it's representation >= 0.
1251 * @param x the graphic location along the axis that the
1252 * broken view would occupy >= 0. This may be useful for
1253 * things like tab calculations.
1254 * @param len specifies the distance into the view
1255 * where a potential break is desired >= 0.
1256 * @return the maximum model location possible for a break.
1257 * @see View#breakView
1258 */
1259 public abstract int getBoundedPosition(GlyphView v, int p0, float x, float len);
1260
1261 /**
1262 * Create a painter to use for the given GlyphView. If
1263 * the painter carries state it can create another painter
1264 * to represent a new GlyphView that is being created. If
1265 * the painter doesn't hold any significant state, it can
1266 * return itself. The default behavior is to return itself.
1267 * @param v the {@code GlyphView} to provide a painter for
1268 * @param p0 the starting document offset >= 0
1269 * @param p1 the ending document offset >= p0
1270 * @return a painter to use for the given GlyphView
1271 */
1272 public GlyphPainter getPainter(GlyphView v, int p0, int p1) {
1273 return this;
1274 }
1275
1276 /**
1277 * Provides a way to determine the next visually represented model
1278 * location that one might place a caret. Some views may not be
1279 * visible, they might not be in the same order found in the model, or
1280 * they just might not allow access to some of the locations in the
1281 * model.
1282 *
1283 * @param v the view to use
1284 * @param pos the position to convert >= 0
1285 * @param b either {@code Position.Bias.Forward}
1286 * or {@code Position.Bias.Backward}
1287 * @param a the allocated region to render into
1288 * @param direction the direction from the current position that can
1289 * be thought of as the arrow keys typically found on a keyboard.
1290 * This may be SwingConstants.WEST, SwingConstants.EAST,
1291 * SwingConstants.NORTH, or SwingConstants.SOUTH.
1292 * @param biasRet either {@code Position.Bias.Forward}
1293 * or {@code Position.Bias.Backward}
1294 * is returned as the zero-th element of this array
1295 * @return the location within the model that best represents the next
1296 * location visual position.
1297 * @exception BadLocationException for a bad location within a document model
1298 * @exception IllegalArgumentException for an invalid direction
1299 */
1300 public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b, Shape a,
1301 int direction,
1302 Position.Bias[] biasRet)
1303 throws BadLocationException {
1304
1305 int startOffset = v.getStartOffset();
1306 int endOffset = v.getEndOffset();
1307 Segment text;
1308
1309 switch (direction) {
1310 case View.NORTH:
1311 case View.SOUTH:
1312 if (pos != -1) {
1313 // Presumably pos is between startOffset and endOffset,
|