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