244 private static final int MAXRECENT = 5;
245 private static final FontDesignMetrics[]
246 recentMetrics = new FontDesignMetrics[MAXRECENT];
247 private static int recentIndex = 0;
248
249 public static FontDesignMetrics getMetrics(Font font) {
250 return getMetrics(font, getDefaultFrc());
251 }
252
253 public static FontDesignMetrics getMetrics(Font font,
254 FontRenderContext frc) {
255
256
257 /* When using alternate composites, can't cache based just on
258 * the java.awt.Font. Since this is rarely used and we can still
259 * cache the physical fonts, its not a problem to just return a
260 * new instance in this case.
261 * Note that currently Swing native L&F composites are not handled
262 * by this code as they use the metrics of the physical anyway.
263 */
264 if (FontManager.maybeUsingAlternateCompositeFonts() &&
265 FontManager.getFont2D(font) instanceof CompositeFont) {
266 return new FontDesignMetrics(font, frc);
267 }
268
269 FontDesignMetrics m = null;
270 KeyReference r;
271
272 /* There are 2 possible keys used to perform lookups in metricsCache.
273 * If the FRC is set to all defaults, we just use the font as the key.
274 * If the FRC is non-default in any way, we construct a hybrid key
275 * that combines the font and FRC.
276 */
277 boolean usefontkey = frc.equals(getDefaultFrc());
278
279 if (usefontkey) {
280 r = metricsCache.get(font);
281 } else /* use hybrid key */ {
282 // NB synchronization is not needed here because of updates to
283 // the metrics cache but is needed for the shared key.
284 synchronized (MetricsKey.class) {
285 MetricsKey.key.init(font, frc);
336
337 /* private to enable caching - call getMetrics() instead. */
338 private FontDesignMetrics(Font font, FontRenderContext frc) {
339 super(font);
340 this.font = font;
341 this.frc = frc;
342
343 this.isAntiAliased = frc.isAntiAliased();
344 this.usesFractionalMetrics = frc.usesFractionalMetrics();
345
346 frcTx = frc.getTransform();
347
348 matrix = new double[4];
349 initMatrixAndMetrics();
350
351 initAdvCache();
352 }
353
354 private void initMatrixAndMetrics() {
355
356 Font2D font2D = FontManager.getFont2D(font);
357 fontStrike = font2D.getStrike(font, frc);
358 StrikeMetrics metrics = fontStrike.getFontMetrics();
359 this.ascent = metrics.getAscent();
360 this.descent = metrics.getDescent();
361 this.leading = metrics.getLeading();
362 this.maxAdvance = metrics.getMaxAdvance();
363
364 devmatrix = new double[4];
365 frcTx.getMatrix(devmatrix);
366 }
367
368 private void initAdvCache() {
369 advCache = new float[256];
370 // 0 is a valid metric so force it to -1
371 for (int i = 0; i < 256; i++) {
372 advCache[i] = UNKNOWN_WIDTH;
373 }
374 }
375
376 private void readObject(ObjectInputStream in) throws IOException,
456 }
457
458 public int stringWidth(String str) {
459
460 float width = 0;
461 if (font.hasLayoutAttributes()) {
462 /* TextLayout throws IAE for null, so throw NPE explicitly */
463 if (str == null) {
464 throw new NullPointerException("str is null");
465 }
466 if (str.length() == 0) {
467 return 0;
468 }
469 width = new TextLayout(str, font, frc).getAdvance();
470 } else {
471 int length = str.length();
472 for (int i=0; i < length; i++) {
473 char ch = str.charAt(i);
474 if (ch < 0x100) {
475 width += getLatinCharWidth(ch);
476 } else if (FontManager.isNonSimpleChar(ch)) {
477 width = new TextLayout(str, font, frc).getAdvance();
478 break;
479 } else {
480 width += handleCharWidth(ch);
481 }
482 }
483 }
484
485 return (int) (0.5 + width);
486 }
487
488 public int charsWidth(char data[], int off, int len) {
489
490 float width = 0;
491 if (font.hasLayoutAttributes()) {
492 if (len == 0) {
493 return 0;
494 }
495 String str = new String(data, off, len);
496 width = new TextLayout(str, font, frc).getAdvance();
497 } else {
498 /* Explicit test needed to satisfy superclass spec */
499 if (len < 0) {
500 throw new IndexOutOfBoundsException("len="+len);
501 }
502 int limit = off + len;
503 for (int i=off; i < limit; i++) {
504 char ch = data[i];
505 if (ch < 0x100) {
506 width += getLatinCharWidth(ch);
507 } else if (FontManager.isNonSimpleChar(ch)) {
508 String str = new String(data, off, len);
509 width = new TextLayout(str, font, frc).getAdvance();
510 break;
511 } else {
512 width += handleCharWidth(ch);
513 }
514 }
515 }
516
517 return (int) (0.5 + width);
518 }
519
520 /**
521 * Gets the advance widths of the first 256 characters in the
522 * <code>Font</code>. The advance is the
523 * distance from the leftmost point to the rightmost point on the
524 * character's baseline. Note that the advance of a
525 * <code>String</code> is not necessarily the sum of the advances
526 * of its characters.
527 * @return an array storing the advance widths of the
|
244 private static final int MAXRECENT = 5;
245 private static final FontDesignMetrics[]
246 recentMetrics = new FontDesignMetrics[MAXRECENT];
247 private static int recentIndex = 0;
248
249 public static FontDesignMetrics getMetrics(Font font) {
250 return getMetrics(font, getDefaultFrc());
251 }
252
253 public static FontDesignMetrics getMetrics(Font font,
254 FontRenderContext frc) {
255
256
257 /* When using alternate composites, can't cache based just on
258 * the java.awt.Font. Since this is rarely used and we can still
259 * cache the physical fonts, its not a problem to just return a
260 * new instance in this case.
261 * Note that currently Swing native L&F composites are not handled
262 * by this code as they use the metrics of the physical anyway.
263 */
264 SunFontManager fm = SunFontManager.getInstance();
265 if (fm.maybeUsingAlternateCompositeFonts() &&
266 FontUtilities.getFont2D(font) instanceof CompositeFont) {
267 return new FontDesignMetrics(font, frc);
268 }
269
270 FontDesignMetrics m = null;
271 KeyReference r;
272
273 /* There are 2 possible keys used to perform lookups in metricsCache.
274 * If the FRC is set to all defaults, we just use the font as the key.
275 * If the FRC is non-default in any way, we construct a hybrid key
276 * that combines the font and FRC.
277 */
278 boolean usefontkey = frc.equals(getDefaultFrc());
279
280 if (usefontkey) {
281 r = metricsCache.get(font);
282 } else /* use hybrid key */ {
283 // NB synchronization is not needed here because of updates to
284 // the metrics cache but is needed for the shared key.
285 synchronized (MetricsKey.class) {
286 MetricsKey.key.init(font, frc);
337
338 /* private to enable caching - call getMetrics() instead. */
339 private FontDesignMetrics(Font font, FontRenderContext frc) {
340 super(font);
341 this.font = font;
342 this.frc = frc;
343
344 this.isAntiAliased = frc.isAntiAliased();
345 this.usesFractionalMetrics = frc.usesFractionalMetrics();
346
347 frcTx = frc.getTransform();
348
349 matrix = new double[4];
350 initMatrixAndMetrics();
351
352 initAdvCache();
353 }
354
355 private void initMatrixAndMetrics() {
356
357 Font2D font2D = FontUtilities.getFont2D(font);
358 fontStrike = font2D.getStrike(font, frc);
359 StrikeMetrics metrics = fontStrike.getFontMetrics();
360 this.ascent = metrics.getAscent();
361 this.descent = metrics.getDescent();
362 this.leading = metrics.getLeading();
363 this.maxAdvance = metrics.getMaxAdvance();
364
365 devmatrix = new double[4];
366 frcTx.getMatrix(devmatrix);
367 }
368
369 private void initAdvCache() {
370 advCache = new float[256];
371 // 0 is a valid metric so force it to -1
372 for (int i = 0; i < 256; i++) {
373 advCache[i] = UNKNOWN_WIDTH;
374 }
375 }
376
377 private void readObject(ObjectInputStream in) throws IOException,
457 }
458
459 public int stringWidth(String str) {
460
461 float width = 0;
462 if (font.hasLayoutAttributes()) {
463 /* TextLayout throws IAE for null, so throw NPE explicitly */
464 if (str == null) {
465 throw new NullPointerException("str is null");
466 }
467 if (str.length() == 0) {
468 return 0;
469 }
470 width = new TextLayout(str, font, frc).getAdvance();
471 } else {
472 int length = str.length();
473 for (int i=0; i < length; i++) {
474 char ch = str.charAt(i);
475 if (ch < 0x100) {
476 width += getLatinCharWidth(ch);
477 } else if (FontUtilities.isNonSimpleChar(ch)) {
478 width = new TextLayout(str, font, frc).getAdvance();
479 break;
480 } else {
481 width += handleCharWidth(ch);
482 }
483 }
484 }
485
486 return (int) (0.5 + width);
487 }
488
489 public int charsWidth(char data[], int off, int len) {
490
491 float width = 0;
492 if (font.hasLayoutAttributes()) {
493 if (len == 0) {
494 return 0;
495 }
496 String str = new String(data, off, len);
497 width = new TextLayout(str, font, frc).getAdvance();
498 } else {
499 /* Explicit test needed to satisfy superclass spec */
500 if (len < 0) {
501 throw new IndexOutOfBoundsException("len="+len);
502 }
503 int limit = off + len;
504 for (int i=off; i < limit; i++) {
505 char ch = data[i];
506 if (ch < 0x100) {
507 width += getLatinCharWidth(ch);
508 } else if (FontUtilities.isNonSimpleChar(ch)) {
509 String str = new String(data, off, len);
510 width = new TextLayout(str, font, frc).getAdvance();
511 break;
512 } else {
513 width += handleCharWidth(ch);
514 }
515 }
516 }
517
518 return (int) (0.5 + width);
519 }
520
521 /**
522 * Gets the advance widths of the first 256 characters in the
523 * <code>Font</code>. The advance is the
524 * distance from the leftmost point to the rightmost point on the
525 * character's baseline. Note that the advance of a
526 * <code>String</code> is not necessarily the sum of the advances
527 * of its characters.
528 * @return an array storing the advance widths of the
|