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 }