/* | 
|
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package sun.font;  | 
|
import java.awt.Font;  | 
|
import java.awt.font.GlyphVector;  | 
|
import java.awt.font.FontRenderContext;  | 
|
import sun.java2d.loops.FontInfo;  | 
|
/* | 
|
 * This class represents a list of actual renderable glyphs. | 
|
 * It can be constructed from a number of text sources, representing | 
|
 * the various ways in which a programmer can ask a Graphics2D object | 
|
 * to render some text.  Once constructed, it provides a way of iterating | 
|
 * through the device metrics and graybits of the individual glyphs that | 
|
 * need to be rendered to the screen. | 
|
 * | 
|
 * Note that this class holds pointers to native data which must be | 
|
 * disposed.  It is not marked as finalizable since it is intended | 
|
 * to be very lightweight and finalization is a comparitively expensive | 
|
 * procedure.  The caller must specifically use try{} finally{} to | 
|
 * manually ensure that the object is disposed after use, otherwise | 
|
 * native data structures might be leaked. | 
|
 * | 
|
 * Here is a code sample for using this class: | 
|
 * | 
|
 * public void drawString(String str, FontInfo info, float x, float y) { | 
|
 *     GlyphList gl = GlyphList.getInstance(); | 
|
 *     try { | 
|
 *         gl.setFromString(info, str, x, y); | 
|
 *         int strbounds[] = gl.getBounds(); | 
|
 *         int numglyphs = gl.getNumGlyphs(); | 
|
 *         for (int i = 0; i < numglyphs; i++) { | 
|
 *             gl.setGlyphIndex(i); | 
|
 *             int metrics[] = gl.getMetrics(); | 
|
 *             byte bits[] = gl.getGrayBits(); | 
|
 *             int glyphx = metrics[0]; | 
|
 *             int glyphy = metrics[1]; | 
|
 *             int glyphw = metrics[2]; | 
|
 *             int glyphh = metrics[3]; | 
|
 *             int off = 0; | 
|
 *             for (int j = 0; j < glyphh; j++) { | 
|
 *                 for (int i = 0; i < glyphw; i++) { | 
|
 *                     int dx = glyphx + i; | 
|
 *                     int dy = glyphy + j; | 
|
 *                     int alpha = bits[off++]; | 
|
 *                     drawPixel(alpha, dx, dy); | 
|
 *                 } | 
|
 *             } | 
|
 *         } | 
|
 *     } finally { | 
|
 *         gl.dispose(); | 
|
 *     } | 
|
 * } | 
|
*/  | 
|
public final class GlyphList { | 
|
private static final int MINGRAYLENGTH = 1024;  | 
|
private static final int MAXGRAYLENGTH = 8192;  | 
|
private static final int DEFAULT_LENGTH = 32;  | 
|
int glyphindex;  | 
|
int metrics[];  | 
|
byte graybits[];  | 
|
/* A reference to the strike is needed for the case when the GlyphList  | 
|
* may be added to a queue for batch processing, (e.g. OpenGL) and we need  | 
|
* to be completely certain that the strike is still valid when the glyphs  | 
|
* images are later referenced. This does mean that if such code discards  | 
|
* GlyphList and places only the data it contains on the queue, that the  | 
|
* strike needs to be part of that data held by a strong reference.  | 
|
* In the cases of drawString() and drawChars(), this is a single strike,  | 
|
* although it may be a composite strike. In the case of  | 
|
* drawGlyphVector() it may be a single strike, or a list of strikes.  | 
|
*/  | 
|
Object strikelist; // hold multiple strikes during rendering of complex gv  | 
|
    /* In normal usage, the same GlyphList will get recycled, so | 
|
     * it makes sense to allocate arrays that will get reused along with | 
|
     * it, rather than generating garbage. Garbage will be generated only | 
|
     * in MP envts where multiple threads are executing. Throughput should | 
|
     * still be higher in those cases. | 
|
*/  | 
|
int len = 0;  | 
|
int maxLen = 0;  | 
|
int maxPosLen = 0;  | 
|
int glyphData[];  | 
|
char chData[];  | 
|
long images[];  | 
|
float positions[];  | 
|
float x, y;  | 
|
float gposx, gposy;  | 
|
boolean usePositions;  | 
|
    /* lcdRGBOrder is used only by LCD text rendering. Its here because | 
|
     * the Graphics may have a different hint value than the one used | 
|
     * by a GlyphVector, so it has to be stored here - and is obtained | 
|
     * from the right FontInfo. Another approach would have been to have | 
|
     * install a separate pipe for that case but that's a lot of extra | 
|
     * code when a simple boolean will suffice. The overhead to non-LCD | 
|
     * text is a redundant boolean assign per call. | 
|
*/  | 
|
boolean lcdRGBOrder;  | 
|
    /* | 
|
     * lcdSubPixPos is used only by LCD text rendering. Its here because | 
|
     * the Graphics may have a different hint value than the one used | 
|
     * by a GlyphVector, so it has to be stored here - and is obtained | 
|
     * from the right FontInfo. Its also needed by the code which | 
|
     * calculates glyph positions which already needs to access this | 
|
     * GlyphList and would otherwise need the FontInfo. | 
|
     * This is true only if LCD text and fractional metrics hints | 
|
     * are selected on the graphics. | 
|
     * When this is true and the glyph positions as determined by the | 
|
     * advances are non-integral, it requests adjustment of the positions. | 
|
     * Setting this for surfaces which do not support it through accelerated | 
|
     * loops may cause a slow-down as software loops are invoked instead. | 
|
*/  | 
|
boolean lcdSubPixPos;  | 
|
    /* This scheme creates a singleton GlyphList which is checked out | 
|
     * for use. Callers who find its checked out create one that after use | 
|
     * is discarded. This means that in a MT-rendering environment, | 
|
     * there's no need to synchronise except for that one instance. | 
|
     * Fewer threads will then need to synchronise, perhaps helping | 
|
     * throughput on a MP system. If for some reason the reusable | 
|
     * GlyphList is checked out for a long time (or never returned?) then | 
|
     * we would end up always creating new ones. That situation should not | 
|
     * occur and if if did, it would just lead to some extra garbage being | 
|
     * created. | 
|
*/  | 
|
private static GlyphList reusableGL = new GlyphList();  | 
|
private static boolean inUse;  | 
|
    void ensureCapacity(int len) { | 
|
      /* Note len must not be -ve! only setFromChars should be capable | 
|
       * of passing down a -ve len, and this guards against it. | 
|
*/  | 
|
if (len < 0) {  | 
|
len = 0;  | 
|
}  | 
|
if (usePositions && len > maxPosLen) {  | 
|
positions = new float[len * 2 + 2];  | 
|
maxPosLen = len;  | 
|
}  | 
|
if (maxLen == 0 || len > maxLen) {  | 
|
glyphData = new int[len];  | 
|
chData = new char[len];  | 
|
images = new long[len];  | 
|
maxLen = len;  | 
|
}  | 
|
}  | 
|
    private GlyphList() { | 
|
// ensureCapacity(DEFAULT_LENGTH);  | 
|
}  | 
|
//     private GlyphList(int arraylen) { | 
|
// ensureCapacity(arraylen);  | 
|
// }  | 
|
public static GlyphList getInstance() {  | 
|
        /* The following heuristic is that if the reusable instance is | 
|
         * in use, it probably still will be in a micro-second, so avoid | 
|
         * synchronising on the class and just allocate a new instance. | 
|
         * The cost is one extra boolean test for the normal case, and some | 
|
         * small number of cases where we allocate an extra object when | 
|
         * in fact the reusable one would be freed very soon. | 
|
*/  | 
|
if (inUse) {  | 
|
return new GlyphList();  | 
|
        } else { | 
|
synchronized(GlyphList.class) {  | 
|
if (inUse) {  | 
|
return new GlyphList();  | 
|
                } else { | 
|
inUse = true;  | 
|
return reusableGL;  | 
|
}  | 
|
}  | 
|
}  | 
|
}  | 
|
/* In some cases the caller may be able to estimate the size of  | 
|
* array needed, and it will usually be long enough. This avoids  | 
|
* the unnecessary reallocation that occurs if our default  | 
|
* values are too small. This is useful because this object  | 
|
* will be discarded so the re-allocation overhead is high.  | 
|
*/  | 
|
//     public static GlyphList getInstance(int sz) { | 
|
//      if (inUse) { | 
|
// return new GlyphList(sz);  | 
|
//      } else { | 
|
//          synchronized(GlyphList.class) { | 
|
//              if (inUse) { | 
|
// return new GlyphList();  | 
|
//              } else { | 
|
// inUse = true;  | 
|
// return reusableGL;  | 
|
// }  | 
|
// }  | 
|
// }  | 
|
// }  | 
|
/* GlyphList is in an invalid state until setFrom* method is called.  | 
|
* After obtaining a new GlyphList it is the caller's responsibility  | 
|
* that one of these methods is executed before handing off the  | 
|
* GlyphList  | 
|
*/  | 
|
public boolean setFromString(FontInfo info, String str, float x, float y) {  | 
|
this.x = x;  | 
|
this.y = y;  | 
|
this.strikelist = info.fontStrike;  | 
|
this.lcdRGBOrder = info.lcdRGBOrder;  | 
|
this.lcdSubPixPos = info.lcdSubPixPos;  | 
|
len = str.length();  | 
|
ensureCapacity(len);  | 
|
str.getChars(0, len, chData, 0);  | 
|
return mapChars(info, len);  | 
|
}  | 
|
public boolean setFromChars(FontInfo info, char[] chars, int off, int alen,  | 
|
                                float x, float y) { | 
|
this.x = x;  | 
|
this.y = y;  | 
|
this.strikelist = info.fontStrike;  | 
|
this.lcdRGBOrder = info.lcdRGBOrder;  | 
|
this.lcdSubPixPos = info.lcdSubPixPos;  | 
|
len = alen;  | 
|
if (alen < 0) {  | 
|
len = 0;  | 
|
        } else { | 
|
len = alen;  | 
|
}  | 
|
ensureCapacity(len);  | 
|
System.arraycopy(chars, off, chData, 0, len);  | 
|
return mapChars(info, len);  | 
|
}  | 
|
private final boolean mapChars(FontInfo info, int len) {  | 
|
        /* REMIND.Is it worthwhile for the iteration to convert | 
|
         * chars to glyph ids to directly map to images? | 
|
*/  | 
|
if (info.font2D.getMapper().charsToGlyphsNS(len, chData, glyphData)) {  | 
|
return false;  | 
|
}  | 
|
info.fontStrike.getGlyphImagePtrs(glyphData, images, len);  | 
|
glyphindex = -1;  | 
|
return true;  | 
|
}  | 
|
public void setFromGlyphVector(FontInfo info, GlyphVector gv,  | 
|
                                   float x, float y) { | 
|
this.x = x;  | 
|
this.y = y;  | 
|
this.lcdRGBOrder = info.lcdRGBOrder;  | 
|
this.lcdSubPixPos = info.lcdSubPixPos;  | 
|
        /* A GV may be rendered in different Graphics. It is possible it is | 
|
         * used for one case where LCD text is available, and another where | 
|
         * it is not. Pass in the "info". to ensure get a suitable one. | 
|
*/  | 
|
StandardGlyphVector sgv = StandardGlyphVector.getStandardGV(gv, info);  | 
|
        // call before ensureCapacity :- | 
|
usePositions = sgv.needsPositions(info.devTx);  | 
|
len = sgv.getNumGlyphs();  | 
|
ensureCapacity(len);  | 
|
strikelist = sgv.setupGlyphImages(images,  | 
|
usePositions ? positions : null,  | 
|
info.devTx);  | 
|
glyphindex = -1;  | 
|
}  | 
|
    public int[] getBounds() { | 
|
        /* We co-opt the 5 element array that holds per glyph metrics in order | 
|
         * to return the bounds. So a caller must copy the data out of the | 
|
         * array before calling any other methods on this GlyphList | 
|
*/  | 
|
if (glyphindex >= 0) {  | 
|
throw new InternalError("calling getBounds after setGlyphIndex");  | 
|
}  | 
|
if (metrics == null) {  | 
|
metrics = new int[5];  | 
|
}  | 
|
        /* gposx and gposy are used to accumulate the advance. | 
|
* Add 0.5f for consistent rounding to pixel position. */  | 
|
gposx = x + 0.5f;  | 
|
gposy = y + 0.5f;  | 
|
fillBounds(metrics);  | 
|
return metrics;  | 
|
}  | 
|
    /* This method now assumes "state", so must be called 0->len | 
|
     * The metrics it returns are accumulated on the fly | 
|
     * So it could be renamed "nextGlyph()". | 
|
     * Note that a laid out GlyphVector which has assigned glyph positions | 
|
     * doesn't have this stricture.. | 
|
*/  | 
|
    public void setGlyphIndex(int i) { | 
|
glyphindex = i;  | 
|
if (images[i] == 0L) {  | 
|
metrics[0] = (int)gposx;  | 
|
metrics[1] = (int)gposy;  | 
|
metrics[2] = 0;  | 
|
metrics[3] = 0;  | 
|
metrics[4] = 0;  | 
|
return;  | 
|
}  | 
|
float gx =  | 
|
StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftXOffset);  | 
|
float gy =  | 
|
StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftYOffset);  | 
|
if (usePositions) {  | 
|
metrics[0] = (int)Math.floor(positions[(i<<1)] + gposx + gx);  | 
|
metrics[1] = (int)Math.floor(positions[(i<<1)+1] + gposy + gy);  | 
|
        } else { | 
|
metrics[0] = (int)Math.floor(gposx + gx);  | 
|
metrics[1] = (int)Math.floor(gposy + gy);  | 
|
            /* gposx and gposy are used to accumulate the advance */ | 
|
gposx += StrikeCache.unsafe.getFloat  | 
|
(images[i]+StrikeCache.xAdvanceOffset);  | 
|
gposy += StrikeCache.unsafe.getFloat  | 
|
(images[i]+StrikeCache.yAdvanceOffset);  | 
|
}  | 
|
metrics[2] =  | 
|
StrikeCache.unsafe.getChar(images[i]+StrikeCache.widthOffset);  | 
|
metrics[3] =  | 
|
StrikeCache.unsafe.getChar(images[i]+StrikeCache.heightOffset);  | 
|
metrics[4] =  | 
|
StrikeCache.unsafe.getChar(images[i]+StrikeCache.rowBytesOffset);  | 
|
}  | 
|
    public int[] getMetrics() { | 
|
return metrics;  | 
|
}  | 
|
    public byte[] getGrayBits() { | 
|
int len = metrics[4] * metrics[3];  | 
|
if (graybits == null) {  | 
|
graybits = new byte[Math.max(len, MINGRAYLENGTH)];  | 
|
        } else { | 
|
if (len > graybits.length) {  | 
|
graybits = new byte[len];  | 
|
}  | 
|
}  | 
|
if (images[glyphindex] == 0L) {  | 
|
return graybits;  | 
|
}  | 
|
long pixelDataAddress =  | 
|
StrikeCache.unsafe.getAddress(images[glyphindex] +  | 
|
StrikeCache.pixelDataOffset);  | 
|
if (pixelDataAddress == 0L) {  | 
|
return graybits;  | 
|
}  | 
|
        /* unsafe is supposed to be fast, but I doubt if this loop can beat | 
|
         * a native call which does a getPrimitiveArrayCritical and a | 
|
         * memcpy for the typical amount of image data (30-150 bytes) | 
|
         * Consider a native method if there is a performance problem (which | 
|
         * I haven't seen so far). | 
|
*/  | 
|
for (int i=0; i<len; i++) {  | 
|
graybits[i] = StrikeCache.unsafe.getByte(pixelDataAddress+i);  | 
|
}  | 
|
return graybits;  | 
|
}  | 
|
    public long[] getImages() { | 
|
return images;  | 
|
}  | 
|
    public boolean usePositions() { | 
|
return usePositions;  | 
|
}  | 
|
    public float[] getPositions() { | 
|
return positions;  | 
|
}  | 
|
    public float getX() { | 
|
return x;  | 
|
}  | 
|
    public float getY() { | 
|
return y;  | 
|
}  | 
|
public Object getStrike() {  | 
|
return strikelist;  | 
|
}  | 
|
    public boolean isSubPixPos() { | 
|
return lcdSubPixPos;  | 
|
}  | 
|
    public boolean isRGBOrder() { | 
|
return lcdRGBOrder;  | 
|
}  | 
|
    /* There's a reference equality test overhead here, but it allows us | 
|
     * to avoid synchronizing for GL's that will just be GC'd. This | 
|
     * helps MP throughput. | 
|
*/  | 
|
    public void dispose() { | 
|
if (this == reusableGL) {  | 
|
if (graybits != null && graybits.length > MAXGRAYLENGTH) {  | 
|
graybits = null;  | 
|
}  | 
|
usePositions = false;  | 
|
strikelist = null; // remove reference to the strike list  | 
|
inUse = false;  | 
|
}  | 
|
}  | 
|
    /* The value here is for use by the rendering engine as it reflects | 
|
     * the number of glyphs in the array to be blitted. Surrogates pairs | 
|
     * may have two slots (the second of these being a dummy entry of the | 
|
     * invisible glyph), whereas an application client would expect only | 
|
     * one glyph. In other words don't propagate this value up to client code. | 
|
     * | 
|
     * {dlf} an application client should have _no_ expectations about the | 
|
     * number of glyphs per char.  This ultimately depends on the font | 
|
     * technology and layout process used, which in general clients will | 
|
     * know nothing about. | 
|
*/  | 
|
    public int getNumGlyphs() { | 
|
return len;  | 
|
}  | 
|
    /* We re-do all this work as we iterate through the glyphs | 
|
     * but it seems unavoidable without re-working the Java TextRenderers. | 
|
*/  | 
|
    private void fillBounds(int[] bounds) { | 
|
        /* Faster to access local variables in the for loop? */ | 
|
int xOffset = StrikeCache.topLeftXOffset;  | 
|
int yOffset = StrikeCache.topLeftYOffset;  | 
|
int wOffset = StrikeCache.widthOffset;  | 
|
int hOffset = StrikeCache.heightOffset;  | 
|
int xAdvOffset = StrikeCache.xAdvanceOffset;  | 
|
int yAdvOffset = StrikeCache.yAdvanceOffset;  | 
|
if (len == 0) {  | 
|
bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0;  | 
|
return;  | 
|
}  | 
|
float bx0, by0, bx1, by1;  | 
|
bx0 = by0 = Float.POSITIVE_INFINITY;  | 
|
bx1 = by1 = Float.NEGATIVE_INFINITY;  | 
|
int posIndex = 0;  | 
|
float glx = x + 0.5f;  | 
|
float gly = y + 0.5f;  | 
|
char gw, gh;  | 
|
float gx, gy, gx0, gy0, gx1, gy1;  | 
|
for (int i=0; i<len; i++) {  | 
|
if (images[i] == 0L) {  | 
|
continue;  | 
|
}  | 
|
gx = StrikeCache.unsafe.getFloat(images[i]+xOffset);  | 
|
gy = StrikeCache.unsafe.getFloat(images[i]+yOffset);  | 
|
gw = StrikeCache.unsafe.getChar(images[i]+wOffset);  | 
|
gh = StrikeCache.unsafe.getChar(images[i]+hOffset);  | 
|
if (usePositions) {  | 
|
gx0 = positions[posIndex++] + gx + glx;  | 
|
gy0 = positions[posIndex++] + gy + gly;  | 
|
            } else { | 
|
gx0 = glx + gx;  | 
|
gy0 = gly + gy;  | 
|
glx += StrikeCache.unsafe.getFloat(images[i]+xAdvOffset);  | 
|
gly += StrikeCache.unsafe.getFloat(images[i]+yAdvOffset);  | 
|
}  | 
|
gx1 = gx0 + gw;  | 
|
gy1 = gy0 + gh;  | 
|
if (bx0 > gx0) bx0 = gx0;  | 
|
if (by0 > gy0) by0 = gy0;  | 
|
if (bx1 < gx1) bx1 = gx1;  | 
|
if (by1 < gy1) by1 = gy1;  | 
|
}  | 
|
        /* floor is safe and correct because all glyph widths, heights | 
|
         * and offsets are integers | 
|
*/  | 
|
bounds[0] = (int)Math.floor(bx0);  | 
|
bounds[1] = (int)Math.floor(by0);  | 
|
bounds[2] = (int)Math.floor(bx1);  | 
|
bounds[3] = (int)Math.floor(by1);  | 
|
}  | 
|
}  |