aboutsummaryrefslogtreecommitdiff
path: root/src/shape.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shape.c')
-rw-r--r--src/shape.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/shape.c b/src/shape.c
new file mode 100644
index 0000000..93625e0
--- /dev/null
+++ b/src/shape.c
@@ -0,0 +1,234 @@
+/*
+ * shape.c
+ *
+ * Copyright © 2014 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This file is part of Colloquium.
+ *
+ * Colloquium is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pango/pangocairo.h>
+
+#include "wrap.h"
+#include "sc_interp.h"
+#include "shape.h"
+
+
+static void shape_and_measure(gpointer data, gpointer user_data)
+{
+ struct wrap_box *box = user_data;
+ PangoItem *item = data;
+ PangoRectangle rect;
+
+ /* FIXME: Don't assume only one run per wrap box */
+ box->glyphs = pango_glyph_string_new();
+ box->item = item;
+
+ pango_shape(box->text+item->offset, item->length, &item->analysis,
+ box->glyphs);
+
+ pango_glyph_string_extents(box->glyphs, box->font, NULL, &rect);
+
+ box->width += rect.width;
+ if ( rect.height > box->height ) {
+ box->height = rect.height;
+ }
+ if ( PANGO_ASCENT(rect) > box->ascent ) {
+ box->ascent = PANGO_ASCENT(rect);
+ }
+}
+
+
+/* Add "text", followed by a space of type "space", to "line" */
+static int add_wrap_box(struct wrap_line *line, char *text, size_t offset,
+ enum wrap_box_space space, PangoContext *pc,
+ struct sc_font *font, int editable)
+{
+ GList *pango_items;
+ struct wrap_box *box;
+ PangoAttrList *attrs;
+ PangoAttribute *attr;
+
+ if ( line->n_boxes == line->max_boxes ) {
+ line->max_boxes += 32;
+ alloc_boxes(line);
+ if ( line->n_boxes == line->max_boxes ) return 1;
+ }
+
+ box = &line->boxes[line->n_boxes];
+ if ( !editable ) offset = 0;
+ box->sc_offset = offset;
+ box->type = WRAP_BOX_PANGO;
+ box->text = text;
+ box->space = space;
+ box->font = font->font;
+ box->width = 0;
+ box->editable = editable;
+ box->ascent = font->ascent;
+ box->height = font->height;
+ box->col[0] = font->col[0]; /* Red */
+ box->col[1] = font->col[1]; /* Green */
+ box->col[2] = font->col[2]; /* Blue */
+ box->col[3] = font->col[3]; /* Alpha */
+ line->n_boxes++;
+
+ if ( strlen(text) == 0 ) {
+ box->type = WRAP_BOX_NOTHING;
+ return 0;
+ }
+
+ attrs = pango_attr_list_new();
+ attr = pango_attr_font_desc_new(font->fontdesc);
+ pango_attr_list_insert_before(attrs, attr);
+ pango_items = pango_itemize(pc, text, 0, strlen(text), attrs, NULL);
+ g_list_foreach(pango_items, shape_and_measure, box);
+ g_list_free(pango_items);
+ pango_attr_list_unref(attrs);
+
+ return 0;
+}
+
+
+static void add_image_box(struct wrap_line *line, const char *filename,
+ size_t offset, int w, int h, int editable)
+{
+ struct wrap_box *box;
+
+ box = &line->boxes[line->n_boxes];
+ if ( !editable ) offset = 0;
+ box->sc_offset = offset;
+ box->type = WRAP_BOX_IMAGE;
+ box->text = NULL;
+ box->space = WRAP_SPACE_NONE;
+ box->width = pango_units_from_double(w);
+ box->ascent = pango_units_from_double(h);
+ box->height = pango_units_from_double(h);
+ box->filename = strdup(filename);
+ box->editable = editable;
+ line->n_boxes++;
+}
+
+
+int split_words(struct wrap_line *boxes, PangoContext *pc, const char *text,
+ PangoLanguage *lang, int editable, struct sc_font *font)
+{
+ PangoLogAttr *log_attrs;
+ glong len_chars, i;
+ size_t len_bytes, start;
+
+ /* Empty block? */
+ if ( text == NULL ) return 1;
+
+ len_chars = g_utf8_strlen(text, -1);
+ if ( len_chars == 0 ) return 1;
+
+ len_bytes = strlen(text);
+
+ log_attrs = malloc((len_chars+1)*sizeof(PangoLogAttr));
+ if ( log_attrs == NULL ) return 1;
+
+ /* Create glyph string */
+ pango_get_log_attrs(text, len_bytes, -1, lang, log_attrs, len_chars+1);
+
+ start = 0;
+ for ( i=0; i<len_chars; i++ ) {
+
+ if ( log_attrs[i].is_line_break ) {
+
+ char *word;
+ enum wrap_box_space type;
+ size_t len;
+ char *ptr;
+ size_t offs;
+
+ ptr = g_utf8_offset_to_pointer(text, i);
+ offs = ptr - text;
+
+ /* Stuff up to (but not including) sc[i] forms a
+ * wrap box */
+ len = offs - start;
+ if ( log_attrs[i].is_mandatory_break ) {
+ type = WRAP_SPACE_EOP;
+ if ( (offs>0) && (text[offs-1] == '\n') ) len--;
+ if ( (offs>0) && (text[offs-1] == '\r') ) len--;
+ } else if ( (i>0)
+ && log_attrs[i-1].is_expandable_space ) {
+ type = WRAP_SPACE_INTERWORD;
+ len--; /* Not interested in spaces */
+ } else {
+ type = WRAP_SPACE_NONE;
+ }
+
+ word = strndup(text+start, len);
+ if ( word == NULL ) {
+ fprintf(stderr, "strndup() failed.\n");
+ free(log_attrs);
+ return 1;
+ }
+
+ if ( add_wrap_box(boxes, word, start, type,
+ pc, font, editable) ) {
+ fprintf(stderr, "Failed to add wrap box.\n");
+ }
+ start = offs;
+
+ }
+
+ }
+ if ( i > start ) {
+
+ char *word;
+ size_t l;
+
+ word = strdup(text+start); /* to the end */
+ if ( word == NULL ) {
+ fprintf(stderr, "strndup() failed.\n");
+ free(log_attrs);
+ return 1;
+ }
+ l = strlen(word);
+
+ if ( (word[l-1] == '\n') ) {
+
+ /* There is a newline at the end of the SC */
+ char *word2;
+
+ word2 = strndup(word, l-1);
+ add_wrap_box(boxes, word2, start,
+ WRAP_SPACE_EOP, pc, font, editable);
+ add_wrap_box(boxes, strdup(""), len_bytes,
+ WRAP_SPACE_NONE, pc, font, editable);
+
+ } else {
+
+ add_wrap_box(boxes, word, start,
+ WRAP_SPACE_NONE, pc, font, editable);
+
+ }
+
+ }
+
+ free(log_attrs);
+ return 0;
+}