GlyphPainter1.java revision 15954:64781a24c0f4
1/*
2 * Copyright (c) 1999, 2014, Oracle and/or its affiliates. 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * 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        float x = alloc.x;
102        int p = v.getStartOffset();
103        int[] justificationData = getJustificationData(v);
104        if (p != p0) {
105            text = v.getText(p, p0);
106            float width = Utilities.getTabbedTextWidth(v, text, metrics, x,
107                                                       expander, p,
108                                                       justificationData);
109            x += width;
110            SegmentCache.releaseSharedSegment(text);
111        }
112
113        // determine the y coordinate to render the glyphs
114        float y = alloc.y + metrics.getHeight() - metrics.getDescent();
115
116        // render the glyphs
117        text = v.getText(p0, p1);
118        g.setFont(metrics.getFont());
119
120        Utilities.drawTabbedText(v, text, x, y, g, expander,p0,
121                                 justificationData, true);
122        SegmentCache.releaseSharedSegment(text);
123    }
124
125    public Shape modelToView(GlyphView v, int pos, Position.Bias bias,
126                             Shape a) throws BadLocationException {
127
128        sync(v);
129        Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
130        int p0 = v.getStartOffset();
131        int p1 = v.getEndOffset();
132        TabExpander expander = v.getTabExpander();
133        Segment text;
134
135        if(pos == p1) {
136            // The caller of this is left to right and borders a right to
137            // left view, return our end location.
138            return new Rectangle(alloc.x + alloc.width, alloc.y, 0,
139                                 metrics.getHeight());
140        }
141        if ((pos >= p0) && (pos <= p1)) {
142            // determine range to the left of the position
143            text = v.getText(p0, pos);
144            int[] justificationData = getJustificationData(v);
145            int width = Utilities.getTabbedTextWidth(v, text, metrics, alloc.x, expander, p0,
146                                                     justificationData);
147            SegmentCache.releaseSharedSegment(text);
148            return new Rectangle(alloc.x + width, alloc.y, 0, metrics.getHeight());
149        }
150        throw new BadLocationException("modelToView - can't convert", p1);
151    }
152
153    /**
154     * Provides a mapping from the view coordinate space to the logical
155     * coordinate space of the model.
156     *
157     * @param v the view containing the view coordinates
158     * @param x the X coordinate
159     * @param y the Y coordinate
160     * @param a the allocated region to render into
161     * @param biasReturn always returns <code>Position.Bias.Forward</code>
162     *   as the zero-th element of this array
163     * @return the location within the model that best represents the
164     *  given point in the view
165     * @see View#viewToModel
166     */
167    public int viewToModel(GlyphView v, float x, float y, Shape a,
168                           Position.Bias[] biasReturn) {
169
170        sync(v);
171        Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
172        int p0 = v.getStartOffset();
173        int p1 = v.getEndOffset();
174        TabExpander expander = v.getTabExpander();
175        Segment text = v.getText(p0, p1);
176        int[] justificationData = getJustificationData(v);
177        int offs = Utilities.getTabbedTextOffset(v, text, metrics,
178                                                 alloc.x, (int) x, expander, p0,
179                                                 justificationData);
180        SegmentCache.releaseSharedSegment(text);
181        int retValue = p0 + offs;
182        if(retValue == p1) {
183            // No need to return backward bias as GlyphPainter1 is used for
184            // ltr text only.
185            retValue--;
186        }
187        biasReturn[0] = Position.Bias.Forward;
188        return retValue;
189    }
190
191    /**
192     * Determines the best location (in the model) to break
193     * the given view.
194     * This method attempts to break on a whitespace
195     * location.  If a whitespace location can't be found, the
196     * nearest character location is returned.
197     *
198     * @param v the view
199     * @param p0 the location in the model where the
200     *  fragment should start its representation >= 0
201     * @param pos the graphic location along the axis that the
202     *  broken view would occupy >= 0; this may be useful for
203     *  things like tab calculations
204     * @param len specifies the distance into the view
205     *  where a potential break is desired >= 0
206     * @return the model location desired for a break
207     * @see View#breakView
208     */
209    public int getBoundedPosition(GlyphView v, int p0, float x, float len) {
210        sync(v);
211        TabExpander expander = v.getTabExpander();
212        Segment s = v.getText(p0, v.getEndOffset());
213        int[] justificationData = getJustificationData(v);
214        int index = Utilities.getTabbedTextOffset(v, s, metrics, x, (x+len),
215                                                  expander, p0, false,
216                                                  justificationData, true);
217        SegmentCache.releaseSharedSegment(s);
218        int p1 = p0 + index;
219        return p1;
220    }
221
222    @SuppressWarnings("deprecation")
223    void sync(GlyphView v) {
224        Font f = v.getFont();
225        if ((metrics == null) || (! f.equals(metrics.getFont()))) {
226            // fetch a new FontMetrics
227            Container c = v.getContainer();
228            metrics = (c != null) ? c.getFontMetrics(f) :
229                Toolkit.getDefaultToolkit().getFontMetrics(f);
230        }
231    }
232
233
234
235    /**
236     * @return justificationData from the ParagraphRow this GlyphView
237     * is in or {@code null} if no justification is needed
238     */
239    private int[] getJustificationData(GlyphView v) {
240        View parent = v.getParent();
241        int [] ret = null;
242        if (parent instanceof ParagraphView.Row) {
243            ParagraphView.Row row = ((ParagraphView.Row) parent);
244            ret = row.justificationData;
245        }
246        return ret;
247    }
248
249    // --- variables ---------------------------------------------
250
251    FontMetrics metrics;
252}
253