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 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 it 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 StrikeCache.unsafe.getAddress(images[glyphindex] + 366 StrikeCache.pixelDataOffset); 367 368 if (pixelDataAddress == 0L) { 369 return graybits; 370 } 371 /* unsafe is supposed to be fast, but I doubt if this loop can beat 372 * a native call which does a getPrimitiveArrayCritical and a 373 * memcpy for the typical amount of image data (30-150 bytes) 374 * Consider a native method if there is a performance problem (which 375 * I haven't seen so far). 376 */ 377 for (int i=0; i<len; i++) { 378 graybits[i] = StrikeCache.unsafe.getByte(pixelDataAddress+i); 379 } 380 return graybits; 381 } 382 383 public long[] getImages() { 384 return images; 385 } 386 387 public boolean usePositions() { 388 return usePositions; 389 } 390 391 public float[] getPositions() { 392 return positions; 393 } 394 395 public float getX() { 396 return x; 397 } 398 399 public float getY() { 400 return y; 401 } 402 403 public Object getStrike() { 404 return strikelist; 405 } 406 407 public boolean isSubPixPos() { 408 return lcdSubPixPos; 409 } 410 411 public boolean isRGBOrder() { 412 return lcdRGBOrder; 413 } 414 415 /* There's a reference equality test overhead here, but it allows us 416 * to avoid synchronizing for GL's that will just be GC'd. This 417 * helps MP throughput. 418 */ 419 public void dispose() { 420 if (this == reusableGL) { 421 if (graybits != null && graybits.length > MAXGRAYLENGTH) { 422 graybits = null; 423 } 424 usePositions = false; 425 strikelist = null; // remove reference to the strike list 426 inUse = false; 427 } 428 } 429 430 /* The value here is for use by the rendering engine as it reflects 431 * the number of glyphs in the array to be blitted. Surrogates pairs 432 * may have two slots (the second of these being a dummy entry of the 433 * invisible glyph), whereas an application client would expect only 434 * one glyph. In other words don't propagate this value up to client code. 435 * 436 * {dlf} an application client should have _no_ expectations about the 437 * number of glyphs per char. This ultimately depends on the font 438 * technology and layout process used, which in general clients will 439 * know nothing about. 440 */ 441 public int getNumGlyphs() { 442 return len; 443 } 444 445 /* We re-do all this work as we iterate through the glyphs 446 * but it seems unavoidable without re-working the Java TextRenderers. 447 */ 448 private void fillBounds(int[] bounds) { 449 /* Faster to access local variables in the for loop? */ 450 int xOffset = StrikeCache.topLeftXOffset; 451 int yOffset = StrikeCache.topLeftYOffset; 452 int wOffset = StrikeCache.widthOffset; 453 int hOffset = StrikeCache.heightOffset; 454 int xAdvOffset = StrikeCache.xAdvanceOffset; 455 int yAdvOffset = StrikeCache.yAdvanceOffset; 456 457 if (len == 0) { 458 bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0; 459 return; 460 } 461 float bx0, by0, bx1, by1; 462 bx0 = by0 = Float.POSITIVE_INFINITY; 463 bx1 = by1 = Float.NEGATIVE_INFINITY; 464 465 int posIndex = 0; 466 float glx = x + 0.5f; 467 float gly = y + 0.5f; 468 char gw, gh; 469 float gx, gy, gx0, gy0, gx1, gy1; 470 for (int i=0; i<len; i++) { 471 gx = StrikeCache.unsafe.getFloat(images[i]+xOffset); 472 gy = StrikeCache.unsafe.getFloat(images[i]+yOffset); 473 gw = StrikeCache.unsafe.getChar(images[i]+wOffset); 474 gh = StrikeCache.unsafe.getChar(images[i]+hOffset); 475 476 if (usePositions) { 477 gx0 = positions[posIndex++] + gx + glx; 478 gy0 = positions[posIndex++] + gy + gly; 479 } else { 480 gx0 = glx + gx; 481 gy0 = gly + gy; 482 glx += StrikeCache.unsafe.getFloat(images[i]+xAdvOffset); 483 gly += StrikeCache.unsafe.getFloat(images[i]+yAdvOffset); 484 } 485 gx1 = gx0 + gw; 486 gy1 = gy0 + gh; 487 if (bx0 > gx0) bx0 = gx0; 488 if (by0 > gy0) by0 = gy0; 489 if (bx1 < gx1) bx1 = gx1; 490 if (by1 < gy1) by1 = gy1; 491 } 492 /* floor is safe and correct because all glyph widths, heights 493 * and offsets are integers 494 */ 495 bounds[0] = (int)Math.floor(bx0); 496 bounds[1] = (int)Math.floor(by0); 497 bounds[2] = (int)Math.floor(bx1); 498 bounds[3] = (int)Math.floor(by1); 499 } 500 }