blob: 136613f33c20f2650acc3ca36b3181c0d4824c82 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.font;
27
28import java.awt.Font;
29import java.awt.font.GlyphVector;
30import java.awt.font.FontRenderContext;
31import 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 */
79public 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}