[cairo] Possible bug/misuse in set_scaled_font/set_font_face & FreeType

Jeremy Moles cubicool at gmail.com
Mon Dec 16 11:06:00 PST 2013


(This is a resubmission; my intial post was rejected because I attached 
a huge font file, sorry.)

Hello all! I am developing a (pretty cool) 2D text scenegraph library 
that uses Cairo, Harfbuzz, and glyphy. While working on some of the core 
components, I think I have discovered a bug (or perhaps more likely, a 
misuse) in/of Cairo. Attached is a very simple demo application.

You'll notice that I only use FreeType to load the initial font file, 
and then quickly create a cairo_font_fact_t* from that directly. I never 
call FT_Set_Char_Size, nor do I want to manage the font size with 
FreeType directly.

The issue I've found is that unless I call:

cairo_get_scaled_font()

...after a call to cairo_set_font_size(), then the font glyphs seem to 
have wrong/null origins. I know that that the implementation is probably 
calling FT_Set_Char_Size underneath the hood, but it doesn't seem to 
actually "apply" until after the get_scaled_font() call. I don't know 
how else to best describe it, so I just attached a really simple example 
demonstrating it.

Hopefully I can get some advice/comments on my usage.

Thanks!

-------------- next part --------------
#include <stdlib.h>
#include <stdio.h>

#include <ft2build.h>

#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>
#include <harfbuzz/hb-icu.h>

#include <cairo/cairo.h>
#include <cairo/cairo-ft.h>

int main(int argc, char** argv) {
	FT_Library            ft_library;
	FT_Face               ft_face;
	hb_font_t*            hb_font;
	hb_buffer_t*          buf;
	hb_glyph_info_t*      glyph_info;
	hb_glyph_position_t*  glyph_pos;
	cairo_font_face_t*    cr_font;
	cairo_surface_t*      surface;
	cairo_t*              cr;
	cairo_glyph_t*        cairo_glyphs;

	unsigned int i;
	unsigned int glyph_count;

	int x = 50;
	int y = 90;

	FT_Init_FreeType(&ft_library);
	FT_New_Face(ft_library, "DejaVuSerif.ttf", 0, &ft_face);
		
	hb_font = hb_ft_font_create(ft_face, NULL);
	cr_font = cairo_ft_font_face_create_for_ft_face(ft_face, 0);

	surface = cairo_image_surface_create(
		CAIRO_FORMAT_RGB24,
		512,
		128
	);

	cr = cairo_create(surface);

	cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
	cairo_set_font_face(cr, cr_font);
	cairo_set_font_size(cr, 50.0);

	/* The "bug" is here. Without this call, the new glyphs don't have proper "origins"
	 * it seems. I wish my terminology was better. */
	cairo_get_scaled_font(cr);
	
	buf = hb_buffer_create();

	hb_buffer_set_unicode_funcs(buf, hb_icu_get_unicode_funcs());
	hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
	hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
	hb_buffer_set_language(buf, hb_language_from_string("en", strlen("en")));

	hb_buffer_add_utf8(buf, "FOOBARBAZ", 9, 0, 9);
	hb_shape(hb_font, buf, NULL, 0);

	glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
	glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);
	cairo_glyphs = malloc(sizeof(cairo_glyph_t) * glyph_count);

	for(i = 0; i < glyph_count; i++) {
		cairo_glyphs[i].index = glyph_info[i].codepoint;
		cairo_glyphs[i].x = x + (glyph_pos[i].x_offset / 64);
		cairo_glyphs[i].y = y - (glyph_pos[i].y_offset / 64);

		x += glyph_pos[i].x_advance / 64;
		y -= glyph_pos[i].y_advance / 64;
	}

	cairo_show_glyphs(cr, cairo_glyphs, glyph_count);

	cairo_surface_write_to_png(surface, "foo.png");

	free(cairo_glyphs);	
	hb_buffer_destroy(buf);
	hb_font_destroy(hb_font);
	cairo_surface_destroy(surface);
	cairo_destroy(cr);
	FT_Done_FreeType(ft_library);

	return 0;
}

-------------- next part --------------
CC      = gcc
CFLAGS  = -g -O2 -Wall --pedantic `freetype-config --cflags` `pkg-config --cflags harfbuzz-icu` -W -Wall -Wno-unused-parameter
LDFLAGS =`icu-config --ldflags`
LIBS    = -lcairo -lharfbuzz `freetype-config --libs` `pkg-config --libs harfbuzz-icu`

main: main.c
	$(CC) $(<) $(CFLAGS) -o $(@) $(LDFLAGS) $(LIBS)

clean:
	rm -f main



More information about the cairo mailing list