Welcome to the F R E E T Y P E P R O J E C T The FREE TrueType Font Engine Copyright 1996 David Turner This document is an introduction to the FreeType project, a very efficient and fast, though portable, TrueType font rendering engine *freely available*. The reader's good knowledge of the TrueType Font specification is not required, though being a indeniable "plus". --------------------------------------------------------------------- TABLE OF CONTENTS : Introduction : I. Engine Design Goals : 1. Easy Maintenance 2. System Independance 3. Reliability 4. High Quality 5. Speed ! II. Engine Architecture : 1. Component Hierarchy 2. Runtime Execution II. Internals : 1. Engine Memory Management. 2. Rasterizer mechanics. 3. Interpreting TrueType opcodes. III. Engine Characteristics : 1. Differences found between TrueType specs and real-world font files. 2. Engine's behaviour with incorrect font files or glyphs. IV. What to do now ? : 1. Debug the whole interpreter.. 2. Add more character-oriented functions. 3. Porting considerations ( IMPORTANT ). -------------------------------------------------------------------- Introduction : -------------- Managing fonts can be a serious task ! In these good old days when all we had were dot-matrix printers, it was common practice to use bitmap files to print and/or display text. This could lead to the use of a lot of disk space, as each pointsize of a same typeface had to be bitmapped in a separate file. Moreover, it made creating new typefaces incredibly slow and painful, as the file for each size had to be generated. The first system which included automaticaly-computed bitmap files from a description was undoubtly Metafonts, part of the TeX package from Donald Knuth, which is still widely used in academia and research nowadays ! Metafonts is a font specification language and bitmap generator. It produces the bitmaps that the TeX program uses to generate its 'DVI' ( DeVice-Independent ) files. Unlike modern systems, it's a stand-alone product that is not integrated into TeX, and does not work "on-demand". It must be run by the user before any TeX processing to generate the bitmap files. Metafonts was a masterpiece at the time it was invented, and in many ways, it still is, with features that have yet to come to modern systems ( like family-generation : give him the description of an A, and it will generate all others letters of the alphabet with the same style !! ). Metafonts did not resolve the disk space problem, it just automated the bitmap generation and made it fairly easy. Meanwhile, the advent of laser printers and graphical environments urged the need for a suitable 'on-demand' font rendering system. Not surprisingly, Adobe which led the laser revolution with its Postcript printing language, proposed the Type 1 Font Format. This format is based on a vector specification of each glyph as well as the presence of small instructions, called 'hinting', to help preserve some aesthetics properties of the fonts when rendering to small sizes ( like keeping the width of the two vertical bars of a H the same, for example ). As Type 1 was one of Postcript's key points, laser printers became the choice of quality of many, as the quality of the printed texts out-performed by far dot-matrix. A Type 1 font was typically downloaded into the laser printer's memory, where all rendering calculations took place; there was no need for extra work from the computer. This is why early windowing systems started to allow printing with Type 1 fonts on Postcript printers, while keeping their weak bitmap files for display. Moreover, Adobe refused to license the font rendering code to Apple and Microsoft. The two software giants decided then to team up to create a new font technology, today known as 'TrueType'. Few weeks after they had agreed, Adobe announced ATM ( Adobe Type Manager ), a product that allowed ( and still does ! ) Macintosh and Windows owner to display Type 1 fonts and (at last) do some real WYSIWYG. What is funny is that neither products were even written on paper at that time. Adobe benefited from the vast momentum of already available Type 1 fonts, most Typeface designers having been converted to their format. It is still widely used in corporations where the quality of the fonts used is important ( Publishing, Advertising, .. ), while TrueType, which finally came out and became part of System 7 and Windows 3.0, is a source of free or cheap low-level fonts for a lot of every-day jobs. Though, more and more new fonts are proposed in both formats today. So the question is : why make a TrueType engine rather than a Type 1 one ? Well, few years ago, if someone wanted some good quality fonts, one had to purchase them in Type 1 format from professional designers. This seems not to be so true today, after we bought so many of these troublesome but cheap Windows PCs. Moreover, the TrueType specification includes a much better hinting facility : you can actually *read* TrueType fonts at 12 pts on a VGA screen, while this is unlikely with ATM whose rendering of small sizes is jerky, to say the least ( just ask any OS/2 user out there !! ). Finally, there *is* already a freely available Type 1 renderer, donated by IBM to the X Consortium. Look for source distributions of X11r6 for it ! It works, the source isn't really readable ( IMHO ) and suffers from a "weird" implementation ( still IMHO ), to be polite ! The FreeType project aims the development of a TrueType engine that can be easily ported across platforms, while being fast, accurate and stable. Simply. I. Engine Design Goals : ------------------------ This section describes the several goals the engine has been developped for : - Easy maintenance : In an age where all 'serious' programming is done in C or C++, the author decided to code the engine in PASCAL ! This may seem rather weird, but this language comes on the PC with high-quality programming environments ( namely Borland's for DOS, and Virtual Pascal on OS/2 ) that allow light-speed compilation, real module separation and easy debugging. The drawback of these compilers ( i.e. a poorly, if ever, optimised generated code ) forced development to focus on algorithm fine-tuning, rather than clever macro tricks, and the tendency to optimize 'on the run' so usual of C programmers ( a practice that easily leads to weird and hardly maintainable code ). This approach, though quite constraining at first, paid back faster than expected. The project is now a well crafted piece of software, and runs *fast* even under Borland Pascal. This is unoptimized code, and one could expect a great performance increase by translating to C and using a good optimizing compiler like GCC, or even to assembly. The current version has been compiled and tested on Borland's 16 bits Pascal Compilers ( Turbo-Pascal, Borland-Pascal Real Mode, and Borland-Pascal DPMI ) as well as the 32 bit OS/2 Virtual Pascal compiler ( a *must-have* ). The 32-bits version is about 2.5 to 3 times faster than its 16-bit counterpart. This is mainly due to the fact that most of the data processed by the engine is 32-bit, a painful task for 16-bit programs.. There exist some small differences between the 16-bit and 32-bit engines, coming from very short buit-in assembly lines embedded in functions, for convenience rather than speed.. See the section on Porting to locate these.. As a whole, the Engine proved several times to be highly readable and maintainable. It takes about 12 K-lines of commented and airy Pascal code, which is a small for such a software. - System Independence *and* Portability: The Engine has been developped with portability in mind. This means that we don't rely on any specific feature of the Pascal runtime libraries. It thus manages resources in a specific way. a. Memory management : A client application should first allocate a block of memory and pass it to the engine at elaboration. The engine has no interface to any external memory manager to allocate or release chunks of memory. Rather, it will use the passed memory block, called the Font Storage Pool, for all its needs. Deallocation of the pool is left to the client application. This approach garantees that the engine's memory requirements during execution are limited to those defined by the client application. Should the pool be too small, the engine should fail to initialize, or to load a font file, in a gentle way ( typically with an error message ). b. File operations : A simple unit called 'File' provides a basic I/O layer using the simple Pascal FILE type ( unbuffered file access ). New instances of 'File' can be written to take care of buffered or memory-mapped files access when possible, or other systems I/O. c. Endianess : TrueType is built on little-endianess, used typically on Motorola processors, where the high order byte is always in the first memory position, while the lowest is in the last. Endianess plays a role when reading data from the font file, and when extracting constant values from the instruction stream. In the modules where it is important ( 'Tables' and 'Ins' ), the short/long int access has been well defined, and porting to a platform with a different endianess should not be a big problem. - Reliability and Predictable Behaviour : This means that in the event of a corrupt font file processed by the Engine, the latter should react gently by delivering an error message, rather than puking garbage at the screen or at the application's memory space. This is important if one wants to make the Engine part of a windowing system ( it's author is considering seriously writing a TrueType SubSystem for OS/2, and maybe X11/Linux ), and keep it stable. - High Quality : The quality of the rendered glyphs should equal those found on the Windows and Macintosh platforms. This implies an accurate rasterizer ( did you say *smooth* splines ? ;), as well as a real TrueType bytecode interpreter ( did you say good hinting ? ). Most shareware/commercial TrueType libraries do not include both components. Their overall rendering quality is consequently poor to disastrous, especially with small characters. The Free TrueType Engine is to date the first freely available source code for such a library. NOTE : Win95's style anti-aliasing technology is not considered seriously right now.. This being a matter of time, not of competence :-) It doesn't seem to be a difficult issue though.. - Speed : This may surprise the many programmers who think that portable code is forced to be inefficient. The idea is to fine-tune every piece of algorithm found in this engine, as long as it stays on touch with its goals ( accuracy, portability, maintainability ). For example, appropriate research led the rasterizer to become faster, more accurate, and less memory-consuming as time passed. This is Pascal code, with zero, nilch, nada, optimisation; though, it flies .. test it ! II. Engine Architecture : 1. Component hierarchy : ------------------------ A component is simply a Pascal unit ( a simple module made of a spec and a body ). We'll give for each component its name which can be used to get its unit name. The unit name is found by prefixing "TT" to the component name; hence, the 'Types' component is in file 'TTTypes.Pas' ! a. Base Components : - 'Types' - 'Error' - 'Vars' - 'Calc' - 'File' - 'Disp' b. Advanced Components : - 'Raster' - 'Tables' - 'Ins' c. Test programes : - 'TestTime' - 'TTZoom' - 'TTDebug' 2. Runtime execution : ---------------------- a. The Storage Pool : Though written in Pascal, the Engine has been developped to be as platform, language and system independent as possible. This simply means two things : The features, like File I/O, dependent on a specific runtime library or system, have been moved to well chosen modules, which are the only ones that shall be touched to port the engine. Moreover, the Engine provides its own memory management routines. A client application should allocate a memory block with its own implementation of 'malloc', 'GetMem', or wathever similar function, and pass a pointer and its size at Egine elaboration. This block is called the Storage Pool, as all Engine routines will allocate the blocks they need in it. b. The Interpreter : - code ranges c. The Rasterizer : - pixel coordinates : According to the TrueType specifications, all pixel coordinates managed by the rasterizer are in 6 bits fixed float format coded on 32 bits ( the famous F26dot6 type ). - contours : A contour is a closed, oriented curve giving the borders of the regions to be filled when rasterizing a glyph. One glyph is commonly described using several contours. According to the TrueType specs, contours must be oriented so that the filled region is to the right of the contour orientation. Unfortunately, many freely available fonts do not respect this simple rule ! Contours are given to the rasterizer as sets of segments and simple arcs ( second-degree B‚zier polynomials ). They are first converted to sets of "Profiles". - profiles : Put it simply, a "profile" is a contour's portion of a contour that can only be either ascending or descending, i.e. it is monotonous in the vertical direction. There is no such thing as a horizontal profile, as we shall see. Here are a few examples : A Square 1 2 ---->---- is made of two | | | | | | profiles | | ^ v ^ + v | | | | | | | | ----<---- up down A Triangle P2 1 2 |\ is made of two | \ ^ | \ \ | \ | | \ \ profiles | \ | | | \ v ^ | \ | | \ | | + \ v | \ | | \ P1 ---___ \ ---___ \ ---_\ ---_ \ <--__ P3 up down A more general contour can be made of more than two profiles : __ ^ / | / ___ / | / | / | / | / | | | / / => | v / / | | | | | | ^ | ^ | |___| | | ^ + | + | + v | | | v | | | | | up | |___________| | down | <-- up down Each profile is an array that associates one horizontal *pixel coordinate* to each bitmap *scanline* crossed by the contour's section represented by the profile. They are stored in the Storage Pool - table overflow and sub-banding