blob: 3d50d2ece53a3dc903d2d371fde37d56bd67d4a9 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.text;
26
27import java.awt.*;
28
29/**
30 * A class to perform rendering of the glyphs.
31 * This can be implemented to be stateless, or
32 * to hold some information as a cache to
33 * facilitate faster rendering and model/view
34 * translation. At a minimum, the GlyphPainter
35 * allows a View implementation to perform its
36 * duties independent of a particular version
37 * of JVM and selection of capabilities (i.e.
38 * shaping for i18n, etc).
39 * <p>
40 * This implementation is intended for operation
41 * under the JDK1.1 API of the Java Platform.
42 * Since the JDK is backward compatible with
43 * JDK1.1 API, this class will also function on
44 * Java 2. The JDK introduces improved
45 * API for rendering text however, so the GlyphPainter2
46 * is recommended for the DK.
47 *
48 * @author Timothy Prinzing
49 * @see GlyphView
50 */
51class GlyphPainter1 extends GlyphView.GlyphPainter {
52
53 /**
54 * Determine the span the glyphs given a start location
55 * (for tab expansion).
56 */
57 public float getSpan(GlyphView v, int p0, int p1,
58 TabExpander e, float x) {
59 sync(v);
60 Segment text = v.getText(p0, p1);
61 int[] justificationData = getJustificationData(v);
62 int width = Utilities.getTabbedTextWidth(v, text, metrics, (int) x, e, p0,
63 justificationData);
64 SegmentCache.releaseSharedSegment(text);
65 return width;
66 }
67
68 public float getHeight(GlyphView v) {
69 sync(v);
70 return metrics.getHeight();
71 }
72
73 /**
74 * Fetches the ascent above the baseline for the glyphs
75 * corresponding to the given range in the model.
76 */
77 public float getAscent(GlyphView v) {
78 sync(v);
79 return metrics.getAscent();
80 }
81
82 /**
83 * Fetches the descent below the baseline for the glyphs
84 * corresponding to the given range in the model.
85 */
86 public float getDescent(GlyphView v) {
87 sync(v);
88 return metrics.getDescent();
89 }
90
91 /**
92 * Paints the glyphs representing the given range.
93 */
94 public void paint(GlyphView v, Graphics g, Shape a, int p0, int p1) {
95 sync(v);
96 Segment text;
97 TabExpander expander = v.getTabExpander();
98 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
99
100 // determine the x coordinate to render the glyphs
101 int x = alloc.x;
102 int p = v.getStartOffset();
103 int[] justificationData = getJustificationData(v);
104 if (p != p0) {
105 text = v.getText(p, p0);
106 int width = Utilities.getTabbedTextWidth(v, text, metrics, x, expander, p,
107 justificationData);
108 x += width;
109 SegmentCache.releaseSharedSegment(text);
110 }
111
112 // determine the y coordinate to render the glyphs
113 int y = alloc.y + metrics.getHeight() - metrics.getDescent();
114
115 // render the glyphs
116 text = v.getText(p0, p1);
117 g.setFont(metrics.getFont());
118
119 Utilities.drawTabbedText(v, text, x, y, g, expander,p0,
120 justificationData);
121 SegmentCache.releaseSharedSegment(text);
122 }
123
124 public Shape modelToView(GlyphView v, int pos, Position.Bias bias,
125 Shape a) throws BadLocationException {
126
127 sync(v);
128 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
129 int p0 = v.getStartOffset();
130 int p1 = v.getEndOffset();
131 TabExpander expander = v.getTabExpander();
132 Segment text;
133
134 if(pos == p1) {
135 // The caller of this is left to right and borders a right to
136 // left view, return our end location.
137 return new Rectangle(alloc.x + alloc.width, alloc.y, 0,
138 metrics.getHeight());
139 }
140 if ((pos >= p0) && (pos <= p1)) {
141 // determine range to the left of the position
142 text = v.getText(p0, pos);
143 int[] justificationData = getJustificationData(v);
144 int width = Utilities.getTabbedTextWidth(v, text, metrics, alloc.x, expander, p0,
145 justificationData);
146 SegmentCache.releaseSharedSegment(text);
147 return new Rectangle(alloc.x + width, alloc.y, 0, metrics.getHeight());
148 }
149 throw new BadLocationException("modelToView - can't convert", p1);
150 }
151
152 /**
153 * Provides a mapping from the view coordinate space to the logical
154 * coordinate space of the model.
155 *
156 * @param v the view containing the view coordinates
157 * @param x the X coordinate
158 * @param y the Y coordinate
159 * @param a the allocated region to render into
160 * @param biasReturn always returns <code>Position.Bias.Forward</code>
161 * as the zero-th element of this array
162 * @return the location within the model that best represents the
163 * given point in the view
164 * @see View#viewToModel
165 */
166 public int viewToModel(GlyphView v, float x, float y, Shape a,
167 Position.Bias[] biasReturn) {
168
169 sync(v);
170 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
171 int p0 = v.getStartOffset();
172 int p1 = v.getEndOffset();
173 TabExpander expander = v.getTabExpander();
174 Segment text = v.getText(p0, p1);
175 int[] justificationData = getJustificationData(v);
176 int offs = Utilities.getTabbedTextOffset(v, text, metrics,
177 alloc.x, (int) x, expander, p0,
178 justificationData);
179 SegmentCache.releaseSharedSegment(text);
180 int retValue = p0 + offs;
181 if(retValue == p1) {
182 // No need to return backward bias as GlyphPainter1 is used for
183 // ltr text only.
184 retValue--;
185 }
186 biasReturn[0] = Position.Bias.Forward;
187 return retValue;
188 }
189
190 /**
191 * Determines the best location (in the model) to break
192 * the given view.
193 * This method attempts to break on a whitespace
194 * location. If a whitespace location can't be found, the
195 * nearest character location is returned.
196 *
197 * @param v the view
198 * @param p0 the location in the model where the
199 * fragment should start its representation >= 0
200 * @param pos the graphic location along the axis that the
201 * broken view would occupy >= 0; this may be useful for
202 * things like tab calculations
203 * @param len specifies the distance into the view
204 * where a potential break is desired >= 0
205 * @return the model location desired for a break
206 * @see View#breakView
207 */
208 public int getBoundedPosition(GlyphView v, int p0, float x, float len) {
209 sync(v);
210 TabExpander expander = v.getTabExpander();
211 Segment s = v.getText(p0, v.getEndOffset());
212 int[] justificationData = getJustificationData(v);
213 int index = Utilities.getTabbedTextOffset(v, s, metrics, (int)x, (int)(x+len),
214 expander, p0, false,
215 justificationData);
216 SegmentCache.releaseSharedSegment(s);
217 int p1 = p0 + index;
218 return p1;
219 }
220
221 void sync(GlyphView v) {
222 Font f = v.getFont();
223 if ((metrics == null) || (! f.equals(metrics.getFont()))) {
224 // fetch a new FontMetrics
225 Container c = v.getContainer();
226 metrics = (c != null) ? c.getFontMetrics(f) :
227 Toolkit.getDefaultToolkit().getFontMetrics(f);
228 }
229 }
230
231
232
233 /**
234 * @return justificationData from the ParagraphRow this GlyphView
235 * is in or {@code null} if no justification is needed
236 */
237 private int[] getJustificationData(GlyphView v) {
238 View parent = v.getParent();
239 int [] ret = null;
240 if (parent instanceof ParagraphView.Row) {
241 ParagraphView.Row row = ((ParagraphView.Row) parent);
242 ret = row.justificationData;
243 }
244 return ret;
245 }
246
247 // --- variables ---------------------------------------------
248
249 FontMetrics metrics;
250}