001 /*
002 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package javax.swing.text;
026
027 import java.awt.*;
028
029 /**
030 * A class to perform rendering of the glyphs.
031 * This can be implemented to be stateless, or
032 * to hold some information as a cache to
033 * facilitate faster rendering and model/view
034 * translation. At a minimum, the GlyphPainter
035 * allows a View implementation to perform its
036 * duties independent of a particular version
037 * of JVM and selection of capabilities (i.e.
038 * shaping for i18n, etc).
039 * <p>
040 * This implementation is intended for operation
041 * under the JDK1.1 API of the Java Platform.
042 * Since the JDK is backward compatible with
043 * JDK1.1 API, this class will also function on
044 * Java 2. The JDK introduces improved
045 * API for rendering text however, so the GlyphPainter2
046 * is recommended for the DK.
047 *
048 * @author Timothy Prinzing
049 * @version 1.27 05/05/07
050 * @see GlyphView
051 */
052 class GlyphPainter1 extends GlyphView.GlyphPainter {
053
054 /**
055 * Determine the span the glyphs given a start location
056 * (for tab expansion).
057 */
058 public float getSpan(GlyphView v, int p0, int p1, TabExpander e,
059 float x) {
060 sync(v);
061 Segment text = v.getText(p0, p1);
062 int[] justificationData = getJustificationData(v);
063 int width = Utilities.getTabbedTextWidth(v, text, metrics,
064 (int) x, e, p0, justificationData);
065 SegmentCache.releaseSharedSegment(text);
066 return width;
067 }
068
069 public float getHeight(GlyphView v) {
070 sync(v);
071 return metrics.getHeight();
072 }
073
074 /**
075 * Fetches the ascent above the baseline for the glyphs
076 * corresponding to the given range in the model.
077 */
078 public float getAscent(GlyphView v) {
079 sync(v);
080 return metrics.getAscent();
081 }
082
083 /**
084 * Fetches the descent below the baseline for the glyphs
085 * corresponding to the given range in the model.
086 */
087 public float getDescent(GlyphView v) {
088 sync(v);
089 return metrics.getDescent();
090 }
091
092 /**
093 * Paints the glyphs representing the given range.
094 */
095 public void paint(GlyphView v, Graphics g, Shape a, int p0, int p1) {
096 sync(v);
097 Segment text;
098 TabExpander expander = v.getTabExpander();
099 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a
100 .getBounds();
101
102 // determine the x coordinate to render the glyphs
103 int x = alloc.x;
104 int p = v.getStartOffset();
105 int[] justificationData = getJustificationData(v);
106 if (p != p0) {
107 text = v.getText(p, p0);
108 int width = Utilities.getTabbedTextWidth(v, text, metrics,
109 x, expander, p, justificationData);
110 x += width;
111 SegmentCache.releaseSharedSegment(text);
112 }
113
114 // determine the y coordinate to render the glyphs
115 int y = alloc.y + metrics.getHeight() - metrics.getDescent();
116
117 // render the glyphs
118 text = v.getText(p0, p1);
119 g.setFont(metrics.getFont());
120
121 Utilities.drawTabbedText(v, text, x, y, g, expander, p0,
122 justificationData);
123 SegmentCache.releaseSharedSegment(text);
124 }
125
126 public Shape modelToView(GlyphView v, int pos, Position.Bias bias,
127 Shape a) throws BadLocationException {
128
129 sync(v);
130 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a
131 .getBounds();
132 int p0 = v.getStartOffset();
133 int p1 = v.getEndOffset();
134 TabExpander expander = v.getTabExpander();
135 Segment text;
136
137 if (pos == p1) {
138 // The caller of this is left to right and borders a right to
139 // left view, return our end location.
140 return new Rectangle(alloc.x + alloc.width, alloc.y, 0,
141 metrics.getHeight());
142 }
143 if ((pos >= p0) && (pos <= p1)) {
144 // determine range to the left of the position
145 text = v.getText(p0, pos);
146 int[] justificationData = getJustificationData(v);
147 int width = Utilities.getTabbedTextWidth(v, text, metrics,
148 alloc.x, expander, p0, justificationData);
149 SegmentCache.releaseSharedSegment(text);
150 return new Rectangle(alloc.x + width, alloc.y, 0, metrics
151 .getHeight());
152 }
153 throw new BadLocationException("modelToView - can't convert",
154 p1);
155 }
156
157 /**
158 * Provides a mapping from the view coordinate space to the logical
159 * coordinate space of the model.
160 *
161 * @param v the view containing the view coordinates
162 * @param x the X coordinate
163 * @param y the Y coordinate
164 * @param a the allocated region to render into
165 * @param biasReturn always returns <code>Position.Bias.Forward</code>
166 * as the zero-th element of this array
167 * @return the location within the model that best represents the
168 * given point in the view
169 * @see View#viewToModel
170 */
171 public int viewToModel(GlyphView v, float x, float y, Shape a,
172 Position.Bias[] biasReturn) {
173
174 sync(v);
175 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a
176 .getBounds();
177 int p0 = v.getStartOffset();
178 int p1 = v.getEndOffset();
179 TabExpander expander = v.getTabExpander();
180 Segment text = v.getText(p0, p1);
181 int[] justificationData = getJustificationData(v);
182 int offs = Utilities.getTabbedTextOffset(v, text, metrics,
183 alloc.x, (int) x, expander, p0, justificationData);
184 SegmentCache.releaseSharedSegment(text);
185 int retValue = p0 + offs;
186 if (retValue == p1) {
187 // No need to return backward bias as GlyphPainter1 is used for
188 // ltr text only.
189 retValue--;
190 }
191 biasReturn[0] = Position.Bias.Forward;
192 return retValue;
193 }
194
195 /**
196 * Determines the best location (in the model) to break
197 * the given view.
198 * This method attempts to break on a whitespace
199 * location. If a whitespace location can't be found, the
200 * nearest character location is returned.
201 *
202 * @param v the view
203 * @param p0 the location in the model where the
204 * fragment should start its representation >= 0
205 * @param pos the graphic location along the axis that the
206 * broken view would occupy >= 0; this may be useful for
207 * things like tab calculations
208 * @param len specifies the distance into the view
209 * where a potential break is desired >= 0
210 * @return the model location desired for a break
211 * @see View#breakView
212 */
213 public int getBoundedPosition(GlyphView v, int p0, float x,
214 float len) {
215 sync(v);
216 TabExpander expander = v.getTabExpander();
217 Segment s = v.getText(p0, v.getEndOffset());
218 int[] justificationData = getJustificationData(v);
219 int index = Utilities.getTabbedTextOffset(v, s, metrics,
220 (int) x, (int) (x + len), expander, p0, false,
221 justificationData);
222 SegmentCache.releaseSharedSegment(s);
223 int p1 = p0 + index;
224 return p1;
225 }
226
227 void sync(GlyphView v) {
228 Font f = v.getFont();
229 if ((metrics == null) || (!f.equals(metrics.getFont()))) {
230 // fetch a new FontMetrics
231 Container c = v.getContainer();
232 metrics = (c != null) ? c.getFontMetrics(f) : Toolkit
233 .getDefaultToolkit().getFontMetrics(f);
234 }
235 }
236
237 /**
238 * @return justificationData from the ParagraphRow this GlyphView
239 * is in or {@code null} if no justification is needed
240 */
241 private int[] getJustificationData(GlyphView v) {
242 View parent = v.getParent();
243 int[] ret = null;
244 if (parent instanceof ParagraphView.Row) {
245 ParagraphView.Row row = ((ParagraphView.Row) parent);
246 ret = row.justificationData;
247 }
248 return ret;
249 }
250
251 // --- variables ---------------------------------------------
252
253 FontMetrics metrics;
254 }
|