Commit f17a0ce
Draw text items in SVG files
Changed files (3)
Diff
@@ -410,6 +410,10 @@ public class SvgFile : GLib.Object { parse_line (layer, parent_style, tag); } + if (name == "text") {+ parse_text (layer, parent_style, tag);+ }+ if (name == "svg") { SvgDrawing embedded = parse_svg_file (tag, format); layer.add_object (embedded);@@ -602,6 +606,35 @@ public class SvgFile : GLib.Object { 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? public static SvgTransforms parse_transform (string transforms) {@@ -611,6 +644,10 @@ public class SvgFile : GLib.Object { transform_functions = new SvgTransforms (); + if (transforms == "") {+ return transform_functions;+ }+ transform = transform.replace ("\t", " "); transform = transform.replace ("\n", " "); transform = transform.replace ("\r", " ");@@ -621,7 +658,7 @@ public class SvgFile : GLib.Object { } if (unlikely (transform.index_of (")") == -1)) {- warning ("No parenthesis in transform function.");+ warning (@"No parenthesis in transform function: $transform"); return transform_functions; } new file mode 100644@@ -0,0 +1,82 @@+/*+ 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";+ }+}++}new file mode 100644@@ -0,0 +1,137 @@+#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);+}