Clone in a terminal:
Commit 72a8c8e
Johan Mattsson - 2016-07-17T11:26:59+00:00
72a8c8ed21a1b205ed172dc50dd0fb94cdc374f0johan.mattsson.m@gmail.com

Text extent

Changed files (3)

Diff

diff --git a/libsvgbird/Text.vala b/libsvgbird/Text.valaindex bc12878..2cbc1b3 100644--- a/libsvgbird/Text.vala+++ b/libsvgbird/Text.vala@@ -26,6 +26,7 @@ extern struct svg_bird_font_item { }  extern void svg_bird_draw_text (Context cr, svg_bird_font_item* font, string text);+extern void svg_bird_get_extent (svg_bird_font_item* font, string text, out double w, out double h);  extern void svg_bird_font_item_delete (svg_bird_font_item* item); extern svg_bird_font_item* svg_bird_font_item_create (string font_file, int font_size);@@ -66,7 +67,7 @@ public class Text : Object { 	public double y = 0;  	svg_bird_font_item* font = null;-	+ 	public Text () { 		if (!svg_bird_has_font_config ()) { 			init_font_config ();@@ -79,6 +80,21 @@ public class Text : Object { 		svg_bird_font_item_delete (font); 	} +	public void get_text_extents (out double w, out double h) {+		svg_bird_get_extent (font, content, out w, out h);+	}++	public override bool update_boundaries (Context context) {+		double w;+		double h;+		get_text_extents (out w, out h);+		left = x;+		top = y;+		bottom = y + h;+		right = x + w;+		return true;+	}+	 	public void set_font_size (int s) { 		font_size = s; 		set_font (font_family);@@ -90,10 +106,6 @@ public class Text : Object { 		} 		 		font = svg_bird_font_item_create (font_family, font_size);-		-		if (font == null) {-			font = svg_bird_font_item_create ("sans-serif", font_size);-		} 	}  	public void init_font_config () {@@ -141,12 +153,13 @@ public class Text : Object { 	public override void draw_outline (Context cr) { 		cr.save (); 		cr.translate (x, y);++		double w, h;+		svg_bird_get_extent (font, content, out w, out h); 		 		if (font != null) { 			svg_bird_draw_text (cr, font, content);-		} else {-			warning ("No font.");-		}+		}  		 		cr.restore (); 	}diff --git a/libsvgbird/text_drawing.c b/libsvgbird/text_drawing.cnew file mode 100644index 0000000..ea2f9ab--- /dev/null+++ b/libsvgbird/text_drawing.c@@ -0,0 +1,278 @@+#include <stdlib.h>+#include <glib.h>+#include <stdio.h>+#include <math.h>+#include <harfbuzz/hb.h>+#include <harfbuzz/hb-ft.h>+#include <cairo.h>+#include <cairo-ft.h>+ +static GMutex font_config_lock;+FcConfig* font_config = NULL; ++typedef struct svg_bird_font_item_t {+	int font_size;+	FT_Library ft_library;+	FT_Face ft_face;+	hb_font_t *hb_font;+} svg_bird_font_item;++gchar* svg_bird_find_font_file (const gchar* font_name);+void svg_bird_font_item_delete (svg_bird_font_item* item);++void svg_bird_get_extent (svg_bird_font_item* font, const char* text, double* width, double* height) {+	hb_buffer_t *hb_buffer;	++	hb_buffer = hb_buffer_create ();+	hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);+	hb_buffer_guess_segment_properties (hb_buffer);++	hb_shape (font->hb_font, hb_buffer, NULL, 0);++	unsigned int len = hb_buffer_get_length (hb_buffer);+	hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL);+	hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);+	+	double current_x = 0;+	double current_y = 0;+	+	for (unsigned int i = 0; i < len; i++) {+		double x_position = current_x + pos[i].x_offset / 64.;+		double y_position = current_y + pos[i].y_offset / 64.;+ 		+		current_x += pos[i].x_advance / 64.;+		current_y += pos[i].y_advance / 64.;+	}++	*width = current_x;+	*height = current_y;++	if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer))) {+		*height += font->font_size * 1.25;+	} else {+		*width += font->font_size * 1.25;+	}+}++gboolean svg_bird_has_font_config () {+	g_mutex_lock (&font_config_lock);+	gboolean exists = font_config != NULL;+	g_mutex_unlock (&font_config_lock);+	return exists;+}++void svg_bird_set_font_config (FcConfig* f) {+	g_mutex_lock (&font_config_lock);+	font_config = f;+	g_mutex_unlock (&font_config_lock);+}++svg_bird_font_item* svg_bird_font_item_create (const char* font_family, int font_size) {+	FT_Error ft_error;+	svg_bird_font_item* font = malloc (sizeof (svg_bird_font_item));+	memset (font, 0, sizeof (svg_bird_font_item));+ +	char* font_file = svg_bird_find_font_file (font_family);++	FT_Library ft_library = 0;+	FT_Face ft_face = 0;+	+	font->font_size = font_size;+	if ((ft_error = FT_Init_FreeType (&ft_library))) {+		g_warning ("Can't init freetype");+		svg_bird_font_item_delete (font);+		return NULL;+ 	}+ 	+ 	font->ft_library = ft_library;+ 	+	if ((ft_error = FT_New_Face (font->ft_library, font_file, 0, &ft_face))) {+		g_warning ("Can't find freetype font %s %s.", font_family, font_file);+		svg_bird_font_item_delete (font);+		return NULL;+ 	}+ 	+ 	font->ft_face = ft_face;+ 	+	if ((ft_error = FT_Set_Char_Size (font->ft_face, font_size * 64, font_size * 64, 0, 0)))  {+		g_warning ("Can't set font size.");+		svg_bird_font_item_delete (font);+		return NULL;+	}++	font->hb_font = hb_ft_font_create (font->ft_face, NULL);++	if (font->hb_font == NULL) {+		g_warning ("Can't create harfbuzz font for %s", font_file);+		svg_bird_font_item_delete (font);+		return NULL;+	}++	free (font_file);+	return font;+}++void svg_bird_font_item_delete (svg_bird_font_item* item) {+	if (item) {+		if (item->ft_face) {+			FT_Done_Face (item->ft_face);+		}++		if (item->hb_font) {+			hb_font_destroy (item->hb_font);+		}+		+		if (item->ft_library) {+			FT_Done_FreeType (item->ft_library);+		}+				+		free (item);+	}+}++void svg_bird_draw_text (cairo_t* cr, svg_bird_font_item* font, const char* text) {+	cairo_save (cr);+	+	hb_buffer_t *hb_buffer;	++	hb_buffer = hb_buffer_create ();+	hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);+	hb_buffer_guess_segment_properties (hb_buffer);++	hb_shape (font->hb_font, hb_buffer, NULL, 0);++	unsigned int len = hb_buffer_get_length (hb_buffer);+	hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL);+	hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);+	+	double current_x = 0;+	double current_y = 0;+	for (unsigned int i = 0; i < len; i++) {+		hb_codepoint_t gid   = info[i].codepoint;+		unsigned int cluster = info[i].cluster;+		double x_position = current_x + pos[i].x_offset / 64.;+		double y_position = current_y + pos[i].y_offset / 64.;+ 		+		current_x += pos[i].x_advance / 64.;+		current_y += pos[i].y_advance / 64.;+	}++	double width = 0;+	double height = 0;+	+	cairo_font_face_t *cairo_face;+	cairo_face = cairo_ft_font_face_create_for_ft_face (font->ft_face, 0);+	cairo_set_font_face (cr, cairo_face);+	cairo_set_font_size (cr, font->font_size);++	cairo_font_extents_t font_extents;+	cairo_font_extents (cr, &font_extents);++	if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer))) {+		double baseline = (font->font_size - font_extents.height) * .5 + font_extents.ascent;+		cairo_translate (cr, 0, baseline);+	} else {+		cairo_translate (cr, font->font_size * .5, 0);+	}+	+	cairo_glyph_t *cairo_glyphs = cairo_glyph_allocate (len);+	current_x = 0;+	current_y = 0;+	+	cairo_matrix_t matrix;+	cairo_get_matrix (cr, &matrix);+	cairo_matrix_invert (&matrix);+	+	for (unsigned int i = 0; i < len; i++) {+		cairo_glyphs[i].index = info[i].codepoint;+		cairo_glyphs[i].x = current_x + pos[i].x_offset / 64.;+		cairo_glyphs[i].y = -(current_y + pos[i].y_offset / 64.);++		double dx = pos[i].x_advance / 64.0;+		double dy = pos[i].y_advance / 64.0;+ 		+		cairo_matrix_transform_distance (&matrix, &dx, &dy);++		current_x += dx;+		current_y += dy;+ 	}+	+	cairo_show_glyphs (cr, cairo_glyphs, len);+	cairo_glyph_free (cairo_glyphs);++	cairo_font_face_destroy (cairo_face);+ +	hb_buffer_destroy (hb_buffer);+	cairo_restore (cr);+ }++gchar* svg_bird_find_font_file (const gchar* font_name) {+	const FcChar8* name;+	FcPattern* search_pattern;+	FcPattern* font;+	FcChar8* file;+	gchar* path;+	FcObjectSet* font_properties;+	FcFontSet* fonts;+	int i;+	+	if (!svg_bird_has_font_config ()) {+		g_warning("Font config not loaded.");+		return NULL;+	}++	g_mutex_lock (&font_config_lock);++	if (font_config == NULL) {+		g_warning("Font config not loaded.");+		return NULL;+	}+	+	path = NULL;+	name = font_name;++	// match any font as fallback+	search_pattern = FcPatternCreate ();+	font_properties = FcObjectSetBuild (FC_FILE, NULL);++	fonts = FcFontList (font_config, search_pattern, font_properties);+	+	if (fonts->nfont > 0) {+		for (i = 0; i < fonts->nfont; i++) {+			font = fonts->fonts[i];+			+			if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {+				path = g_strdup ((gchar*) file);+				break;+			}+			+			FcPatternDestroy (font);+		}+	}+	+	FcPatternDestroy (search_pattern);+	+	// search for a family name+	search_pattern = FcPatternCreate ();+	FcPatternAddString (search_pattern, FC_FAMILY, name);+	fonts = FcFontList (font_config, search_pattern, font_properties);+	+	if (fonts->nfont > 0) {+		for (i = 0; i < fonts->nfont; i++) {+			font = fonts->fonts[i];+			+			if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {+				g_free (path);+				path = g_strdup ((gchar*) file);+				break;+			}+			+			FcPatternDestroy (font);+		}+	}++	FcPatternDestroy (search_pattern);+	+	g_mutex_unlock (&font_config_lock);+	return path;+}diff --git a/libsvgbird/text_helpers.c b/libsvgbird/text_helpers.cdeleted file mode 100644index 822ce61..0000000--- a/libsvgbird/text_helpers.c+++ /dev/null@@ -1,252 +0,0 @@-#include <stdlib.h>-#include <glib.h>-#include <stdio.h>-#include <math.h>-#include <harfbuzz/hb.h>-#include <harfbuzz/hb-ft.h>-#include <cairo.h>-#include <cairo-ft.h>- -static GMutex font_config_lock;-FcConfig* font_config = NULL; --typedef struct svg_bird_font_item_t {-	int font_size;-	FT_Library ft_library;-	FT_Face ft_face;-	hb_font_t *hb_font;-} svg_bird_font_item;--gchar* svg_bird_find_font_file (const gchar* font_name);-void svg_bird_font_item_delete (svg_bird_font_item* item);--gboolean svg_bird_has_font_config () {-	g_mutex_lock (&font_config_lock);-	gboolean exists = font_config != NULL;-	g_mutex_unlock (&font_config_lock);-	return exists;-}--void svg_bird_set_font_config (FcConfig* f) {-	g_mutex_lock (&font_config_lock);-	font_config = f;-	g_mutex_unlock (&font_config_lock);-}--svg_bird_font_item* svg_bird_font_item_create (const char* font_family, int font_size) {-	FT_Error ft_error;-	svg_bird_font_item* font = malloc (sizeof (svg_bird_font_item));-	memset (font, 0, sizeof (svg_bird_font_item));- -	char* font_file = svg_bird_find_font_file (font_family);--	FT_Library ft_library = 0;-	FT_Face ft_face = 0;-	-	font->font_size = font_size;-	if ((ft_error = FT_Init_FreeType (&ft_library))) {-		g_warning ("Can't init freetype");-		svg_bird_font_item_delete (font);-		return NULL;- 	}- 	- 	font->ft_library = ft_library;- 	-	if ((ft_error = FT_New_Face (font->ft_library, font_file, 0, &ft_face))) {-		g_warning ("Can't find freetype font %s %s.", font_family, font_file);-		svg_bird_font_item_delete (font);-		return NULL;- 	}- 	- 	font->ft_face = ft_face;- 	-	if ((ft_error = FT_Set_Char_Size (font->ft_face, font_size * 64, font_size * 64, 0, 0)))  {-		g_warning ("Can't set font size.");-		svg_bird_font_item_delete (font);-		return NULL;-	}--	font->hb_font = hb_ft_font_create (font->ft_face, NULL);--	if (font->hb_font == NULL) {-		g_warning ("Can't create harfbuzz font for %s", font_file);-		svg_bird_font_item_delete (font);-		return NULL;-	}--	free (font_file);-	return font;-}--void svg_bird_font_item_delete (svg_bird_font_item* item) {-	if (item) {-		if (item->ft_face) {-			FT_Done_Face (item->ft_face);-		}--		if (item->hb_font) {-			hb_font_destroy (item->hb_font);-		}-		-		if (item->ft_library) {-			FT_Done_FreeType (item->ft_library);-		}-				-		free (item);-	}-}--void svg_bird_draw_text (cairo_t* cr, svg_bird_font_item* font, const char* text) {-	cairo_save (cr);-	-	hb_buffer_t *hb_buffer;	--	hb_buffer = hb_buffer_create ();-	hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);-	hb_buffer_guess_segment_properties (hb_buffer);--	hb_shape (font->hb_font, hb_buffer, NULL, 0);--	unsigned int len = hb_buffer_get_length (hb_buffer);-	hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL);-	hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);-	-	double current_x = 0;-	double current_y = 0;-	for (unsigned int i = 0; i < len; i++) {-		hb_codepoint_t gid   = info[i].codepoint;-		unsigned int cluster = info[i].cluster;-		double x_position = current_x + pos[i].x_offset / 64.;-		double y_position = current_y + pos[i].y_offset / 64.;- 		-		current_x += pos[i].x_advance / 64.;-		current_y += pos[i].y_advance / 64.;-	}--	double width = 0;-	double height = 0;-	for (unsigned int i = 0; i < len; i++) {-		width  += pos[i].x_advance / 64.;-		height -= pos[i].y_advance / 64.;-	}-	-	if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer)))-		height += font->font_size;-	else-		width += font->font_size;--	cairo_font_face_t *cairo_face;-	cairo_face = cairo_ft_font_face_create_for_ft_face (font->ft_face, 0);-	cairo_set_font_face (cr, cairo_face);-	cairo_set_font_size (cr, font->font_size);--	if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer))) {-		cairo_font_extents_t font_extents;-		cairo_font_extents (cr, &font_extents);-		double baseline = (font->font_size - font_extents.height) * .5 + font_extents.ascent;-		cairo_translate (cr, 0, baseline);-	} else {-		cairo_translate (cr, font->font_size * .5, 0);-	}-	-	cairo_glyph_t *cairo_glyphs = cairo_glyph_allocate (len);-	current_x = 0;-	current_y = 0;-	-	cairo_matrix_t matrix;-	cairo_get_matrix (cr, &matrix);-	cairo_matrix_invert (&matrix);-	-	for (unsigned int i = 0; i < len; i++) {-		cairo_glyphs[i].index = info[i].codepoint;-		cairo_glyphs[i].x = current_x + pos[i].x_offset / 64.;-		cairo_glyphs[i].y = -(current_y + pos[i].y_offset / 64.);--		double dx = pos[i].x_advance / 64.0;-		double dy = pos[i].y_advance / 64.0;- 		-		cairo_matrix_transform_distance (&matrix, &dx, &dy);-		-		current_x += dx;-		current_y += dy;- 	}-	-	cairo_show_glyphs (cr, cairo_glyphs, len);-	cairo_glyph_free (cairo_glyphs);--	cairo_font_face_destroy (cairo_face);- -	hb_buffer_destroy (hb_buffer);-	cairo_restore (cr);- }--gchar* svg_bird_find_font_file (const gchar* font_name) {-	const FcChar8* name;-	FcPattern* search_pattern;-	FcPattern* font;-	FcChar8* file;-	gchar* path;-	FcObjectSet* font_properties;-	FcFontSet* fonts;-	int i;-	-	if (!svg_bird_has_font_config ()) {-		g_warning("Font config not loaded.");-		return NULL;-	}--	g_mutex_lock (&font_config_lock);--	if (font_config == NULL) {-		g_warning("Font config not loaded.");-		return NULL;-	}-	-	path = NULL;-	name = font_name;--	// match any font as fallback-	search_pattern = FcPatternCreate ();-	font_properties = FcObjectSetBuild (FC_FILE, NULL);--	fonts = FcFontList (font_config, search_pattern, font_properties);-	-	if (fonts->nfont > 0) {-		for (i = 0; i < fonts->nfont; i++) {-			font = fonts->fonts[i];-			-			if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {-				path = g_strdup ((gchar*) file);-				break;-			}-			-			FcPatternDestroy (font);-		}-	}-	-	FcPatternDestroy (search_pattern);-	-	// search for a family name-	search_pattern = FcPatternCreate ();-	FcPatternAddString (search_pattern, FC_FAMILY, name);-	fonts = FcFontList (font_config, search_pattern, font_properties);-	-	if (fonts->nfont > 0) {-		for (i = 0; i < fonts->nfont; i++) {-			font = fonts->fonts[i];-			-			if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {-				g_free (path);-				path = g_strdup ((gchar*) file);-				break;-			}-			-			FcPatternDestroy (font);-		}-	}--	FcPatternDestroy (search_pattern);-	-	g_mutex_unlock (&font_config_lock);-	return path;-}

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112