Commit 72a8c8e
Text extent
Changed files (3)
Diff
@@ -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 (); }new file mode 100644@@ -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;+}deleted file mode 100644@@ -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;-}