/* * shape.c * * Copyright © 2014-2015 Thomas White * * 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 . * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "wrap.h" #include "sc_interp.h" #include "shape.h" struct box_adding_stuff { struct wrap_line *line; SCInterpreter *scin; int editable; enum wrap_box_space space; SCBlock *bl; size_t offs; }; void shape_box(struct wrap_box *box) { PangoRectangle rect; const char *tp; tp = g_utf8_offset_to_pointer(sc_block_contents(box->scblock), box->offs_char); pango_shape(tp, box->len_bytes, &box->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); } } static void add_wrap_box(gpointer vi, gpointer vb) { struct wrap_box *box; double *col; PangoItem *item = vi; struct box_adding_stuff *bas = vb; size_t offs_bytes; const char *tp; if ( bas->line->n_boxes == bas->line->max_boxes ) { bas->line->max_boxes += 32; alloc_boxes(bas->line); if ( bas->line->n_boxes == bas->line->max_boxes ) return; } box = &bas->line->boxes[bas->line->n_boxes]; box->type = WRAP_BOX_PANGO; box->space = bas->space; box->font = sc_interp_get_font(bas->scin); box->width = 0; box->editable = bas->editable; box->ascent = sc_interp_get_ascent(bas->scin); box->height = sc_interp_get_height(bas->scin); /* Link to the actual text */ tp = sc_block_contents(bas->bl); offs_bytes = item->offset + bas->offs; box->scblock = bas->bl; box->offs_char = g_utf8_pointer_to_offset(tp, tp+offs_bytes); box->len_chars = g_utf8_strlen(tp+offs_bytes, item->length); box->len_bytes = item->length; col = sc_interp_get_fgcol(bas->scin); box->col[0] = col[0]; /* Red */ box->col[1] = col[1]; /* Green */ box->col[2] = col[2]; /* Blue */ box->col[3] = col[3]; /* Alpha */ box->glyphs = pango_glyph_string_new(); box->analysis = item->analysis; bas->line->n_boxes++; shape_box(box); } static void add_nothing_box(struct wrap_line *line, SCBlock *scblock, int editable, enum wrap_box_space sp, SCInterpreter *scin, size_t offs) { struct wrap_box *box; if ( line->n_boxes == line->max_boxes ) { line->max_boxes += 32; alloc_boxes(line); if ( line->n_boxes == line->max_boxes ) return; } box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_NOTHING; box->scblock = scblock; box->offs_char = offs; box->space = sp; box->width = 0; box->len_chars = 0; box->ascent = sc_interp_get_ascent(scin); box->height = sc_interp_get_height(scin); box->filename = NULL; box->editable = editable; line->n_boxes++; } static UNUSED char *swizzle(const char *inp, size_t len) { int i; char *out = malloc(len+1); strncpy(out, inp, len); out[len] = '\0'; for ( i=0; in_boxes == line->max_boxes ) { line->max_boxes += 32; alloc_boxes(line); if ( line->n_boxes == line->max_boxes ) return; } box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_CALLBACK; box->scblock = NULL; box->offs_char = 0; 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->draw_func = func; box->bvp = bvp; box->vp = vp; box->editable = 0; line->n_boxes++; } void add_image_box(struct wrap_line *line, const char *filename, int w, int h, int editable) { struct wrap_box *box; if ( line->n_boxes == line->max_boxes ) { line->max_boxes += 32; alloc_boxes(line); if ( line->n_boxes == line->max_boxes ) return; } box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_IMAGE; box->scblock = NULL; box->offs_char = 0; 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, SCBlock *bl, PangoLanguage *lang, int editable, SCInterpreter *scin) { PangoLogAttr *log_attrs; glong len_chars, i; size_t len_bytes, start; int chars_done; const char *text = sc_block_contents(bl); /* Empty block? */ if ( text == NULL ) return 1; len_chars = g_utf8_strlen(text, -1); if ( len_chars == 0 ) { add_wrap_boxes(boxes, WRAP_SPACE_NONE, pc, scin, bl, 0, 0, editable); return 1; } len_bytes = strlen(text); log_attrs = malloc((len_chars+1)*sizeof(PangoLogAttr)); if ( log_attrs == NULL ) return 1; pango_get_log_attrs(text, len_bytes, -1, lang, log_attrs, len_chars+1); //debug_log_attrs(len_chars, text, log_attrs); start = 0; chars_done = 0; for ( i=0; i0) && (g_utf8_prev_char(ptr)[0]=='\n') ) len--; } else if ( (i>0) && log_attrs[i-1].is_expandable_space ) { type = WRAP_SPACE_INTERWORD; len--; } else { type = WRAP_SPACE_NONE; } if ( add_wrap_boxes(boxes, type, pc, scin, bl, start, len, editable) ) { fprintf(stderr, "Failed to add wrap box.\n"); } start = offs; chars_done = i; } } /* Add the stuff left over at the end */ if ( i > chars_done ) { size_t l = strlen(text+start); if ( (text[start+l-1] == '\n') ) { /* There is a newline at the end of the SC */ add_wrap_boxes(boxes, WRAP_SPACE_EOP, pc, scin, bl, start, l-1, editable); } else { add_wrap_boxes(boxes, WRAP_SPACE_NONE, pc, scin, bl, start, l, editable); } } free(log_attrs); return 0; }