The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Draw text items in SVG files

These changes was commited to the Birdfont repository Sat, 16 Jul 2016 20:12:05 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Sat, 16 Jul 2016 20:12:05 +0000]

Updated Files

libsvgbird/SvgFile.vala
libsvgbird/Text.vala
libsvgbird/text_helpers.c
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -408,6 +408,10 @@ if (name == "line") { parse_line (layer, parent_style, tag); + } + + if (name == "text") { + parse_text (layer, parent_style, tag); } if (name == "svg") { @@ -601,6 +605,35 @@ set_object_properties (line, parent_style, tag); layer.add_object (line); + } + + private void parse_text (Layer layer, SvgStyle parent_style, XmlElement tag) { + Text text = new Text (); + + foreach (Attribute attr in tag.get_attributes ()) { + string name = attr.get_name (); + + if (name == "font-size") { + text.font_size = (int) parse_number (attr.get_content ()); + } + + if (name == "font-family") { + text.font_family = attr.get_content (); + } + + if (name == "x") { + text.x = parse_number (attr.get_content ()); + } + + if (name == "y") { + text.y = parse_number (attr.get_content ()); + } + } + + text.set_text (tag.get_content ()); + + set_object_properties (text, parent_style, tag); + layer.add_object (text); } // FIXME: reverse order? @@ -610,6 +643,10 @@ SvgTransforms transform_functions; transform_functions = new SvgTransforms (); + + if (transforms == "") { + return transform_functions; + } transform = transform.replace ("\t", " "); transform = transform.replace ("\n", " "); @@ -621,7 +658,7 @@ } if (unlikely (transform.index_of (")") == -1)) { - warning ("No parenthesis in transform function."); + warning (@"No parenthesis in transform function: $transform"); return transform_functions; }
diff --git libsvgbird/Text.vala(new)
--- /dev/null +++ b/libsvgbird/Text.vala @@ -1,1 +1,83 @@ + /* + Copyright (C) 2016 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + */ + + using Cairo; + using Math; + + extern class svg_bird_font_item {} + extern void svg_bird_draw_text (Context cr, svg_bird_font_item* font, string text); + + 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); + + namespace SvgBird { + + public class Text : Object { + public string font_family = ""; + public int font_size = 12; + public double x = 0; + public double y = 0; + public string content; + + svg_bird_font_item* font; + + public Text () { + font = svg_bird_font_item_create ("resources/Roboto-Regular.ttf", 34); + } + + ~Text () { + svg_bird_font_item_delete (font); + } + + public void set_text (string t) { + content = t.replace ("\n", " "); + content = content.replace ("\t", " "); + + while (content.index_of (" ") > -1) { + content = content.replace (" ", " "); + } + + content = content.strip (); + } + + public Text.create_copy (Text c) { + Object.copy_attributes (c, this); + font_family = c.font_family; + x = c.x; + y = c.y; + font_size = c.font_size; + } + + public override void draw_outline (Context cr) { + cr.save (); + cr.translate (x, y); + svg_bird_draw_text (cr, font, content); + cr.restore (); + } + + public override bool is_empty () { + return false; + } + + public override Object copy () { + return new Text.create_copy (this); + } + + public override string to_string () { + return "Text"; + } + } + + }
diff --git libsvgbird/text_helpers.c(new)
--- /dev/null +++ b/libsvgbird/text_helpers.c @@ -1,1 +1,138 @@ + #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> + + #define FONT_SIZE 36 + #define MARGIN (FONT_SIZE * .5) + + 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; + + svg_bird_font_item* svg_bird_font_item_create (const char* font_file, int font_size) { + FT_Error ft_error; + + svg_bird_font_item* font = malloc (sizeof (svg_bird_font_item)); + + font->font_size = font_size; + + if ((ft_error = FT_Init_FreeType (&font->ft_library))) { + g_warning ("Can't init freetype"); + return NULL; + } + + if ((ft_error = FT_New_Face (font->ft_library, font_file, 0, &font->ft_face))) { + g_warning ("Can't init freetype font."); + return NULL; + } + + 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."); + return NULL; + } + + font->hb_font = hb_ft_font_create (font->ft_face, NULL); + + } + + void svg_bird_font_item_delete (svg_bird_font_item* item) { + if (item != NULL) { + FT_Done_Face (item->ft_face); + FT_Done_FreeType (item->ft_library); + hb_font_destroy (item->hb_font); + 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); + }