Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/font/GlyphList.java
38829 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.font;2627import java.awt.Font;28import java.awt.font.GlyphVector;29import java.awt.font.FontRenderContext;30import sun.java2d.loops.FontInfo;3132/*33* This class represents a list of actual renderable glyphs.34* It can be constructed from a number of text sources, representing35* the various ways in which a programmer can ask a Graphics2D object36* to render some text. Once constructed, it provides a way of iterating37* through the device metrics and graybits of the individual glyphs that38* need to be rendered to the screen.39*40* Note that this class holds pointers to native data which must be41* disposed. It is not marked as finalizable since it is intended42* to be very lightweight and finalization is a comparitively expensive43* procedure. The caller must specifically use try{} finally{} to44* manually ensure that the object is disposed after use, otherwise45* native data structures might be leaked.46*47* Here is a code sample for using this class:48*49* public void drawString(String str, FontInfo info, float x, float y) {50* GlyphList gl = GlyphList.getInstance();51* try {52* gl.setFromString(info, str, x, y);53* int strbounds[] = gl.getBounds();54* int numglyphs = gl.getNumGlyphs();55* for (int i = 0; i < numglyphs; i++) {56* gl.setGlyphIndex(i);57* int metrics[] = gl.getMetrics();58* byte bits[] = gl.getGrayBits();59* int glyphx = metrics[0];60* int glyphy = metrics[1];61* int glyphw = metrics[2];62* int glyphh = metrics[3];63* int off = 0;64* for (int j = 0; j < glyphh; j++) {65* for (int i = 0; i < glyphw; i++) {66* int dx = glyphx + i;67* int dy = glyphy + j;68* int alpha = bits[off++];69* drawPixel(alpha, dx, dy);70* }71* }72* }73* } finally {74* gl.dispose();75* }76* }77*/78public final class GlyphList {79private static final int MINGRAYLENGTH = 1024;80private static final int MAXGRAYLENGTH = 8192;81private static final int DEFAULT_LENGTH = 32;8283int glyphindex;84int metrics[];85byte graybits[];8687/* A reference to the strike is needed for the case when the GlyphList88* may be added to a queue for batch processing, (e.g. OpenGL) and we need89* to be completely certain that the strike is still valid when the glyphs90* images are later referenced. This does mean that if such code discards91* GlyphList and places only the data it contains on the queue, that the92* strike needs to be part of that data held by a strong reference.93* In the cases of drawString() and drawChars(), this is a single strike,94* although it may be a composite strike. In the case of95* drawGlyphVector() it may be a single strike, or a list of strikes.96*/97Object strikelist; // hold multiple strikes during rendering of complex gv9899/* In normal usage, the same GlyphList will get recycled, so100* it makes sense to allocate arrays that will get reused along with101* it, rather than generating garbage. Garbage will be generated only102* in MP envts where multiple threads are executing. Throughput should103* still be higher in those cases.104*/105int len = 0;106int maxLen = 0;107int maxPosLen = 0;108int glyphData[];109char chData[];110long images[];111float positions[];112float x, y;113float gposx, gposy;114boolean usePositions;115116/* lcdRGBOrder is used only by LCD text rendering. Its here because117* the Graphics may have a different hint value than the one used118* by a GlyphVector, so it has to be stored here - and is obtained119* from the right FontInfo. Another approach would have been to have120* install a separate pipe for that case but that's a lot of extra121* code when a simple boolean will suffice. The overhead to non-LCD122* text is a redundant boolean assign per call.123*/124boolean lcdRGBOrder;125126/*127* lcdSubPixPos is used only by LCD text rendering. Its here because128* the Graphics may have a different hint value than the one used129* by a GlyphVector, so it has to be stored here - and is obtained130* from the right FontInfo. Its also needed by the code which131* calculates glyph positions which already needs to access this132* GlyphList and would otherwise need the FontInfo.133* This is true only if LCD text and fractional metrics hints134* are selected on the graphics.135* When this is true and the glyph positions as determined by the136* advances are non-integral, it requests adjustment of the positions.137* Setting this for surfaces which do not support it through accelerated138* loops may cause a slow-down as software loops are invoked instead.139*/140boolean lcdSubPixPos;141142/* This scheme creates a singleton GlyphList which is checked out143* for use. Callers who find its checked out create one that after use144* is discarded. This means that in a MT-rendering environment,145* there's no need to synchronise except for that one instance.146* Fewer threads will then need to synchronise, perhaps helping147* throughput on a MP system. If for some reason the reusable148* GlyphList is checked out for a long time (or never returned?) then149* we would end up always creating new ones. That situation should not150* occur and if if did, it would just lead to some extra garbage being151* created.152*/153private static GlyphList reusableGL = new GlyphList();154private static boolean inUse;155156157void ensureCapacity(int len) {158/* Note len must not be -ve! only setFromChars should be capable159* of passing down a -ve len, and this guards against it.160*/161if (len < 0) {162len = 0;163}164if (usePositions && len > maxPosLen) {165positions = new float[len * 2 + 2];166maxPosLen = len;167}168169if (maxLen == 0 || len > maxLen) {170glyphData = new int[len];171chData = new char[len];172images = new long[len];173maxLen = len;174}175}176177private GlyphList() {178// ensureCapacity(DEFAULT_LENGTH);179}180181// private GlyphList(int arraylen) {182// ensureCapacity(arraylen);183// }184185public static GlyphList getInstance() {186/* The following heuristic is that if the reusable instance is187* in use, it probably still will be in a micro-second, so avoid188* synchronising on the class and just allocate a new instance.189* The cost is one extra boolean test for the normal case, and some190* small number of cases where we allocate an extra object when191* in fact the reusable one would be freed very soon.192*/193if (inUse) {194return new GlyphList();195} else {196synchronized(GlyphList.class) {197if (inUse) {198return new GlyphList();199} else {200inUse = true;201return reusableGL;202}203}204}205}206207/* In some cases the caller may be able to estimate the size of208* array needed, and it will usually be long enough. This avoids209* the unnecessary reallocation that occurs if our default210* values are too small. This is useful because this object211* will be discarded so the re-allocation overhead is high.212*/213// public static GlyphList getInstance(int sz) {214// if (inUse) {215// return new GlyphList(sz);216// } else {217// synchronized(GlyphList.class) {218// if (inUse) {219// return new GlyphList();220// } else {221// inUse = true;222// return reusableGL;223// }224// }225// }226// }227228/* GlyphList is in an invalid state until setFrom* method is called.229* After obtaining a new GlyphList it is the caller's responsibility230* that one of these methods is executed before handing off the231* GlyphList232*/233234public boolean setFromString(FontInfo info, String str, float x, float y) {235this.x = x;236this.y = y;237this.strikelist = info.fontStrike;238this.lcdRGBOrder = info.lcdRGBOrder;239this.lcdSubPixPos = info.lcdSubPixPos;240len = str.length();241ensureCapacity(len);242str.getChars(0, len, chData, 0);243return mapChars(info, len);244}245246public boolean setFromChars(FontInfo info, char[] chars, int off, int alen,247float x, float y) {248this.x = x;249this.y = y;250this.strikelist = info.fontStrike;251this.lcdRGBOrder = info.lcdRGBOrder;252this.lcdSubPixPos = info.lcdSubPixPos;253len = alen;254if (alen < 0) {255len = 0;256} else {257len = alen;258}259ensureCapacity(len);260System.arraycopy(chars, off, chData, 0, len);261return mapChars(info, len);262}263264private final boolean mapChars(FontInfo info, int len) {265/* REMIND.Is it worthwhile for the iteration to convert266* chars to glyph ids to directly map to images?267*/268if (info.font2D.getMapper().charsToGlyphsNS(len, chData, glyphData)) {269return false;270}271info.fontStrike.getGlyphImagePtrs(glyphData, images, len);272glyphindex = -1;273return true;274}275276277public void setFromGlyphVector(FontInfo info, GlyphVector gv,278float x, float y) {279this.x = x;280this.y = y;281this.lcdRGBOrder = info.lcdRGBOrder;282this.lcdSubPixPos = info.lcdSubPixPos;283/* A GV may be rendered in different Graphics. It is possible it is284* used for one case where LCD text is available, and another where285* it is not. Pass in the "info". to ensure get a suitable one.286*/287StandardGlyphVector sgv = StandardGlyphVector.getStandardGV(gv, info);288// call before ensureCapacity :-289usePositions = sgv.needsPositions(info.devTx);290len = sgv.getNumGlyphs();291ensureCapacity(len);292strikelist = sgv.setupGlyphImages(images,293usePositions ? positions : null,294info.devTx);295glyphindex = -1;296}297298public int[] getBounds() {299/* We co-opt the 5 element array that holds per glyph metrics in order300* to return the bounds. So a caller must copy the data out of the301* array before calling any other methods on this GlyphList302*/303if (glyphindex >= 0) {304throw new InternalError("calling getBounds after setGlyphIndex");305}306if (metrics == null) {307metrics = new int[5];308}309/* gposx and gposy are used to accumulate the advance.310* Add 0.5f for consistent rounding to pixel position. */311gposx = x + 0.5f;312gposy = y + 0.5f;313fillBounds(metrics);314return metrics;315}316317/* This method now assumes "state", so must be called 0->len318* The metrics it returns are accumulated on the fly319* So it could be renamed "nextGlyph()".320* Note that a laid out GlyphVector which has assigned glyph positions321* doesn't have this stricture..322*/323public void setGlyphIndex(int i) {324glyphindex = i;325if (images[i] == 0L) {326metrics[0] = (int)gposx;327metrics[1] = (int)gposy;328metrics[2] = 0;329metrics[3] = 0;330metrics[4] = 0;331return;332}333float gx =334StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftXOffset);335float gy =336StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftYOffset);337338if (usePositions) {339metrics[0] = (int)Math.floor(positions[(i<<1)] + gposx + gx);340metrics[1] = (int)Math.floor(positions[(i<<1)+1] + gposy + gy);341} else {342metrics[0] = (int)Math.floor(gposx + gx);343metrics[1] = (int)Math.floor(gposy + gy);344/* gposx and gposy are used to accumulate the advance */345gposx += StrikeCache.unsafe.getFloat346(images[i]+StrikeCache.xAdvanceOffset);347gposy += StrikeCache.unsafe.getFloat348(images[i]+StrikeCache.yAdvanceOffset);349}350metrics[2] =351StrikeCache.unsafe.getChar(images[i]+StrikeCache.widthOffset);352metrics[3] =353StrikeCache.unsafe.getChar(images[i]+StrikeCache.heightOffset);354metrics[4] =355StrikeCache.unsafe.getChar(images[i]+StrikeCache.rowBytesOffset);356}357358public int[] getMetrics() {359return metrics;360}361362public byte[] getGrayBits() {363int len = metrics[4] * metrics[3];364if (graybits == null) {365graybits = new byte[Math.max(len, MINGRAYLENGTH)];366} else {367if (len > graybits.length) {368graybits = new byte[len];369}370}371if (images[glyphindex] == 0L) {372return graybits;373}374long pixelDataAddress =375StrikeCache.unsafe.getAddress(images[glyphindex] +376StrikeCache.pixelDataOffset);377378if (pixelDataAddress == 0L) {379return graybits;380}381/* unsafe is supposed to be fast, but I doubt if this loop can beat382* a native call which does a getPrimitiveArrayCritical and a383* memcpy for the typical amount of image data (30-150 bytes)384* Consider a native method if there is a performance problem (which385* I haven't seen so far).386*/387for (int i=0; i<len; i++) {388graybits[i] = StrikeCache.unsafe.getByte(pixelDataAddress+i);389}390return graybits;391}392393public long[] getImages() {394return images;395}396397public boolean usePositions() {398return usePositions;399}400401public float[] getPositions() {402return positions;403}404405public float getX() {406return x;407}408409public float getY() {410return y;411}412413public Object getStrike() {414return strikelist;415}416417public boolean isSubPixPos() {418return lcdSubPixPos;419}420421public boolean isRGBOrder() {422return lcdRGBOrder;423}424425/* There's a reference equality test overhead here, but it allows us426* to avoid synchronizing for GL's that will just be GC'd. This427* helps MP throughput.428*/429public void dispose() {430if (this == reusableGL) {431if (graybits != null && graybits.length > MAXGRAYLENGTH) {432graybits = null;433}434usePositions = false;435strikelist = null; // remove reference to the strike list436inUse = false;437}438}439440/* The value here is for use by the rendering engine as it reflects441* the number of glyphs in the array to be blitted. Surrogates pairs442* may have two slots (the second of these being a dummy entry of the443* invisible glyph), whereas an application client would expect only444* one glyph. In other words don't propagate this value up to client code.445*446* {dlf} an application client should have _no_ expectations about the447* number of glyphs per char. This ultimately depends on the font448* technology and layout process used, which in general clients will449* know nothing about.450*/451public int getNumGlyphs() {452return len;453}454455/* We re-do all this work as we iterate through the glyphs456* but it seems unavoidable without re-working the Java TextRenderers.457*/458private void fillBounds(int[] bounds) {459/* Faster to access local variables in the for loop? */460int xOffset = StrikeCache.topLeftXOffset;461int yOffset = StrikeCache.topLeftYOffset;462int wOffset = StrikeCache.widthOffset;463int hOffset = StrikeCache.heightOffset;464int xAdvOffset = StrikeCache.xAdvanceOffset;465int yAdvOffset = StrikeCache.yAdvanceOffset;466467if (len == 0) {468bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0;469return;470}471float bx0, by0, bx1, by1;472bx0 = by0 = Float.POSITIVE_INFINITY;473bx1 = by1 = Float.NEGATIVE_INFINITY;474475int posIndex = 0;476float glx = x + 0.5f;477float gly = y + 0.5f;478char gw, gh;479float gx, gy, gx0, gy0, gx1, gy1;480for (int i=0; i<len; i++) {481if (images[i] == 0L) {482continue;483}484gx = StrikeCache.unsafe.getFloat(images[i]+xOffset);485gy = StrikeCache.unsafe.getFloat(images[i]+yOffset);486gw = StrikeCache.unsafe.getChar(images[i]+wOffset);487gh = StrikeCache.unsafe.getChar(images[i]+hOffset);488489if (usePositions) {490gx0 = positions[posIndex++] + gx + glx;491gy0 = positions[posIndex++] + gy + gly;492} else {493gx0 = glx + gx;494gy0 = gly + gy;495glx += StrikeCache.unsafe.getFloat(images[i]+xAdvOffset);496gly += StrikeCache.unsafe.getFloat(images[i]+yAdvOffset);497}498gx1 = gx0 + gw;499gy1 = gy0 + gh;500if (bx0 > gx0) bx0 = gx0;501if (by0 > gy0) by0 = gy0;502if (bx1 < gx1) bx1 = gx1;503if (by1 < gy1) by1 = gy1;504}505/* floor is safe and correct because all glyph widths, heights506* and offsets are integers507*/508bounds[0] = (int)Math.floor(bx0);509bounds[1] = (int)Math.floor(by0);510bounds[2] = (int)Math.floor(bx1);511bounds[3] = (int)Math.floor(by1);512}513}514515516