JDK-4950815 : JEDITORPANE DOESN'T USE CREATED FONTS
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2003-11-07
  • Updated: 2003-11-19
  • Resolved: 2003-11-19
Related Reports
Relates :  
Relates :  
Description

Name: pa48320			Date: 11/07/2003

Pass some ttf font files on the command line to the included Java program.  (Use font files which aren't otherwise installed.)  In Java 1.4.1 (specifically 1.4.1_05-b01), both the local fonts and the fonts loaded from files are displayed.  In Java 1.5, the local fonts show up, but all of the fonts loaded from disk display as Ariel.

Interestingly, if the code creating the JEditorPane instance for the local fonts (lines 94-95) are moved prior to the createFont calls (before line 56, for example), then this fails in 1.4.1 as well.

In spite of various attempts at re-ordering the code and even not displaying the installed fonts, I cannot seem to get the Java 1.5 version of JEditorPane to use font info.

Frequency: always

Workaround: (none) Don't use JEditorPane to display fonts.  JLabel is able to display a created font in 1.5.

Severity: (medium?) some progress possible


----- begin FontView5.java -----
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;

public class FontView5
{
	private static final String SAMPLE = "The quick brown fox jumped over the lazy dog.";
	private static final char[] SAMPLE_CHARS = nonWhiteCharacterSet(SAMPLE);

	private static char[] nonWhiteCharacterSet(String text) {
		Set set = new TreeSet();

		int n = text.length();
		for (int i = 0; i < n; i++) {
			char c = text.charAt(i);
			if ( Character.isWhitespace(c) ) continue;

			set.add( new Character(c) );
		}

		n = set.size();
		if (n <= 0) return null;

		char[] rc = new char [n];
		Iterator it = set.iterator();
		for (int i = 0; i < n; i++)
			rc[i] = ( (Character) it.next() ).charValue();
		return rc;
	}

	public static void main(String[] args)
	{
		if ( (args == null) || (args.length <= 0) || (args[0] == null) ) {
			System.out.println("usage: <truetype font file>+");
			System.exit(1);
			return;
		}


		// grab list of local fonts before defining any from disk files
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		String[] familyNames = ge.getAvailableFontFamilyNames();
		Set localFontNames = new HashSet();
		String localTitle = "Local fonts";
		if ( (familyNames != null) && (familyNames.length > 0) ) {
			for (int i = 0; i < familyNames.length; i++)
				localFontNames.add( familyNames[i] );
		} else localTitle = "(no) " + localTitle;



		Set loadedFontNames = new TreeSet(); // family names (not font names)
		Set files = new HashSet();

		for (int i = 0; i < args.length; i++) {
			String fname = args[i];
			File file = new File(fname);
			if ( !files.add(file) ) {
				System.out.println("duplicate file: " + file);
				continue;
			}

			Font f;
			try {	f = readFontFile(file);	}
			catch (Exception ex) {
				System.out.println("unable to read font " + file);
				ex.printStackTrace();
				continue;
			}

			if ( !canDisplayAny(f, SAMPLE_CHARS) ) {
				System.out.println("skipping font " + f.getFontName() + " (" + file
					+ ") because it cannot display any of the characters in the sample text");
				continue;
			}

			loadedFontNames.add( f.getFamily() );
		}

		if (loadedFontNames.size() <= 0) {
			System.out.println("No fonts successfully read");
			System.exit(2);
			return;
		}


		String html = generateHTML(loadedFontNames, "loaded fonts");
		JEditorPane loaded = new JEditorPane("text/html", html);

		JEditorPane local = new JEditorPane( "text/html"
			, generateHTML(localFontNames, localTitle) );

		JPanel content = new JPanel( new GridLayout(0, 2) );
		content.add( new JScrollPane(local) );
		content.add( new JScrollPane(loaded) );

		JFrame f = new JFrame("FontView5");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(640, 480);
		//f.setContentPane( new JScrollPane(content) );
		f.setContentPane(content);
		f.setVisible(true);
	}

	private static Font readFontFile(File f)
		throws IOException, FontFormatException
	{
		InputStream s = null;
		try {
			s = new FileInputStream(f);
			BufferedInputStream b = new BufferedInputStream(s);
			return Font.createFont(Font.TRUETYPE_FONT, b);
		} finally {
			if (s != null) {
				try {	s.close();	}
				catch (IOException ioe) {}
			}
		}
	}

	private static boolean canDisplayAny(Font f, char[] chars) {
		for (int i = 0; i < chars.length; i++) {
			if ( f.canDisplay( chars[i] ) )
				return true;
		}
		return false;
	}



	private static String generateHTML(Set fontNames, String heading) {
		StringWriter rc = new StringWriter();
		PrintWriter pw = new PrintWriter(rc);

		pw.println("<html>");
		pw.println("<head>");
		pw.println("<title>font list</title>");
		pw.println("<style>");
		pw.println("body {	font-size: 12pt;	}");
		pw.println("th {	text-align: left;	}");
		pw.println(".sample {	font-size: 24pt;	}");
		pw.println("</style>");
		pw.println("</head>");

		pw.println("<body>");

		if ( (heading != null) && (heading.trim().length() > 0) )
			pw.println("<h1>" + heading + "</h1>");

		pw.println("<p>");

		if (fontNames.size() <= 0) {
			pw.println("no font family names");
		} else {
			pw.println("<table border=\"1\">");
//			pw.println("<thead>");
//			pw.println("<tr><th>Family name</th><th>sample</th></tr>");
//			pw.println("</thead>");
//			pw.println("<tbody>");
			pw.println("<tr><th>Family name</th><th>sample</th></tr>");

			Iterator it = new TreeSet(fontNames).iterator();
			while ( it.hasNext() ) {
				pw.println("<tr>");

				String fontName = (String) it.next();

				// col 1
				pw.println("\t<td>" + fontName + "</td>");

				// col 2
				pw.print("\t<td class=\"sample\"><font face=\"" + fontName + "\">");
				pw.print(SAMPLE);
				pw.println("</font></td>");

				pw.println("</tr>");
			}
//			pw.println("</tbody>");
			pw.println("</table>");
		}

		pw.println("</p>");
		pw.println("</body>");
		pw.println("</html>");

		pw.flush();
		return rc.toString();
	}
}
----- end FontView5.java -----

======================================================================

Comments
EVALUATION Name: anR10225 Date: 11/18/2003 In 1.4.2 (b25) once a font has been loaded by Font.createFont() it is added to the list of available fonts and can be accessed via its name. In 1.5.0 this effect disappears. Here is the simplified test case : File file = new File("D:/Swing/temp/CORONET.TTF"); Font.createFont(Font.TRUETYPE_FONT, new BufferedInputStream(new FileInputStream(file))); Font f = Font.decode("coronet"); System.out.println(f); 1.4.2 output: java.awt.Font[family=Coronet,name=coronet,style=plain,size=12] 1.5.0 output: java.awt.Font[family=Dialog,name=coronet,style=plain,size=12] To reproduce make sure you have no Coronet system font. ====================================================================== Name: anR10225 Date: 11/19/2003 The side effect of creating a font by Font.createFont() in 1.4.2 was adding this font into the list of available fonts of GraphicEnvironment. This behavior was considered to be incorrect (refer the bug #4750542) and was fixed in 1.5.0. The list of available fonts of GraphicEnvironment couldn't be changed according to the Java2D API design. The idea of using custom fonts in the JEditorPane is to maintain your own list of the fonts loaded and overriding StyleSheet.getFont() method return whether standard Font available via GraphicEnvironment or your own loaded Font by examining attributes passed to the method. Close this as not a bug. ======================================================================
11-06-2004

WORK AROUND Name: pa48320 Date: 11/07/2003 Workaround: (none) Don't use JEditorPane to display fonts. JLabel is able to display a created font in 1.5. ======================================================================
11-06-2004