Adding Fonts to the Java Runtime

This document explains how to add Asian and other language fonts to the Java Runtime JDK 1.2. More specifically, this document covers the JDK 1.2 special feature for adding these fonts to the Java Runtime. It is very likely that this feature will change in future JDK releases.

At this time, this document describes how to install Japanese, Korean, Chinese, and Traditional Chinese fonts to your system.

The JDK 1.2 release for Win32 platforms supports TrueType and Postscript Type1 fonts. JDK 1.2 for Solaris supports scalable outline fonts that can be handled by an X11 server, such as F3, Type1, and TrueType.

Naming of the font.properties Files

There are several font.properties files that come bundled with the JDK 1.2. You can find these files in the directory ../lib that is beneath the directory where Java is installed. These files contain standard font environment information. The explanations that follow assume that the readers of this document are working in an English environment. In an English environment, the default font.properties file has no suffix on its file name, as follows:
font.properties
However, different operating systems have different fonts installed so there is a provision to read font properties files with the operating system version embedded in the name. For instance, Solaris 2.5.1 does not have support for TrueType fonts so the font properties file, font.properties.5.5.1, will include only F3 fonts. Thus, we first look for a file named:
font.properties.<osVersion>
where <osVersion> is the version returned by System.getProperty("os.version") for most systems. On Windows NT, this method is overridden to return NT4.0 instead of 4.0 to distinguish between NT and 95.

However, if your environment is Japanese, Korean, Chinese, or Traditional Chinese, then you must use the font.properties file that corresponds to your particular environment. These files can be identified by the country or locale suffix that is appended to the file name, as follows:

font.properties.<locale>
where locale is one of:
ja

ko

zh

zh_TW

...
Select the file with the suffix for the particular font that you are interested in. Thus, for Traditional Chinese, you would access the file font.properties.zh_TW.

NOTE: The <locale> is actually comprised of <language>_<region>_<encoding> where

<language> is the string returned from System.getProperty("user.language")

<region> is the string returned from System.getProperty("user.region")

<encoding> is the string returned from System.getProperty("file.encoding")

This font.properties.<locale> name can be augmented by the operating system version also. To sum up, the font properties files are searched in the following order:


font.properties.<language>_<region>_<encoding>.<osVersion>
font.properties.<language>_<region>_<encoding>
font.properties.<language>_<region>.<osVersion>
font.properties.<language>_<region>
font.properties.<language>_<encoding>.<osVersion>
font.properties.<language>_<encoding>
font.properties.<language>_<osVersion>
font.properties.<language>
font.properties.<encoding>.<osVersion>
font.properties.<encoding>
font.properties.<osVersion>
font.properties

Using the font.properties File

You must work with the font.properties file to add fonts to the Java Runtime. The font.properties file is platform- specific. It indicates the fonts that a particular platform uses for its Java virtual fonts. Fonts are grouped by types or classes. Currently, the Java Runtime supports the following classes of fonts:

and the following font styles:

The font.properties file defines certain information about the fonts for your platform. This includes aliases, such as:

alias.timesroman=serif

alias.helvetica=sansserif
NOTE: This is a bad example since timesroman and helvetica are actual font names and in JDK1.2, we no longer alias these names to a virtual font.

It also includes descriptions for the fonts. The descriptions differ between the Win32 and Solaris platforms. Our examples use serif fonts to illustrate how fonts are specified and converted, if necessary. However, the same entries apply to other types of fonts. In general, there are entries in the font properties file that specify the fonts you want to use. These entries have the following format:

   <virtual font name>.<style>.<index number> = <platform font name>, attributes
The virtual font name is the name of the font as recognized by the Java Runtime. The platform font name is the actual name of the font on your platform. For example, Dialog and Serif are Java font names, while Times and Helvetica are the native font names on a Win32 or Solaris platform. The index number specifies the order of searching for matching font glyphs, with zero the highest priority.

In JDK1.2, the full matrix of virtual font name and style must be complete. For example, you must have serif, serif.bold serif.italic, serif.bolditalic. Note that serif> is equivalent to serif.plain. All names in this file are case-insensitive.

For example, in the Solaris font.properties file in JDK1.1, the serif entries are as follows:

 serif.plain.0=-linotype-times-medium-r-normal--*-%d-*-*-p-*-iso8859-1
 serif.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
 serif.2=--symbol-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific

 serif.italic.0=-linotype-times-medium-i-normal--*-%d-*-*-p-*-iso8859-1
 
 serif.bold.0=-linotype-times-bold-r-normal--*-%d-*-*-p-*-iso8859-1

 serif.bolditalic.0=-linotype-times-bold-i-normal--*-%d-*-*-p-*-iso8859-1
As you can see, only the first entry of "serif.plain", "serif.italic", "serif.bold" and "serif.bolditalic" were specified. The second and third entry of the font would default to "serif.1" and "serif.2" in each case (since the same two fonts were used in each of the "serif" fonts styles). However, in the JDK 1.2 font.properties, the entire matrix must be specified:
 serif.0=-linotype-times-medium-r-normal--*-%d-*-*-p-*-iso8859-1
 serif.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
 serif.2=--symbol-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific

 serif.italic.0=-linotype-times-medium-i-normal--*-%d-*-*-p-*-iso8859-1
 serif.italic.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
 serif.italic.2=--symbol-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
	
 serif.bold.0=-linotype-times-bold-r-normal--*-%d-*-*-p-*-iso8859-1
 serif.bold.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
 serif.bold.2=--symbol-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
	 
 serif.bolditalic.0=-linotype-times-bold-i-normal--*-%d-*-*-p-*-iso8859-1
 serif.bolditalic.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
 serif.bolditalic.2=--symbol-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
 
As mentioned earlier, the key value for the plain style, plain does not need to be specified (serif.0 defaults to the plain style), however italic, bold or bolditalic must be specified for those styles.

Adding Asian Fonts to the Java Runtime

There are two steps you must take to use Asian fonts, such as the Japanese font, on an English environment platform.

Step 1: Install the Font

First, you must install the Japanese, Korean, Chinese, or Traditional Chinese font to your system. For Windows platform users, Microsoft delivers these Asian fonts free with the NT4.0 installation CD. Or, you can download these fonts from the Microsoft World Wide Web home page. Solaris users must contact SunSoft to request the Asian outline fonts for Solaris environments.

Step 2: Copy the Font

Once you have installed the fonts on your system, copy the font description that you are interested in to font.properties. The easiest way to add one Asian font is to rename the font.properties.<locale> file to be the new font.properties file. The locale symbol represents the font name that you are interested in. No editing is required when you replace font.properties with font.properties.<locale> because font.properties.<locale> is a superset of font.properties. These are the locale symbols that specify the different font properties files:

Locale Symbols for Fonts
Font Name font.properties Symbol
Japanese ja
Korean ko
Chinese zh
Traditional Chinese zh_TW

Thus, to use the the Korean font, you copy or rename font.properties.ko to font.properties.

Using Multiple Fonts in the Runtime

It is possible to use more than one Asian font in your runtime. To do this, you must edit the font.properties file. This section describes the edits you need to make to the file to use multiple Asian fonts.

Specifying Fonts on Win32 Platform

There are three default serif fonts available on an English language Win32 platform. These fonts are:

In addition, the descriptions for these serif fonts in the font.properties file are as follows:


serif.0=Arial,ANSI_CHARSET

serif.1=WingDings,SYMBOL_CHARSET,NEED_CONVERTED

serif.2=Symbol,SYMBOL_CHARSET,NEED_CONVERTED

These three lines together indicate the indexes for the three serif fonts that are available on this platform. Each line indicates one serif font, followed by the index for that font.

The numbers (0, 1, and 2) that appear after the word serif, such as serif.0, indicate the order in which the font glyphs are searched for a corresponding match with the Unicode, or Java string encoding, codepoint. Thus, if serif.0 and serif.1 both have the glyph that corresponds to the same Unicode codepoint, then the glyph for serif.0 will be used.

The first argument is the face name of the Win32 native font. Each line names a particular font. For example, the line for serif.0 names the font Arial, while the line for serif.2 names the font Symbol.

The second argument takes the form *_CHARSET. In our example, it is either ANSI_CHARSET or SYMBOL_CHARSET. This argument indicates the charset entry of the corresponding font in Win32. (See the Win32 API document for more details.)

The third argument, if present, is NEED_CONVERTED. This argument indicates that the corresponding platform font cannot be accessed with Unicode. When this argument is present, the Java Runtime needs to convert the Unicode string to this font index before attempting to use the glyph for the font. Fonts that have this NEED_CONVERTED argument must have a corresponding fontcharset entry, which indicates the charset converter to use to convert the Unicode string.

In our example, both serif.1 and serif.2 have the NEED_CONVERTED argument. Both have fontcharset entries in the font.properties file, as follows:


fontcharset.serif.1=sun.awt.windows.CharToByteWingDings

fontcharset.serif.2=sun.awt.CharToByteSymbol

The fontcharset entry for serif.1 indicates that, to draw the WingDings glyph, the Unicode string should be converted using the sun.awt.windows.CharToByteWingDings converter. (Recall that the font.properties file has already established the font for serif.1 as WingDings.)

The specification for the charset converter is described later in the section The Charset Converter.

NOTE: In the current implementation of JDK1.2, NEED_CONVERTED is not used.

Font file names in JDK1.2

To reduce initialization time, there is now a way to specify the mapping between logical font name to physical font name. For instance:
filename.Arial=ARIAL.TTF
filename.Arial_Bold=ARIALBD.TTF
filename.Arial_Italic=ARIALI.TTF
filename.Arial_Bold_Italic=ARIALBI.TTF
The first entry shows the mapping between the font name Arial and the physical font name, ARIAL.TTF. The next entries show the mapping for Arial with the different styles applied. This shortens the initialization time since we don't have to open every font file to find a font of that particular name.

Win32 Font Files

The current Win32 JDK build provides the following font properties files:


./lib/font.properties

./lib/font.properties.ar

./lib/font.properties.iw

./lib/font.properties.ja

./lib/font.properties.ko

./lib/font.properties.ru

./lib/font.properties.th

./lib/font.properties.zh

./lib/font.properties.zh.NT4.0

./lib/font.properties.zh_TW

If you need a different font from what is provided, then you must create your own font properties file.

Specifying Fonts on Solaris Platform

In JDK 1.2, the fonts specified in the font.properties file should reference scalable fonts. This does not mean that the scalable font will always be used when a specific font point size is requested however. The way in which X11 works is that given an xlfd string such as

	-adobe-courier-bold-o-normal--10-100-75-75-m-60-iso8859-1

the Xserver will first look for a scalable font that matches the entries found in the xlfd string (for font foundry, font family, style, slant, encoding, etc). However, it then will continue to look for a bitmap font which matches this xlfd string exactly, for this specific pixel/point size (in this case 10 pt). If one is found, then X11 will return the bitmap directly read from the bitmap font file which is used rather than a bitmap generated from the data found in the scalable font file.

For example, the serif font on an English Solaris (2.6+) platform consists of the following fonts:

serif.0=-monotype-times new roman-regular-r---*-%d-*-*-p-*-iso8859-1
serif.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
serif.2=-*-symbol-medium-r-normal-*-*-%d-*-*-p-*-adobe-symbol

serif.italic.0=-monotype-times new roman-regular-i---*-%d-*-*-p-*-iso8859-1
serif.italic.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
serif.italic.2=-*-symbol-medium-r-normal-*-*-%d-*-*-p-*-adobe-symbol

serif.bold.0=-monotype-times new roman-bold-r---*-%d-*-*-p-*-iso8859-1
serif.bold.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
serif.bold.2=-*-symbol-medium-r-normal-*-*-%d-*-*-p-*-adobe-symbol

serif.bolditalic.0=-monotype-times new roman-bold-i---*-%d-*-*-p-*-iso8859-1
serif.bolditalic.1=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
serif.bolditalic.2=-*-symbol-medium-r-normal-*-*-%d-*-*-p-*-adobe-symbol

These lines from the Solaris font.properties file indicate the indexes for serif fonts with different styles. For example, the font whose face name is serif and whose style is plain consists of serif.0, serif.1, and serif.2. In addition, these lines indicate that the serif font with the style italic consists of serif.italic.0, serif.italic.1, and serif.italic.2.

Currently, the index of Solaris (X11) font is not a Unicode index. Because it is not Unicode, the font always needs to be converted. Each entry must have a corresponding fontcharset entry to indicate how it should be converted, as follows:


fontcharset.serif.0=sun.io.CharToByte8859_1 

fontcharset.serif.1=sun.awt.motif.CharToByteX11Dingbats

fontcharset.serif.2=sun.awt.CharToByteSymbol

For example, the line:

fontcharset.serif.0=sun.io.CharToByte8859_1 

indicates that all serif.0 fonts, regardless of whether the type is plain (serif.plain.0), bold (serif.bold.0), italics (serif.italic.0), or bold and italics (serif.bolditalic.0), will be converted using the sun.io.CharToByte8859_1 converter.

Testing for correct xlfd strings in the font.properties files

The reason scalable fonts should be specified however is because Java2D can only perform certain operations on scalable fonts, such as generating outlines. Currently the Java2D code can recognize scalable fonts such as TrueType, Type1 or F3. Therefore, when entering xlfd strings in the font.properties file, look for these types of fonts installed on the system and specify those. TrueType fonts will typically have the file extension of "ttf". Type 1 fonts will have either "pfa" or "pfb" as the extension. F3 fonts will have the extension "f3b". On Solaris 2.6, in "C" locale, with all packages installed, you can find fonts of these formats in:

 
	Type1:    /usr/openwin/lib/X11/fonts/Type1
  	TrueType: /usr/openwin/lib/X11/fonts/TrueType
  	F3:       /usr/openwin/lib/X11/fonts/F3

In other locales, the fonts will be installed in a directory such as /usr/openwin/lib/locale/. For example, in JA locale, under /usr/openwin/lib/locale/ja, there are fonts installed in:

	TrueType: /usr/openwin/lib/locale/ja/X11/fonts/TT
	F3:       /usr/openwin/lib/locale/ja/X11/fonts/F3 

The location of the font files may be different depending on locale (that is, may not always be /usr/openwin/lib/locale/<locale>/X11/fonts), but they are typically under the /usr/openwin/lib/locale/<locale> directory somewhere.

Once the scalable fonts have been located, look at the "fonts.dir" file that will be found in the directory with the scalable font files. This file lists all of the valid xlfd strings for the fonts contained in that directory. For example, in the "fonts.dir" file located in the /usr/openwin/lib/locale/ja/X11/fonts/TT directory, there is an entry like this:

	HG-MinchoL.ttf -ricoh-hg mincho l-medium-r-normal--0-0-0-0-m-0-jisx0208.1983-0

In the xlfd string, you will see 4 consecutive zero (0) values. These indicate the pixel size, point size, resolution x and resolution y values. When copying this xlfd string into a font.properties entry, remember to replace the point size (the second "0") with a "%d" which is later replaced with a specific point size when the font is used. Also, replace the other "0" values with "*" (asterisk) to indicate that any value may match this field. So, for example, if the above font was to be used as entry for the "serif" font specified in the font.properties file, it would look like:

	serif.1=-ricoh-hg mincho l-medium-r-normal--*-%d-*-*-m-*-jisx0208.1983-0

When the font is actually used, the point size specified when the Java "Font" object is created is used (the "%d" is replaced with this value), and the font is initialized for use at that point size.

One way to verify that the xlfd strings that you have entered in the font.properties file are correct is to try and display that font using "xfd". "xfd" is an X11 application in /usr/openwin/bin that displays all of the characters found in a font. To run the application, you specify the font (as an xlfd string). To verify an xlfd entry in a font.properties file, replace the "%d" with a valid point size such as 120 (for 12 pt), 140 (for 14 pt), 160 (for 16 pt), etc. (xlfd point size is 10 times the "pixel size" where "pixel size" is normally thought of as the font point size). So, in the above example, with the "serif.1" entry for a Japanese font.properties file, to verify that this xlfd string is correct, run:

	% xfd -fn "-ricoh-hg mincho l-medium-r-normal--*-140-*-*-m-*-jisx0208.1983-0"

If the xlfd string is incorrect, "xfd" will not display a window, and will exit immediately and print out an error message like this:

	Warning: Cannot convert string "<xlfd string>" to type FontStruct
	xfd:  no font to display

If the xlfd string is correct, a window will appear with all of the characters specified in that font. If there are more than 256 characters, then only the first 256 are displayed, but the user may look through all entries by hitting the "NextPage" button displayed on the application.

Note about scalable fonts

Remember that the fonts specified in the font.properties files must be in one of the formats mentioned above (TrueType, Type1 or F3). If there no fonts installed on the system in those formats, then Java2D will not find any valid fonts so operations like drawString ("some Text") will not work.

Currently there is a bug in JDK1.2 where we do not rotate (or scale or shear) F3 fonts. Thus it is desirable to choose a TrueType font if one exists, rather than an F3 font. There are bugs in the X server for Type1 fonts (more problems in 2.5.1 than 2.6) so it is preferable to avoid Type1 fonts also.

Solaris Font Files

The current Solaris JDK build provides the following font properties files:


./lib/font.properties

./lib/font.properties.5.6

./lib/font.properties.5.7

./lib/font.properties.cs

./lib/font.properties.el

./lib/font.properties.hu

./lib/font.properties.ja

./lib/font.properties.ja.5.6

./lib/font.properties.ko

./lib/font.properties.ko.5.6

./lib/font.properties.ko.5.7

./lib/font.properties.lt

./lib/font.properties.lv

./lib/font.properties.pl

./lib/font.properties.ru

./lib/font.properties.tr

./lib/font.properties.zh_EUC_CN

./lib/font.properties.zh_EUC_CN.5.6

./lib/font.properties.zh_EUC_CN.5.7

./lib/font.properties.zh_TW_Big5

./lib/font.properties.zh_EUC_TW

./lib/psfont.properties.ja

If you need a different font from what is provided, then you must create your own font properties file.

Exclusion ranges

As mentioned in the previous sections, the numbers after the virtual font name indicate the order in which the actual fonts are searched to find the requested glyph. There are sometimes overlapping ranges of glyphs in each of the physical fonts that comprise the virtual font. An exclusion range can be added to limit the range in which glyphs are searched in a physical font.

For example, in the Solaris font.properties.ja file, the following describes a monospaced font:

monospaced.plain.0=-morisawa-gothic medium bbb-medium-r-normal-sans-*-%d-*-*-m-*-jisx0201.1976-0
monospaced.plain.1=-morisawa-gothic medium bbb-medium-r-normal-sans-*-%d-*-*-m-*-jisx0208.1983-0
monospaced.plain.2=-morisawa-gothic medium bbb-medium-r-normal-sans-*-%d-*-*-m-*-jisx0201.1976-0
monospaced.plain.3=-urw-itc zapfdingbats-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
monospaced.plain.4=--symbol-medium-r-normal--*-%d-*-*-p-*-sun-fontspecific
The corresponding exclusion range is as follows:
exclusion.monospaced.0=0080-ffff

Thus, glyphs in the range, Unicode 0x0080 to Unicode 0xffff, are excluded from the first font in the virtual font so the subsequent fonts (monospaced.plain.1, monospaced.plain.2, monospaced.plain.3, monospaced.plain.4) will be searched for those glyphs.

The Charset Converter

The charset converter converts Unicode, or Java string encoding, to the index of the font. For font drawing, the JDK 1.1 Runtime uses the charset converter that is the subclass of sun.io.CharToByteConverter.

To add your own font to your JDK 1.1 Runtime, you need to create a charset converter and specify it in the font.properties file.

The following example illustrates how to add your own platform font to the Java serif font. In this example, your font contains 256 glyphs, which are indexed 0 - 0xff. Your font's glyphs correspond to Unicode 0xe000 - 0xe0ff. This example is divided into two steps. First, you create your fontcharset converter class. Second, you specify your font name and converter class name in the font.properties file file.

Step 1. Create fontcharset Converter

This is the Java code for creating the fontcharset converter.

package mypkg.converter;

import sun.io.CharToByte8859_1;
import sun.io.CharToByteConverter;
import sun.io.ConversionBufferFullException;

public class CharToByteMyFont extends sun.io.CharToByte8859_1 { 

   /*
    * This method indicates the range this font covers.
    */
   public boolean canConvert(char ch) {
      if (ch >= 0xe000 && ch <= 0xe0ff) {
         return true;
      }
      return false;
   }

   /*
    * This method converts the unicode to this font index.
    */
   public int convert(char[] input, int inStart, int inEnd, 
                      byte[] output, int outStart, int outEnd) 
                      throws ConversionBufferFullException {
      int outIndex = outStart; 
      for (int i = inStart; i < inEnd; i++) {
         char ch = input[i];
         if (ch >= 0xe000 && ch <= 0xe0ff) {
            if (outIndex >= outEnd) 
            throw new ConversionBufferFullException();
            output[outIndex++] = (byte)(ch - 0xe000);
         }
      }
      return outIndex - outStart;
   }

   /*
    * This method indicates the charset name for this font.
    */
   public String toString() {
      return "MyFont";
   }
}

Step 2. Add Font and Converter to Properties File

You must first set the font name in the font.properties file. Do this by adding an index entry for the font. For example, for a serif font, add a line that designates the serif font followed by the next sequential index number in the file. The Java Runtime requires that the index numbers for any one font be continuous.

Thus, to add a serif font to our previous example font.properties file, you would insert the following line:

serif.3=<your own font name>
The index number must be the next highest index number in the properties file. In our example file, we have already used serif.0, serif.1, and serif.2. Therefore, the new serif font must be serif.3. Had we used a number that was discontinuous, such as serif.5, the Java Runtime would not use that entry.

Next, you must define the converter for this font. This requires a fontcharset entry for the new font, in this case, serif.3. The following line is the fontcharset entry that uses the converter created in the Java code example:

fontcharset.serif.3=mypkg.converter.CharToByteMyfont
You must also ensure that your new converter is visible to the Java Runtime. To ensure that the Java Runtime can see your converter, your java application classpath must include the class path to the converter. In our example, we must be sure that the class mypkg.converter.CharToByteMyfont is visible to the Java Runtime. The simplest way to do this is to put this class under your $JDK_HOME/classes/myown/package directory.

Debugging font.properties files

The best way to debug a custom font.properties file is by comparing it with an existing file. First, you need to find the correct font.properties file (based on osversion, region, encoding, language). Then if you check the differences between your file and the standard file, the only differences should be the fonts you wish to substitute (and possibly other fields related to the new fonts, such as exclusion ranges).

Next, run a test such as SymbolTest in demo/applets/SymbolTest and see if the standard logical fonts are displayed.