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