Implementing Resea GUI (Part 2): Font Rendering with FreeType

Font rendering using Cairo and FreeType
Font rendering using Cairo and FreeType

Last night, as you can see in the screenshot above, I finally succeeded in drawing a text using FreeType and Cairo. Here're some random notes on porting FreeType.

What's FreeType?

Citing from its official site:

FreeType is a freely available software library to render fonts.

It is written in C, designed to be small, efficient, highly customizable, and portable while capable of producing high-quality output (glyph images) of most vector and bitmap font formats.

Thanks to Cairo's built-in support of FreeType, by porting Cairo and FreeType, we can render beautifully anti-aliased characters without spending your 5 years (or more) struggling with the maze of the font rendering.

Porting FreeType to Resea

Almost all portable C libraries are not portable: they depend on the C standard library and some OS-specific APIs like mmap(2). The same is true for FreeType too.

That said, since we have a POSIX API compatibility, porting FreeType to Resea was so easy: try building it on Linux, extract gcc -c ... lines from its build log, add them to libs/third_party/cairo/build.mk, enable CAIRO_HAS_FT_FONT, and that's all!

Rendering fonts using FreeType/Cairo

Here's the sample code:

extern uint8_t font_data[];
extern size_t font_size;

void draw_screen(uint8_t *image);

void main(void) {
    FT_Library ft_lib;
    FT_Face ft_face;

    FT_Init_FreeType(&ft_lib);

    // Load a font file.
    FT_New_Memory_Face(ft_lib, font_data, font_size 0, &ft_face);
    cairo_font_face_t *font_face =
        cairo_ft_font_face_create_for_ft_face(ft_face, 0);

    // Draw "Hi!".
    cairo_set_font_face(cr, font_face);
    cairo_set_font_size(cr, 20);
    cairo_set_source_rgb(cr, .7, .7, .7);
    cairo_move_to(cr, 200, 200);
    cairo_show_text(cr, "Hi!");

    cairo_surface_flush(surface);
    draw_screen(cairo_image_surface_get_data(surface));
}

It's pretty straightforward, isn't it? It seems anti-aliasing is enabled by default. For other available text APIs, see Cairo's manual.

Known issues

Undefined behaviors in FreeType/Cairo

In Resea, all C files are compiled with UBSan, a runtime undefined behavior detector. It turned out that UBSan reports some different undefined behaviors in Cairo and FreeType. They work well with UBSan disabled so I doubt a bug in Resea (components related to memory allocation like malloc).

Lack of GCC's intrinsic header files

FreeType uses some SSE2 instructions via intrinsic functions. Because we haven't ported header files for intrinsic functions, SSE2 is currently disabled (-mno-see3). While it works perfectly without SSE2, to enable the SSE2-based optimized implementation, we need to port compiler-rt.