public static Object createScaler() throws ReflectiveOperationException { // these APIs are used to reproduce the specific case I encountered // as closely as possible Font2D font = FontUtilities.getFont2D(new Font("Noto Sans CJK JP Black", 0, 12)); // this is a reconstruction of what happens at the end of a call stack like: // - BasicListUI.updateLayoutState() // - JComponent.getPreferredSize() // - JComponent.getFontMetrics(Font) // - TrueTypeFont.getScaler Constructor<?> constructor = Class .forName("sun.font.T2KFontScaler") .getConstructor(Font2D.class, int.class, boolean.class, int.class); constructor.setAccessible(true); return constructor.newInstance(font, 0, true, 18604592); }
private Font2D getFont2D() { FontManager fm = FontManagerFactory.getInstance(); if (fm.usingPerAppContextComposites() && font2DHandle != null && font2DHandle.font2D instanceof CompositeFont && ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) { return fm.findFont2D(name, style, FontManager.LOGICAL_FALLBACK); } else if (font2DHandle == null) { font2DHandle = fm.findFont2D(name, style, FontManager.LOGICAL_FALLBACK).handle; } /* Do not cache the de-referenced font2D. It must be explicitly * de-referenced to pick up a valid font in the event that the * original one is marked invalid */ return font2DHandle.font2D; }
/** * Indicates whether or not this <code>Font</code> can display a * specified <code>String</code>. For strings with Unicode encoding, * it is important to know if a particular font can display the * string. This method returns an offset into the <code>String</code> * <code>str</code> which is the first character this * <code>Font</code> cannot display without using the missing glyph * code. If the <code>Font</code> can display all characters, -1 is * returned. * @param str a <code>String</code> object * @return an offset into <code>str</code> that points * to the first character in <code>str</code> that this * <code>Font</code> cannot display; or <code>-1</code> if * this <code>Font</code> can display all characters in * <code>str</code>. * @since 1.2 */ public int canDisplayUpTo(String str) { Font2D font2d = getFont2D(); int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); if (font2d.canDisplay(c)) { continue; } if (!Character.isHighSurrogate(c)) { return i; } if (!font2d.canDisplay(str.codePointAt(i))) { return i; } i++; } return -1; }
/** * Indicates whether or not this <code>Font</code> can display the * text specified by the <code>iter</code> starting at * <code>start</code> and ending at <code>limit</code>. * * @param iter a {@link CharacterIterator} object * @param start the specified starting offset into the specified * <code>CharacterIterator</code>. * @param limit the specified ending offset into the specified * <code>CharacterIterator</code>. * @return an offset into <code>iter</code> that points * to the first character in <code>iter</code> that this * <code>Font</code> cannot display; or <code>-1</code> if * this <code>Font</code> can display all characters in * <code>iter</code>. * @since 1.2 */ public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { Font2D font2d = getFont2D(); char c = iter.setIndex(start); for (int i = start; i < limit; i++, c = iter.next()) { if (font2d.canDisplay(c)) { continue; } if (!Character.isHighSurrogate(c)) { return i; } char c2 = iter.next(); // c2 could be CharacterIterator.DONE which is not a low surrogate. if (!Character.isLowSurrogate(c2)) { return i; } if (!font2d.canDisplay(Character.toCodePoint(c, c2))) { return i; } i++; } return -1; }
private Font(File fontFile, int fontFormat, boolean isCopy, CreatedFontTracker tracker) throws FontFormatException { this.createdFont = true; /* Font2D instances created by this method track their font file * so that when the Font2D is GC'd it can also remove the file. */ FontManager fm = FontManagerFactory.getInstance(); Font2D[] fonts = fm.createFont2D(fontFile, fontFormat, false, isCopy, tracker); this.font2DHandle = fonts[0].handle; this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault()); this.style = Font.PLAIN; this.size = 1; this.pointSize = 1f; }
/** * Indicates whether or not this {@code Font} can display a * specified {@code String}. For strings with Unicode encoding, * it is important to know if a particular font can display the * string. This method returns an offset into the {@code String} * {@code str} which is the first character this * {@code Font} cannot display without using the missing glyph * code. If the {@code Font} can display all characters, -1 is * returned. * @param str a {@code String} object * @return an offset into {@code str} that points * to the first character in {@code str} that this * {@code Font} cannot display; or {@code -1} if * this {@code Font} can display all characters in * {@code str}. * @since 1.2 */ public int canDisplayUpTo(String str) { Font2D font2d = getFont2D(); int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); if (font2d.canDisplay(c)) { continue; } if (!Character.isHighSurrogate(c)) { return i; } if (!font2d.canDisplay(str.codePointAt(i))) { return i; } i++; } return -1; }
/** * Indicates whether or not this {@code Font} can display the * text specified by the {@code iter} starting at * {@code start} and ending at {@code limit}. * * @param iter a {@link CharacterIterator} object * @param start the specified starting offset into the specified * {@code CharacterIterator}. * @param limit the specified ending offset into the specified * {@code CharacterIterator}. * @return an offset into {@code iter} that points * to the first character in {@code iter} that this * {@code Font} cannot display; or {@code -1} if * this {@code Font} can display all characters in * {@code iter}. * @since 1.2 */ public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { Font2D font2d = getFont2D(); char c = iter.setIndex(start); for (int i = start; i < limit; i++, c = iter.next()) { if (font2d.canDisplay(c)) { continue; } if (!Character.isHighSurrogate(c)) { return i; } char c2 = iter.next(); // c2 could be CharacterIterator.DONE which is not a low surrogate. if (!Character.isLowSurrogate(c2)) { return i; } if (!font2d.canDisplay(Character.toCodePoint(c, c2))) { return i; } i++; } return -1; }
private Font2D getFont2D() { if (FontManager.usingPerAppContextComposites && font2DHandle != null && font2DHandle.font2D instanceof CompositeFont && ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) { return FontManager.findFont2D(name, style, FontManager.LOGICAL_FALLBACK); } else if (font2DHandle == null) { font2DHandle = FontManager.findFont2D(name, style, FontManager.LOGICAL_FALLBACK).handle; } /* Do not cache the de-referenced font2D. It must be explicitly * de-referenced to pick up a valid font in the event that the * original one is marked invalid */ return font2DHandle.font2D; }