1/*
2 * Copyright (c) 2000, 2013, 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 */
25
26package sun.font;
27
28import java.awt.Font;
29import java.awt.font.GlyphVector;
30import java.awt.font.FontRenderContext;
31import java.util.concurrent.atomic.AtomicBoolean;
32import sun.java2d.loops.FontInfo;
33
34/*
35 * This class represents a list of actual renderable glyphs.
36 * It can be constructed from a number of text sources, representing
37 * the various ways in which a programmer can ask a Graphics2D object
38 * to render some text.  Once constructed, it provides a way of iterating
39 * through the device metrics and graybits of the individual glyphs that
40 * need to be rendered to the screen.
41 *
42 * Note that this class holds pointers to native data which must be
43 * disposed.  It is not marked as finalizable since it is intended
44 * to be very lightweight and finalization is a comparitively expensive
45 * procedure.  The caller must specifically use try{} finally{} to
46 * manually ensure that the object is disposed after use, otherwise
47 * native data structures might be leaked.
48 *
49 * Here is a code sample for using this class:
50 *
51 * public void drawString(String str, FontInfo info, float x, float y) {
52 *     GlyphList gl = GlyphList.getInstance();
53 *     try {
54 *         gl.setFromString(info, str, x, y);
55 *         int strbounds[] = gl.getBounds();
56 *         int numglyphs = gl.getNumGlyphs();
57 *         for (int i = 0; i < numglyphs; i++) {
58 *             gl.setGlyphIndex(i);
59 *             int metrics[] = gl.getMetrics();
60 *             byte bits[] = gl.getGrayBits();
61 *             int glyphx = metrics[0];
62 *             int glyphy = metrics[1];
63 *             int glyphw = metrics[2];
64 *             int glyphh = metrics[3];
65 *             int off = 0;
66 *             for (int j = 0; j < glyphh; j++) {
67 *                 for (int i = 0; i < glyphw; i++) {
68 *                     int dx = glyphx + i;
69 *                     int dy = glyphy + j;
70 *                     int alpha = bits[off++];
71 *                     drawPixel(alpha, dx, dy);
72 *                 }
73 *             }
74 *         }
75 *     } finally {
76 *         gl.dispose();
77 *     }
78 * }
79 */
80public final class GlyphList {
81    private static final int MINGRAYLENGTH = 1024;
82    private static final int MAXGRAYLENGTH = 8192;
83    private static final int DEFAULT_LENGTH = 32;
84
85    int glyphindex;
86    int metrics[];
87    byte graybits[];
88
89    /* A reference to the strike is needed for the case when the GlyphList
90     * may be added to a queue for batch processing, (e.g. OpenGL) and we need
91     * to be completely certain that the strike is still valid when the glyphs
92     * images are later referenced.  This does mean that if such code discards
93     * GlyphList and places only the data it contains on the queue, that the
94     * strike needs to be part of that data held by a strong reference.
95     * In the cases of drawString() and drawChars(), this is a single strike,
96     * although it may be a composite strike.  In the case of
97     * drawGlyphVector() it may be a single strike, or a list of strikes.
98     */
99    Object strikelist; // hold multiple strikes during rendering of complex gv
100
101    /* In normal usage, the same GlyphList will get recycled, so
102     * it makes sense to allocate arrays that will get reused along with
103     * it, rather than generating garbage. Garbage will be generated only
104     * in MP envts where multiple threads are executing. Throughput should
105     * still be higher in those cases.
106     */
107    int len = 0;
108    int maxLen = 0;
109    int maxPosLen = 0;
110    int glyphData[];
111    char chData[];
112    long images[];
113    float positions[];
114    float x, y;
115    float gposx, gposy;
116    boolean usePositions;
117
118    /* lcdRGBOrder is used only by LCD text rendering. Its here because
119     * the Graphics may have a different hint value than the one used
120     * by a GlyphVector, so it has to be stored here - and is obtained
121     * from the right FontInfo. Another approach would have been to have
122     * install a separate pipe for that case but that's a lot of extra
123     * code when a simple boolean will suffice. The overhead to non-LCD
124     * text is a redundant boolean assign per call.
125     */
126    boolean lcdRGBOrder;
127
128    /*
129     * lcdSubPixPos is used only by LCD text rendering. Its here because
130     * the Graphics may have a different hint value than the one used
131     * by a GlyphVector, so it has to be stored here - and is obtained
132     * from the right FontInfo. Its also needed by the code which
133     * calculates glyph positions which already needs to access this
134     * GlyphList and would otherwise need the FontInfo.
135     * This is true only if LCD text and fractional metrics hints
136     * are selected on the graphics.
137     * When this is true and the glyph positions as determined by the
138     * advances are non-integral, it requests adjustment of the positions.
139     * Setting this for surfaces which do not support it through accelerated
140     * loops may cause a slow-down as software loops are invoked instead.
141     */
142    boolean lcdSubPixPos;
143
144    /* This scheme creates a singleton GlyphList which is checked out
145     * for use. Callers who find its checked out create one that after use
146     * is discarded. This means that in a MT-rendering environment,
147     * there's no need to synchronise except for that one instance.
148     * Fewer threads will then need to synchronise, perhaps helping
149     * throughput on a MP system. If for some reason the reusable
150     * GlyphList is checked out for a long time (or never returned?) then
151     * we would end up always creating new ones. That situation should not
152     * occur and if it did, it would just lead to some extra garbage being
153     * created.
154     */
155    private static final GlyphList reusableGL = new GlyphList();
156    private static final AtomicBoolean inUse = new AtomicBoolean();
157
158
159    void ensureCapacity(int len) {
160      /* Note len must not be -ve! only setFromChars should be capable
161       * of passing down a -ve len, and this guards against it.
162       */
163        if (len < 0) {
164          len = 0;
165        }
166        if (usePositions && len > maxPosLen) {
167            positions = new float[len * 2 + 2];
168            maxPosLen = len;
169        }
170
171        if (maxLen == 0 || len > maxLen) {
172            glyphData = new int[len];
173            chData = new char[len];
174            images = new long[len];
175            maxLen = len;
176        }
177    }
178
179    private GlyphList() {
180//         ensureCapacity(DEFAULT_LENGTH);
181    }
182
183//     private GlyphList(int arraylen) {
184//          ensureCapacity(arraylen);
185//     }
186
187    public static GlyphList getInstance() {
188        if (inUse.compareAndSet(false, true)) {
189            return reusableGL;
190        } else {
191            return new GlyphList();
192        }
193    }
194
195    /* In some cases the caller may be able to estimate the size of
196     * array needed, and it will usually be long enough. This avoids
197     * the unnecessary reallocation that occurs if our default
198     * values are too small. This is useful because this object
199     * will be discarded so the re-allocation overhead is high.
200     */
201//     public static GlyphList getInstance(int sz) {
202//      if (inUse.compareAndSet(false, true) {
203//          return reusableGL;
204//      } else {
205//          return new GlyphList(sz);
206//      }
207//     }
208
209    /* GlyphList is in an invalid state until setFrom* method is called.
210     * After obtaining a new GlyphList it is the caller's responsibility
211     * that one of these methods is executed before handing off the
212     * GlyphList
213     */
214
215    public boolean setFromString(FontInfo info, String str, float x, float y) {
216        this.x = x;
217        this.y = y;
218        this.strikelist = info.fontStrike;
219        this.lcdRGBOrder = info.lcdRGBOrder;
220        this.lcdSubPixPos = info.lcdSubPixPos;
221        len = str.length();
222        ensureCapacity(len);
223        str.getChars(0, len, chData, 0);
224        return mapChars(info, len);
225    }
226
227    public boolean setFromChars(FontInfo info, char[] chars, int off, int alen,
228                                float x, float y) {
229        this.x = x;
230        this.y = y;
231        this.strikelist = info.fontStrike;
232        this.lcdRGBOrder = info.lcdRGBOrder;
233        this.lcdSubPixPos = info.lcdSubPixPos;
234        len = alen;
235        if (alen < 0) {
236            len = 0;
237        } else {
238            len = alen;
239        }
240        ensureCapacity(len);
241        System.arraycopy(chars, off, chData, 0, len);
242        return mapChars(info, len);
243    }
244
245    private boolean mapChars(FontInfo info, int len) {
246        /* REMIND.Is it worthwhile for the iteration to convert
247         * chars to glyph ids to directly map to images?
248         */
249        if (info.font2D.getMapper().charsToGlyphsNS(len, chData, glyphData)) {
250            return false;
251        }
252        info.fontStrike.getGlyphImagePtrs(glyphData, images, len);
253        glyphindex = -1;
254        return true;
255    }
256
257
258    public void setFromGlyphVector(FontInfo info, GlyphVector gv,
259                                   float x, float y) {
260        this.x = x;
261        this.y = y;
262        this.lcdRGBOrder = info.lcdRGBOrder;
263        this.lcdSubPixPos = info.lcdSubPixPos;
264        /* A GV may be rendered in different Graphics. It is possible it is
265         * used for one case where LCD text is available, and another where
266         * it is not. Pass in the "info". to ensure get a suitable one.
267         */
268        StandardGlyphVector sgv = StandardGlyphVector.getStandardGV(gv, info);
269        // call before ensureCapacity :-
270        usePositions = sgv.needsPositions(info.devTx);
271        len = sgv.getNumGlyphs();
272        ensureCapacity(len);
273        strikelist = sgv.setupGlyphImages(images,
274                                          usePositions ? positions : null,
275                                          info.devTx);
276        glyphindex = -1;
277    }
278
279    public int[] getBounds() {
280        /* We co-opt the 5 element array that holds per glyph metrics in order
281         * to return the bounds. So a caller must copy the data out of the
282         * array before calling any other methods on this GlyphList
283         */
284        if (glyphindex >= 0) {
285            throw new InternalError("calling getBounds after setGlyphIndex");
286        }
287        if (metrics == null) {
288            metrics = new int[5];
289        }
290        /* gposx and gposy are used to accumulate the advance.
291         * Add 0.5f for consistent rounding to pixel position. */
292        gposx = x + 0.5f;
293        gposy = y + 0.5f;
294        fillBounds(metrics);
295        return metrics;
296    }
297
298    /* This method now assumes "state", so must be called 0->len
299     * The metrics it returns are accumulated on the fly
300     * So it could be renamed "nextGlyph()".
301     * Note that a laid out GlyphVector which has assigned glyph positions
302     * doesn't have this stricture..
303     */
304    public void setGlyphIndex(int i) {
305        glyphindex = i;
306        float gx =
307            StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftXOffset);
308        float gy =
309            StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftYOffset);
310
311        if (usePositions) {
312            metrics[0] = (int)Math.floor(positions[(i<<1)]   + gposx + gx);
313            metrics[1] = (int)Math.floor(positions[(i<<1)+1] + gposy + gy);
314        } else {
315            metrics[0] = (int)Math.floor(gposx + gx);
316            metrics[1] = (int)Math.floor(gposy + gy);
317            /* gposx and gposy are used to accumulate the advance */
318            gposx += StrikeCache.unsafe.getFloat
319                (images[i]+StrikeCache.xAdvanceOffset);
320            gposy += StrikeCache.unsafe.getFloat
321                (images[i]+StrikeCache.yAdvanceOffset);
322        }
323        metrics[2] =
324            StrikeCache.unsafe.getChar(images[i]+StrikeCache.widthOffset);
325        metrics[3] =
326            StrikeCache.unsafe.getChar(images[i]+StrikeCache.heightOffset);
327        metrics[4] =
328            StrikeCache.unsafe.getChar(images[i]+StrikeCache.rowBytesOffset);
329    }
330
331    public int[] getMetrics() {
332        return metrics;
333    }
334
335    public byte[] getGrayBits() {
336        int len = metrics[4] * metrics[3];
337        if (graybits == null) {
338            graybits = new byte[Math.max(len, MINGRAYLENGTH)];
339        } else {
340            if (len > graybits.length) {
341                graybits = new byte[len];
342            }
343        }
344        long pixelDataAddress =
345            StrikeCache.unsafe.getAddress(images[glyphindex] +
346                                          StrikeCache.pixelDataOffset);
347
348        if (pixelDataAddress == 0L) {
349            return graybits;
350        }
351        /* unsafe is supposed to be fast, but I doubt if this loop can beat
352         * a native call which does a getPrimitiveArrayCritical and a
353         * memcpy for the typical amount of image data (30-150 bytes)
354         * Consider a native method if there is a performance problem (which
355         * I haven't seen so far).
356         */
357        for (int i=0; i<len; i++) {
358            graybits[i] = StrikeCache.unsafe.getByte(pixelDataAddress+i);
359        }
360        return graybits;
361    }
362
363    public long[] getImages() {
364        return images;
365    }
366
367    public boolean usePositions() {
368        return usePositions;
369    }
370
371    public float[] getPositions() {
372        return positions;
373    }
374
375    public float getX() {
376        return x;
377    }
378
379    public float getY() {
380        return y;
381    }
382
383    public Object getStrike() {
384        return strikelist;
385    }
386
387    public boolean isSubPixPos() {
388        return lcdSubPixPos;
389    }
390
391    public boolean isRGBOrder() {
392        return lcdRGBOrder;
393    }
394
395    /* There's a reference equality test overhead here, but it allows us
396     * to avoid synchronizing for GL's that will just be GC'd. This
397     * helps MP throughput.
398     */
399    public void dispose() {
400        if (this == reusableGL) {
401            if (graybits != null && graybits.length > MAXGRAYLENGTH) {
402                graybits = null;
403            }
404            usePositions = false;
405            strikelist = null; // remove reference to the strike list
406            inUse.set(false);
407        }
408    }
409
410    /* The value here is for use by the rendering engine as it reflects
411     * the number of glyphs in the array to be blitted. Surrogates pairs
412     * may have two slots (the second of these being a dummy entry of the
413     * invisible glyph), whereas an application client would expect only
414     * one glyph. In other words don't propagate this value up to client code.
415     *
416     * {dlf} an application client should have _no_ expectations about the
417     * number of glyphs per char.  This ultimately depends on the font
418     * technology and layout process used, which in general clients will
419     * know nothing about.
420     */
421    public int getNumGlyphs() {
422        return len;
423    }
424
425    /* We re-do all this work as we iterate through the glyphs
426     * but it seems unavoidable without re-working the Java TextRenderers.
427     */
428    private void fillBounds(int[] bounds) {
429        /* Faster to access local variables in the for loop? */
430        int xOffset = StrikeCache.topLeftXOffset;
431        int yOffset = StrikeCache.topLeftYOffset;
432        int wOffset = StrikeCache.widthOffset;
433        int hOffset = StrikeCache.heightOffset;
434        int xAdvOffset = StrikeCache.xAdvanceOffset;
435        int yAdvOffset = StrikeCache.yAdvanceOffset;
436
437        if (len == 0) {
438            bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0;
439            return;
440        }
441        float bx0, by0, bx1, by1;
442        bx0 = by0 = Float.POSITIVE_INFINITY;
443        bx1 = by1 = Float.NEGATIVE_INFINITY;
444
445        int posIndex = 0;
446        float glx = x + 0.5f;
447        float gly = y + 0.5f;
448        char gw, gh;
449        float gx, gy, gx0, gy0, gx1, gy1;
450        for (int i=0; i<len; i++) {
451            gx = StrikeCache.unsafe.getFloat(images[i]+xOffset);
452            gy = StrikeCache.unsafe.getFloat(images[i]+yOffset);
453            gw = StrikeCache.unsafe.getChar(images[i]+wOffset);
454            gh = StrikeCache.unsafe.getChar(images[i]+hOffset);
455
456            if (usePositions) {
457                gx0 = positions[posIndex++] + gx + glx;
458                gy0 = positions[posIndex++] + gy + gly;
459            } else {
460                gx0 = glx + gx;
461                gy0 = gly + gy;
462                glx += StrikeCache.unsafe.getFloat(images[i]+xAdvOffset);
463                gly += StrikeCache.unsafe.getFloat(images[i]+yAdvOffset);
464            }
465            gx1 = gx0 + gw;
466            gy1 = gy0 + gh;
467            if (bx0 > gx0) bx0 = gx0;
468            if (by0 > gy0) by0 = gy0;
469            if (bx1 < gx1) bx1 = gx1;
470            if (by1 < gy1) by1 = gy1;
471        }
472        /* floor is safe and correct because all glyph widths, heights
473         * and offsets are integers
474         */
475        bounds[0] = (int)Math.floor(bx0);
476        bounds[1] = (int)Math.floor(by0);
477        bounds[2] = (int)Math.floor(bx1);
478        bounds[3] = (int)Math.floor(by1);
479    }
480}
481