OpenJDK: Font Scaler Replacement Project
An encumbrance. This Project became inactive shortly after the feature was delivered into JDK 7 and was subsequently dissolved Oct 2023. Discussion about font rasterization may be found on client-libs-dev.
At this time, the project is essentially complete, as freetype has been implemented as a replacement. Soon we will remove this project and transfer bugs and improvements into the scope of the 2D group.
Java 2D incorporates technology that converts scalable outline fonts to a specified size and fits this outline to a pixel grid to produce a raster for subsequent blitting. Hence the terms font scaling and rasterization.
The goal of this project is to create an open source JDK text rasterization subsystem. The existing implementation was licensed by Sun from a 3rd party and can not be released as open source.
This project is of a temporary nature and will be open until all major objectives are accomplished.
Background
The current font rasteriser is a native library licensed for use by Java 2D. The rasterizer works with Truetype and Type1 font formats, providing a means to obtain bitmap, outline and metrics for a particular glyph in the particular rasterization mode. Supported rasterization modes are: black&white, greyscale antialiasing, and subpixel antialiasing. The raterizer is also capable of performing arbitrary affine transforms and applying style to outlines (e.g. bolding or italicizing). The proprietary implementation fully supports Truetype hinting and limited Type1 hinting.The rasterizer module has tight connections with several other modules. In particular:
- font management subsystem
- Provides higher level API on top of rasterizer (i.e. rasterizer
interface is almost entirely defined by the needs of this
subsystem). Triggers creation of native state and keeps pointers to
native state in the java objects.
This also includes infrastructure such as bitmap caching and communication to the "blitting" code. - text layout engine
- Directly uses rasterizer on the native layer to access some truetype tables fromt the font file. Note that this is independent from rasterization of a glyph.
- java2d disposer
- This is an internal mechanism for disposing of graphics-related resources used by Java2D. The rasterizer relies on it to ensure that native resources are properly released.
Note, that input data is not necessarily valid or well-formed and problems can be hard to detect beforehand. Given that the rasterizer is largely native code, unexpected problems often leads to a crash. Robustness is one of the important requirements, and the current implementation is addresing it on several different levels:
- Initial validity checks are performed by the font management subsystem. Malformed fonts are rejected.
- If a problem is detected in the runtime then the font is
substituted by the default font. The malformed font is then removed
from the list of known fonts.
This is tricky because removing fonts requires deleting native state, and some of the other subsystems may be keeping pointers pointers to it.
Requirements and objectives
The main objectives are:- Provide a reasonable alternative to the proprietary library (feature and quality wise)
- passes JCK
- should allow usage of old rasterizer by commercial JDK.
- should be cross platform
- should be reasonably robust to be used on a variety of targeted platforms
Overall, we are trying to refactor the logic of working with proprietary code in the way which simplifies plugging another implementation of the font rasterizer instead. But we want to minimize changes to other subsystems to avoid risk of introducing incompatibilities.
Approach
We identified freetype as the most viable cross-platform alternative. It supports the required font formats and rasterization modes. Moreover, it is already used by the native desktops on Linux and OpenSolaris.Technically, the native part of rasterizer-related code is split between fontmanager and rasterizer specific library (t2k for proprietary rasterizer). As part of refactoring we separated JNI calls to the rasterizer-specific and shared parts. Most of the rasterizer-specific calls will are performed through implementation of the newly added FontScaler interface.
Note that there are some caveats. In particular, the native text layout engine needs to obtain pointers to certain truetype tables. (There is no need to process these tables. The contract is to return the pointer to the table in the truetype format.)
The current implementation is based on two notions - FontScaler and FontStrike. FontScaler is specific to particular physical font file (or data stream). FontStrike is specific to not just the font file but also to a particular size, style and rasterization mode. There could be more than one strike per same scaler.
This additional context is available (as native object) on every call to the rasterizer library and it is used to set parameters before processing particular request.
We expect that any scaler implementation will handle errors internally. It should throw an exception if the font (i.e. scaler) becomes unusable and make sure native resources are released.
The solution is to use freetype as a separate binary library (and probably use freetype library installed on the platform (if available)). So, hopefully there will be only a few freetype-specific files in the OpenJDK workspace (native glue code and java wrapper (implementation of FontScaler)).
Issues
We do not expect freetype to be identical in behaviour to the existing rasterizer, Eg,- glyph images may differ
- metrics may differ
- set of displayable glyphs may differ
Status
At this time, the project is essentially complete, as freetype has been implemented as a replacement. Soon we will remove this project and transfer bugs and improvements into the scope of the 2D group.
How to contribute?
You can help by:
- participating in the discussions on the mailing list (font-scaler-dev(at)openjdk.org)
- testing and reporting bugs
- suggesting code improvements.
- improving or suggesting improvements to freetype developers
Note that this project uses OpenJDK contribution rules. Please see them for further details.
Community
- Mailing lists