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 
  26 package sun.font;
  27 
  28 import java.awt.Font;
  29 import java.awt.font.GlyphVector;
  30 import java.awt.font.FontRenderContext;
  31 import java.util.concurrent.atomic.AtomicBoolean;
  32 import 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  */
  80 public 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 }