diff options
-rw-r--r-- | Makefile.am | 10 | ||||
-rw-r--r-- | src/boxvec.c | 98 | ||||
-rw-r--r-- | src/boxvec.h | 63 | ||||
-rw-r--r-- | src/frame.c | 9 | ||||
-rw-r--r-- | src/frame.h | 10 | ||||
-rw-r--r-- | src/render.c | 13 | ||||
-rw-r--r-- | src/sc_editor.c | 88 | ||||
-rw-r--r-- | src/shape.c | 59 | ||||
-rw-r--r-- | src/shape.h | 6 | ||||
-rw-r--r-- | src/wrap.c | 244 | ||||
-rw-r--r-- | src/wrap.h | 13 |
11 files changed, 319 insertions, 294 deletions
diff --git a/Makefile.am b/Makefile.am index cf3e699..bd383f1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ src_colloquium_SOURCES = src/colloquium.c src/render.c \ src/imagestore.c src/notes.c src/pr_clock.c \ src/inhibit_screensaver.c \ src/shape.c src/sc_editor.c src/narrative_window.c \ - src/slide_window.c src/testcard.c + src/slide_window.c src/testcard.c src/boxvec.c INCLUDES = -Iharfatum/src @@ -25,7 +25,8 @@ EXTRA_DIST += src/presentation.h src/render.h src/wrap.h \ src/slideshow.h src/sc_parse.h src/sc_interp.h \ src/imagestore.h src/notes.h src/pr_clock.h \ src/inhibit_screensaver.h src/shape.h \ - src/sc_editor.h src/slide_window.h src/narrative_window.c + src/sc_editor.h src/slide_window.h src/narrative_window.h \ + src/boxvec.h src/default_stylesheet.o: src/default_stylesheet.sty ld -r -b binary -o src/default_stylesheet.o src/default_stylesheet.sty @@ -49,8 +50,9 @@ tests_storycode_test_SOURCES = tests/storycode_test.c src/sc_parse.c tests_render_test_SOURCES = tests/render_test.c src/render.c src/frame.c \ src/wrap.c src/sc_parse.c src/imagestore.c \ - src/sc_interp.c src/shape.c + src/sc_interp.c src/shape.c src/boxvec.c tests_render_test_sc1_SOURCES = tests/render_test_sc1.c src/sc_parse.c \ src/render.c src/frame.c src/wrap.c \ - src/imagestore.c src/sc_interp.c src/shape.c + src/imagestore.c src/sc_interp.c src/shape.c \ + src/boxvec.c diff --git a/src/boxvec.c b/src/boxvec.c new file mode 100644 index 0000000..06754e6 --- /dev/null +++ b/src/boxvec.c @@ -0,0 +1,98 @@ +/* + * boxvec.c + * + * Copyright © 2016 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 <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "boxvec.h" + + +int bv_len(struct boxvec *vec) +{ + return vec->n_boxes; +} + + +extern struct boxvec *bv_new() +{ + struct boxvec *n = malloc(sizeof(struct boxvec)); + if ( n == NULL ) return NULL; + + n->n_boxes = 0; + n->max_boxes = 0; + n->boxes = NULL; + + return NULL; +} + + +int bv_ensure_space(struct boxvec *vec, int n) +{ + struct wrap_box **t; + if ( vec == NULL ) return 1; + if ( vec->max_boxes > n ) return 0; + + n = (n/32)*32 + 32; + t = realloc(vec->boxes, n*sizeof(struct wrap_box *)); + if ( t == NULL ) return 1; + + vec->boxes = t; + return 0; +} + + +int bv_add(struct boxvec *vec, struct wrap_box *bx) +{ + if ( vec == NULL ) return 1; + if ( bv_ensure_space(vec, vec->n_boxes+1) ) return 1; + vec->boxes[vec->n_boxes++] = bx; + return 0; +} + + +struct wrap_box *bv_box(struct boxvec *vec, int i) +{ + assert(vec != NULL); + if ( i >= vec->n_boxes ) return NULL; + return vec->boxes[i]; +} + + +struct wrap_box *bv_last(struct boxvec *vec) +{ + return vec->boxes[vec->n_boxes-1]; +} + + +void bv_free(struct boxvec *vec) +{ + if ( vec == NULL ) return; + free(vec->boxes); + free(vec); +} + diff --git a/src/boxvec.h b/src/boxvec.h new file mode 100644 index 0000000..e830837 --- /dev/null +++ b/src/boxvec.h @@ -0,0 +1,63 @@ +/* + * boxvec.h + * + * Copyright © 2016 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/>. + * + */ + +#ifndef BOXVEC_H +#define BOXVEC_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + + +/* A vector of boxes */ +struct boxvec +{ + int n_boxes; + int max_boxes; + struct wrap_box **boxes; +}; + + +/* Length of a boxvec */ +extern int bv_len(struct boxvec *vec); + +/* Create a bxvec or boxvec */ +extern struct boxvec *bv_new(void); + +/* Ensure space in a bxvec or boxvec */ +extern int bv_ensure_space(struct boxvec *vec, int n); + +/* Add to a bxvec or boxvec */ +extern int bv_add(struct boxvec *vec, struct wrap_box *bx); + +/* Get a box from a boxvec or bxvec */ +extern struct wrap_box *bv_box(struct boxvec *vec, int i); +extern struct wrap_box *bv_last(struct boxvec *vec); + +/* Free a bxvec or boxvec */ +extern void bv_free(struct boxvec *vec); + +#endif /* BOXVEC_H */ diff --git a/src/frame.c b/src/frame.c index 5b16f32..c1dfd39 100644 --- a/src/frame.c +++ b/src/frame.c @@ -32,6 +32,7 @@ #include "sc_parse.h" #include "frame.h" #include "wrap.h" +#include "boxvec.h" static int alloc_ro(struct frame *fr) @@ -66,13 +67,7 @@ struct frame *frame_new() n->scblocks = NULL; - n->boxes = malloc(sizeof(struct wrap_line)); - if ( n->boxes == NULL ) { - fprintf(stderr, "Failed to allocate boxes.\n"); - free(n); - return NULL; - } - initialise_line(n->boxes); + n->boxes = bv_new(); return n; } diff --git a/src/frame.h b/src/frame.h index f22f5f8..11ad36b 100644 --- a/src/frame.h +++ b/src/frame.h @@ -55,17 +55,17 @@ struct frame int max_children; SCBlock *scblocks; - struct wrap_line *boxes; /* The unwrapped boxes */ + struct boxvec *boxes; /* The unwrapped boxes */ int visited; + int n_paragraphs; + struct boxvec **paragraphs; + int *paragraph_start_lines; + int n_lines; int max_lines; struct wrap_line *lines; - int n_paragraphs; - struct wrap_line **paragraphs; - int *paragraph_start_lines; - /* The rectangle allocated to this frame, determined by the renderer */ double x; double y; diff --git a/src/render.c b/src/render.c index cdf3b0a..1d5656b 100644 --- a/src/render.c +++ b/src/render.c @@ -1,7 +1,7 @@ /* * render.c * - * Copyright © 2013-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -42,6 +42,7 @@ #include "render.h" #include "wrap.h" #include "imagestore.h" +#include "boxvec.h" static void render_glyph_box(cairo_t *cr, struct wrap_box *box) @@ -197,18 +198,18 @@ static void render_boxes(struct wrap_line *line, cairo_t *cr, ImageStore *is, int j; double x_pos = 0.0; - for ( j=0; j<line->n_boxes; j++ ) { + for ( j=0; j<bv_len(line->boxes); j++ ) { struct wrap_box *box; cairo_save(cr); - box = &line->boxes[j]; + box = bv_box(line->boxes, j); cairo_translate(cr, x_pos, 0.0); //draw_outline(cr, box); - switch ( line->boxes[j].type ) { + switch ( box->type ) { case WRAP_BOX_PANGO : render_glyph_box(cr, box); @@ -231,8 +232,8 @@ static void render_boxes(struct wrap_line *line, cairo_t *cr, ImageStore *is, } - x_pos += pango_units_to_double(line->boxes[j].width); - x_pos += pango_units_to_double(line->boxes[j].sp); + x_pos += pango_units_to_double(box->width); + x_pos += pango_units_to_double(box->sp); cairo_restore(cr); diff --git a/src/sc_editor.c b/src/sc_editor.c index 48235c2..e5946ed 100644 --- a/src/sc_editor.c +++ b/src/sc_editor.c @@ -1,7 +1,7 @@ /* * sc_editor.c * - * Copyright © 2013-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -44,6 +44,7 @@ #include "sc_editor.h" #include "slideshow.h" #include "shape.h" +#include "boxvec.h" static void scroll_interface_init(GtkScrollable *iface) @@ -364,7 +365,7 @@ static void move_cursor_back(SCEditor *e) cl = e->cursor_line; line = &e->cursor_frame->lines[e->cursor_line]; - box = &line->boxes[e->cursor_box]; + box = bv_box(line->boxes, e->cursor_box); if ( box->type == WRAP_BOX_PANGO ) { if ( cp == 0 ) { @@ -389,13 +390,13 @@ static void move_cursor_back(SCEditor *e) if ( cl < 0 ) return; e->cursor_line = cl; line = &e->cursor_frame->lines[cl]; - cb = line->n_boxes - 1; + cb = bv_len(line->boxes) - 1; } - } while ( !line->boxes[cb].editable ); + } while ( !bv_box(line->boxes, cb)->editable ); e->cursor_box = cb; - box = &line->boxes[cb]; + box = bv_box(line->boxes, cb); if ( box->type == WRAP_BOX_PANGO ) { cp = box->len_chars; if ( box->space == WRAP_SPACE_NONE ) { @@ -420,11 +421,10 @@ void cur_box_diag(SCEditor *e) sbx = e->cursor_box; sps = e->cursor_pos; - struct wrap_box *sbox = &fr->lines[sln].boxes[sbx]; + struct wrap_box *sbox = bv_box(fr->lines[sln].boxes, sbx); printf("line/box/pos: [%i of %i]/[%i of %i]/[%i of %i]\n", - sln, fr->n_lines, - sbx, e->cursor_frame->lines[sln].n_boxes, + sln, fr->n_lines, sbx, bv_len(e->cursor_frame->lines[sln].boxes), sps, sbox->len_chars); printf("box type is %i, space type is %i\n", sbox->type, sbox->space); if ( sbox->type == WRAP_BOX_NOTHING ) { @@ -433,10 +433,10 @@ void cur_box_diag(SCEditor *e) struct wrap_line *ln = &fr->lines[sln]; int i; - for ( i=0; i<ln->n_boxes; i++ ) { + for ( i=0; i<bv_len(ln->boxes); i++ ) { char pp = '['; char pq = ']'; - struct wrap_box *bx = &ln->boxes[i]; + struct wrap_box *bx = bv_box(ln->boxes, i); if ( i == sbx ) { pp = '<'; pq = '>'; } printf("%c%i %i %i%c", pp, bx->offs_char, bx->len_chars, bx->n_segs, pq); @@ -450,7 +450,7 @@ void advance_cursor(SCEditor *e) int advance = 0; signed int cp, cb, cl; struct wrap_line *line = &e->cursor_frame->lines[e->cursor_line]; - struct wrap_box *box = &line->boxes[e->cursor_box]; + struct wrap_box *box = bv_box(line->boxes, e->cursor_box); cp = e->cursor_pos; cb = e->cursor_box; @@ -493,7 +493,7 @@ void advance_cursor(SCEditor *e) cp = 1; } - if ( cb >= line->n_boxes ) { + if ( cb >= bv_len(line->boxes) ) { cl++; if ( cl >= e->cursor_frame->n_lines ) { /* Give up - could not move */ @@ -504,7 +504,7 @@ void advance_cursor(SCEditor *e) cp = 0; } - } while ( !line->boxes[cb].editable ); + } while ( !bv_box(line->boxes, cb)->editable ); e->cursor_line = cl; e->cursor_box = cb; @@ -564,7 +564,7 @@ static void draw_caret(cairo_t *cr, struct frame *fr, if ( fr->n_lines == 0 ) return; /* Locate the cursor in a "logical" and "geographical" sense */ - box = &fr->lines[cursor_line].boxes[cursor_box]; + box = bv_box(fr->lines[cursor_line].boxes, cursor_box); get_cursor_pos(box, cursor_pos, &xposd, &yposd, &line_height); xposd += fr->pad_l; yposd += fr->pad_t; @@ -574,8 +574,8 @@ static void draw_caret(cairo_t *cr, struct frame *fr, } for ( i=0; i<cursor_box; i++ ) { - int w = fr->lines[cursor_line].boxes[i].width; - w += fr->lines[cursor_line].boxes[i].sp; + int w = bv_box(fr->lines[cursor_line].boxes, i)->width; + w += bv_box(fr->lines[cursor_line].boxes, i)->sp; xposd += pango_units_to_double(w); } @@ -717,12 +717,12 @@ static void fixup_cursor(SCEditor *e) if ( e->cursor_line >= fr->n_lines ) { /* We find ourselves on a line which doesn't exist */ e->cursor_line = fr->n_lines-1; - e->cursor_box = fr->lines[fr->n_lines-1].n_boxes-1; + e->cursor_box = bv_len(fr->lines[fr->n_lines-1].boxes)-1; } sline = &fr->lines[e->cursor_line]; - if ( e->cursor_box >= sline->n_boxes ) { + if ( e->cursor_box >= bv_len(sline->boxes) ) { /* We find ourselves in a box which doesn't exist */ @@ -736,12 +736,12 @@ static void fixup_cursor(SCEditor *e) /* There are no more lines, so just go to the end */ e->cursor_line = fr->n_lines-1; sline = &e->cursor_frame->lines[e->cursor_line]; - e->cursor_box = sline->n_boxes-1; + e->cursor_box = bv_len(sline->boxes)-1; } } - assert(e->cursor_box < sline->n_boxes); - sbox = &sline->boxes[e->cursor_box]; + assert(e->cursor_box < bv_len(sline->boxes)); + sbox = bv_box(sline->boxes, e->cursor_box); if ( e->cursor_pos > sbox->len_chars ) { advance_cursor(e); @@ -773,7 +773,7 @@ void insert_scblock(SCBlock *scblock, SCEditor *e) sln = e->cursor_line; sbx = e->cursor_box; sps = e->cursor_pos; - sbox = &e->cursor_frame->lines[sln].boxes[sbx]; + sbox = bv_box(e->cursor_frame->lines[sln].boxes, sbx); sc_insert_block(sbox->scblock, sps+sbox->offs_char, scblock); @@ -791,17 +791,11 @@ void insert_scblock(SCBlock *scblock, SCEditor *e) * Update the boxes from the StoryCode */ static void update_local(SCEditor *e, struct frame *fr, int line, int bn) { - struct wrap_box *box = &fr->lines[line].boxes[bn]; + struct wrap_box *box = bv_box(fr->lines[line].boxes, bn); /* Shape the box again * FIXME: Number of segments could change, need to PangoAnalyse again */ - shape_box(box->cf->cf); - - /* Update the segments */ - box->segs = box->cf->cf->segs; - box->n_segs = box->cf->cf->n_segs; - box->cf->segs = box->cf->cf->segs; - box->cf->n_segs = box->cf->cf->n_segs; + shape_box(box); /* Wrap the paragraph again */ wrap_contents(fr); /* FIXME: Only the current paragraph */ @@ -817,7 +811,7 @@ static void shift_box_offsets(struct frame *fr, struct wrap_box *box, int n) int sn = 0; for ( i=0; i<fr->boxes->n_boxes; i++ ) { - if ( &fr->boxes->boxes[i] == box ) { + if ( bv_box(fr->boxes, i) == box ) { sn = i+1; break; } @@ -826,7 +820,7 @@ static void shift_box_offsets(struct frame *fr, struct wrap_box *box, int n) assert(sn > 0); /* Lowest it can possibly be is 1 */ for ( i=sn; i<fr->boxes->n_boxes; i++ ) { - fr->boxes->boxes[i].offs_char += n; + bv_box(fr->boxes, i)->offs_char += n; } } @@ -851,10 +845,10 @@ static void insert_text(char *t, SCEditor *e) sln = e->cursor_line; sbx = e->cursor_box; sps = e->cursor_pos; - sbox = &e->cursor_frame->lines[sln].boxes[sbx]; + sbox = bv_box(e->cursor_frame->lines[sln].boxes, sbx); if ( sbox->type == WRAP_BOX_NOTHING ) { - printf("Upgrading nothing box to Pango box\n"); + printf("Upgrading nothing box %p to Pango box\n", sbox); sbox->type = WRAP_BOX_PANGO; sbox->col[0] = 0.0; sbox->col[1] = 0.0; @@ -899,7 +893,7 @@ static void insert_text(char *t, SCEditor *e) /* Add a new box containing the text after the break */ insert_box(&e->cursor_frame->lines[sln], sbx); - nbox = &e->cursor_frame->lines[sln].boxes[sbx]; + nbox = bv_box(e->cursor_frame->lines[sln].boxes, sbx); nbox->type = WRAP_BOX_PANGO; nbox->space = WRAP_SPACE_INTERWORD; nbox->len_chars = e->cursor_pos; @@ -916,15 +910,8 @@ static void insert_text(char *t, SCEditor *e) sbox->segs[sseg].len_chars += 1; - /* Update the length of the box in the unwrapped and un-paragraph-split - * string of wrap boxes */ - sbox->cf->cf->len_chars += 1; - - /* ... and also in the paragraph split but unwrapped box */ - sbox->cf->len_chars += 1; - /* Tweak the offsets of all the subsequent boxes */ - shift_box_offsets(fr, sbox->cf->cf, 1); + shift_box_offsets(fr, sbox, 1); fr->empty = 0; @@ -949,7 +936,7 @@ static void do_backspace(struct frame *fr, SCEditor *e) sln = e->cursor_line; sbx = e->cursor_box; sps = e->cursor_pos; - struct wrap_box *sbox = &e->cursor_frame->lines[sln].boxes[sbx]; + struct wrap_box *sbox = bv_box(e->cursor_frame->lines[sln].boxes, sbx); cur_box_diag(e); @@ -957,7 +944,7 @@ static void do_backspace(struct frame *fr, SCEditor *e) /* Delete may cross wrap boxes and maybe SCBlock boundaries */ struct wrap_line *fline = &e->cursor_frame->lines[e->cursor_line]; - struct wrap_box *fbox = &fline->boxes[e->cursor_box]; + struct wrap_box *fbox = bv_box(fline->boxes, e->cursor_box); // SCBlock *scbl = sbox->scblock; // do { @@ -975,15 +962,8 @@ static void do_backspace(struct frame *fr, SCEditor *e) // scbl = sc_block_next(scbl); // } while ( (scbl != fbox->scblock) && (scbl != NULL) ); - /* Update the length of the box in the unwrapped and un-paragraph-split - * string of wrap boxes */ - sbox->cf->cf->len_chars -= 1; - - /* ... and also in the paragraph split but unwrapped box */ - sbox->cf->len_chars -= 1; - /* Tweak the offsets of all the subsequent boxes */ - shift_box_offsets(fr, sbox->cf->cf, -1); + shift_box_offsets(fr, sbox, -1); update_local(e, fr, sln, sbx); @@ -1186,7 +1166,7 @@ static void calculate_box_size(struct frame *fr, SCEditor *e, static struct wrap_box *cbox(struct frame *fr, int ln, int bn) { - return &fr->lines[ln].boxes[bn]; + return bv_box(fr->lines[ln].boxes, bn);; } diff --git a/src/shape.c b/src/shape.c index 3664780..59ec024 100644 --- a/src/shape.c +++ b/src/shape.c @@ -33,6 +33,7 @@ #include "wrap.h" #include "sc_interp.h" #include "shape.h" +#include "boxvec.h" static void shape_segment(struct wrap_box *box, struct text_seg *seg) @@ -93,19 +94,17 @@ void shape_box(struct wrap_box *box) } -static void add_nothing_box(struct wrap_line *line, SCBlock *scblock, +static void add_nothing_box(struct boxvec *boxes, 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 = calloc(1, sizeof(struct wrap_box)); + if ( box == NULL ) { + fprintf(stderr, "Failed to allocate a nothing box.\n"); + return; } - - box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_NOTHING; box->scblock = scblock; box->offs_char = offs; @@ -118,7 +117,7 @@ static void add_nothing_box(struct wrap_line *line, SCBlock *scblock, box->editable = editable; box->segs = NULL; box->n_segs = 0; - line->n_boxes++; + bv_add(boxes, box); } @@ -185,7 +184,7 @@ static void add_seg(gpointer vi, gpointer vb) /* Add "text", followed by a space of type "space", to "line" */ -static int add_text_box(struct wrap_line *line, +static int add_text_box(struct boxvec *boxes, enum wrap_box_space space, PangoContext *pc, SCInterpreter *scin, SCBlock *bl, size_t offs, size_t len, int editable) @@ -199,17 +198,16 @@ static int add_text_box(struct wrap_line *line, int nseg; while ( len==0 ) { - add_nothing_box(line, bl, editable, space, scin, offs); + add_nothing_box(boxes, bl, editable, space, scin, offs); return 0; } /* Create the box */ - if ( line->n_boxes == line->max_boxes ) { - line->max_boxes += 32; - alloc_boxes(line); - if ( line->n_boxes == line->max_boxes ) return 1; + box = calloc(1, sizeof(struct wrap_box)); + if ( box == NULL ) { + fprintf(stderr, "Failed to allocate a text box.\n"); + return 1; } - box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_PANGO; box->space = space; @@ -218,7 +216,6 @@ static int add_text_box(struct wrap_line *line, box->editable = editable; box->ascent = sc_interp_get_ascent(scin); box->height = sc_interp_get_height(scin); - box->cf = NULL; /* Link to the actual text */ box->scblock = bl; @@ -248,24 +245,23 @@ static int add_text_box(struct wrap_line *line, calc_box_geometry(box); - line->n_boxes++; + bv_add(boxes, box); return 0; } -void add_callback_box(struct wrap_line *line, double w, double h, +void add_callback_box(struct boxvec *boxes, double w, double h, SCCallbackDrawFunc draw_func, SCCallbackClickFunc click_func, void *bvp, void *vp) { 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 = calloc(1, sizeof(struct wrap_box)); + if ( box == NULL ) { + fprintf(stderr, "Failed to allocate a callback box.\n"); + return; } - box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_CALLBACK; box->scblock = NULL; @@ -279,22 +275,21 @@ void add_callback_box(struct wrap_line *line, double w, double h, box->bvp = bvp; box->vp = vp; box->editable = 0; - line->n_boxes++; + bv_add(boxes, box); } -void add_image_box(struct wrap_line *line, const char *filename, +void add_image_box(struct boxvec *boxes, 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 = calloc(1, sizeof(struct wrap_box)); + if ( box == NULL ) { + fprintf(stderr, "Failed to allocate a callback box.\n"); + return; } - box = &line->boxes[line->n_boxes]; box->type = WRAP_BOX_IMAGE; box->scblock = NULL; box->offs_char = 0; @@ -304,11 +299,11 @@ void add_image_box(struct wrap_line *line, const char *filename, box->height = pango_units_from_double(h); box->filename = strdup(filename); box->editable = editable; - line->n_boxes++; + bv_add(boxes, box); } -int split_words(struct wrap_line *boxes, PangoContext *pc, SCBlock *bl, +int split_words(struct boxvec *boxes, PangoContext *pc, SCBlock *bl, PangoLanguage *lang, int editable, SCInterpreter *scin) { PangoLogAttr *log_attrs; diff --git a/src/shape.h b/src/shape.h index b9a5191..43775a3 100644 --- a/src/shape.h +++ b/src/shape.h @@ -33,14 +33,14 @@ extern void shape_box(struct wrap_box *box); -extern int split_words(struct wrap_line *boxes, PangoContext *pc, +extern int split_words(struct boxvec *boxes, PangoContext *pc, SCBlock *bl, PangoLanguage *lang, int editable, SCInterpreter *scin); -extern void add_image_box(struct wrap_line *line, const char *filename, +extern void add_image_box(struct boxvec *line, const char *filename, int w, int h, int editable); -extern void add_callback_box(struct wrap_line *line, double w, double h, +extern void add_callback_box(struct boxvec *boxes, double w, double h, SCCallbackDrawFunc draw_func, SCCallbackClickFunc click_func, void *bvp, void *vp); @@ -3,7 +3,7 @@ * * Text wrapping, hyphenation, justification etc * - * Copyright © 2013-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2013-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -39,6 +39,7 @@ #include "wrap.h" #include "frame.h" #include "presentation.h" +#include "boxvec.h" static void alloc_lines(struct frame *fr) @@ -55,32 +56,14 @@ static void alloc_lines(struct frame *fr) } -int alloc_boxes(struct wrap_line *l) -{ - struct wrap_box *boxes_new; - - boxes_new = realloc(l->boxes, l->max_boxes * sizeof(struct wrap_box)); - if ( boxes_new == NULL ) { - fprintf(stderr, "Couldn't allocate memory for boxes!\n"); - return 1; - } - - l->boxes = boxes_new; - return 0; -} - - void initialise_line(struct wrap_line *l) { - l->n_boxes = 0; - l->max_boxes = 32; - l->boxes = NULL; l->width = 0; l->height = 0; l->ascent = 0; l->last_line = 0; l->overfull = 0; - alloc_boxes(l); + l->boxes = bv_new(); } @@ -255,9 +238,9 @@ static int find_cursor_box(struct frame *fr, struct wrap_line *l, *end = 0; - for ( i=0; i<l->n_boxes; i++ ) { - double width = pango_units_to_double(l->boxes[i].width); - width += pango_units_to_double(l->boxes[i].sp); + for ( i=0; i<l->boxes->n_boxes; i++ ) { + double width = pango_units_to_double(bv_box(l->boxes, i)->width); + width += pango_units_to_double(bv_box(l->boxes, i)->sp); if ( xposd < x + width ) { *x_pos = xposd - x; return i; @@ -267,7 +250,7 @@ static int find_cursor_box(struct frame *fr, struct wrap_line *l, *end = 1; *x_pos = x; - return l->n_boxes-1; + return bv_len(l->boxes)-1; } @@ -297,11 +280,11 @@ void find_cursor(struct frame *fr, double xposd, double yposd, *line = ln; if ( end ) { - bn = l->n_boxes-1; + bn = l->boxes->n_boxes-1; } else { bn = find_cursor_box(fr, l, xposd, &x_pos, &end); } - b = &l->boxes[bn]; + b = bv_box(l->boxes, bn); *box = bn; if ( end ) { *pos = b->len_chars; @@ -363,9 +346,9 @@ static void calc_line_geometry(struct wrap_line *line) line->ascent = 0; line->height = 0; - for ( i=0; i<line->n_boxes; i++ ) { + for ( i=0; i<line->boxes->n_boxes; i++ ) { - struct wrap_box *box = &line->boxes[i]; + struct wrap_box *box = bv_box(line->boxes, i); line->width += box->width; if ( box->space == WRAP_SPACE_EOP ) box->sp = 0.0; @@ -476,19 +459,19 @@ static void consider_break(double sigma_prime, double sigma_prime_max, } -static double width(struct wrap_line *boxes, int i) +static double width(struct boxvec *boxes, int i) { /* Indices in Knuth paper go from 1...n. Indices in array go * from 0...n-1 */ - return boxes->boxes[i-1].width; + return bv_box(boxes, i-1)->width; } -static enum wrap_box_space space(struct wrap_line *boxes, int i) +static enum wrap_box_space space(struct boxvec *boxes, int i) { /* Indices in Knuth paper go from 1...n. Indices in array go * from 0...n-1 */ - return boxes->boxes[i-1].space; + return bv_box(boxes, i-1)->space; } @@ -503,13 +486,13 @@ static void UNUSED distribute_spaces(struct wrap_line *line, double l, l = pango_units_from_double(l); L = 0.0; Y = 0.0; Z = 0.0; - for ( i=0; i<line->n_boxes-1; i++ ) { - L += line->boxes[i].width; - L += sp_x(line->boxes[i].space); - Y += sp_y(line->boxes[i].space); - Z += sp_z(line->boxes[i].space); + for ( i=0; i<bv_len(line->boxes); i++ ) { + L += bv_box(line->boxes, i)->width; + L += sp_x(bv_box(line->boxes, i)->space); + Y += sp_y(bv_box(line->boxes, i)->space); + Z += sp_z(bv_box(line->boxes, i)->space); } - L += line->boxes[line->n_boxes-1].width; + L += bv_last(line->boxes)->width; if ( L < l ) { r = (l - L)/Y; @@ -520,24 +503,24 @@ static void UNUSED distribute_spaces(struct wrap_line *line, double l, } if ( r >= 0.0 ) { - for ( i=0; i<line->n_boxes-1; i++ ) { - line->boxes[i].sp = sp_x(line->boxes[i].space); - line->boxes[i].sp += r*sp_y(line->boxes[i].space); + for ( i=0; i<bv_len(line->boxes)-1; i++ ) { + bv_box(line->boxes, i)->sp = sp_x(bv_box(line->boxes, i)->space); + bv_box(line->boxes, i)->sp += r*sp_y(bv_box(line->boxes, i)->space); } } else { - for ( i=0; i<line->n_boxes-1; i++ ) { - line->boxes[i].sp = sp_x(line->boxes[i].space); - line->boxes[i].sp += r*sp_z(line->boxes[i].space); + for ( i=0; bv_len(line->boxes)-1; i++ ) { + bv_box(line->boxes, i)->sp = sp_x(bv_box(line->boxes, i)->space); + bv_box(line->boxes, i)->sp += r*sp_z(bv_box(line->boxes, i)->space); } } - line->boxes[line->n_boxes-1].sp = 0.0; + bv_box(line->boxes, bv_len(line->boxes)-1)->sp = 0.0; line->overfull = overfull; line->underfull = underfull; } -static void output_line(int q, int s, struct frame *fr, struct wrap_line *boxes) +static void output_line(int q, int s, struct frame *fr, struct boxvec *boxes) { struct wrap_line *l; int j; @@ -546,16 +529,14 @@ static void output_line(int q, int s, struct frame *fr, struct wrap_line *boxes) fr->n_lines++; initialise_line(l); - l->max_boxes = s-q; - alloc_boxes(l); + bv_ensure_space(l->boxes, s-q); for ( j=q; j<s; j++ ) { - l->boxes[l->n_boxes++] = boxes->boxes[j]; + bv_add(l->boxes, bv_box(boxes, j)); } } -static void output(int a, int i, int *p, struct frame *fr, - struct wrap_line *boxes) +static void output(int a, int i, int *p, struct frame *fr, struct boxvec *boxes) { int q = i; int r; @@ -590,7 +571,7 @@ static void output(int a, int i, int *p, struct frame *fr, * Practice and Experience 11 (1981) p1119-1184. Despite the name, it's * supposed to work as well as the full TeX algorithm in almost all of the cases * that we care about here. */ -static void UNUSED knuth_suboptimal_fit(struct wrap_line *boxes, +static void UNUSED knuth_suboptimal_fit(struct boxvec *boxes, double line_length, struct frame *fr, double rho) { @@ -607,15 +588,14 @@ static void UNUSED knuth_suboptimal_fit(struct wrap_line *boxes, n = boxes->n_boxes; /* Set the space for the last box to be "end of paragraph" */ - boxes->boxes[boxes->n_boxes-1].space = WRAP_SPACE_EOP; + bv_last(boxes)->space = WRAP_SPACE_EOP; /* Add empty zero-width box at end */ - if ( boxes->n_boxes == boxes->max_boxes ) { - boxes->max_boxes += 32; - alloc_boxes(boxes); - if ( boxes->n_boxes == boxes->max_boxes ) return; + box = malloc(sizeof(struct wrap_box)); + if ( box== NULL ) { + fprintf(stderr, "Couldn't allocate sentinel box\n"); + return; } - box = &boxes->boxes[boxes->n_boxes]; box->type = WRAP_BOX_SENTINEL; box->space = WRAP_SPACE_NONE; box->font = NULL; @@ -625,15 +605,15 @@ static void UNUSED knuth_suboptimal_fit(struct wrap_line *boxes, box->editable = 1; box->scblock = NULL; box->offs_char = 0; - boxes->n_boxes++; + bv_add(boxes, box); line_length *= PANGO_SCALE; reject = 0; - for ( j=0; j<boxes->n_boxes; j++ ) { - if ( boxes->boxes[j].width > line_length ) { + for ( j=0; j<bv_len(boxes); j++ ) { + if ( bv_box(boxes, j)->width > line_length ) { fprintf(stderr, "ERROR: Box %i too long (%i %f)\n", j, - boxes->boxes[j].width, line_length); + bv_box(boxes, j)->width, line_length); fr->trouble = 1; reject = 1; } @@ -772,6 +752,7 @@ static void UNUSED knuth_suboptimal_fit(struct wrap_line *boxes, free(p); free(s); + free(box); /* The sentinel box */ } @@ -792,16 +773,7 @@ static struct wrap_line *new_line(struct frame *fr) } -static int maybe_extend_line(struct wrap_line *l) -{ - if ( l->n_boxes < l->max_boxes ) return 0; - - l->max_boxes += 32; - return alloc_boxes(l); -} - - -static void first_fit(struct wrap_line *boxes, double line_length, +static void first_fit(struct boxvec *boxes, double line_length, struct frame *fr) { struct wrap_line *line; @@ -815,23 +787,20 @@ static void first_fit(struct wrap_line *boxes, double line_length, do { - boxes->boxes[j].sp = sp_x(boxes->boxes[j].space); + bv_box(boxes, j)->sp = sp_x(bv_box(boxes, j)->space); - len += boxes->boxes[j].width; + len += bv_box(boxes, j)->width; if ( len > line_length ) { line = new_line(fr); - len = boxes->boxes[j].width; + len = bv_box(boxes, j)->width; } - line->boxes[line->n_boxes] = boxes->boxes[j]; - line->boxes[line->n_boxes].cf = &boxes->boxes[j]; - line->n_boxes++; - if ( maybe_extend_line(line) ) return; + bv_add(line->boxes, bv_box(boxes, j)); j++; - if ( (j > 0) && (boxes->boxes[j-1].type != WRAP_BOX_SENTINEL) ) + if ( (j > 0) && (bv_box(boxes, j-1)->type != WRAP_BOX_SENTINEL) ) { - len += sp_x(boxes->boxes[j-1].space); + len += sp_x(bv_box(boxes, j-1)->space); } } while ( j < boxes->n_boxes ); @@ -842,66 +811,35 @@ static void first_fit(struct wrap_line *boxes, double line_length, void wrap_line_free(struct wrap_line *l) { - int i, j; - for ( i=0; i<l->n_boxes; i++ ) { - - switch ( l->boxes[i].type ) { - - case WRAP_BOX_PANGO : - for ( j=0; j<l->boxes[i].n_segs; j++ ) { - pango_glyph_string_free(l->boxes[i].segs[j].glyphs); - } - free(l->boxes[i].segs); - break; - - case WRAP_BOX_IMAGE : - break; - - case WRAP_BOX_CALLBACK : - break; - - case WRAP_BOX_NOTHING : - case WRAP_BOX_SENTINEL : - break; - - } - - } - + bv_free(l->boxes); free(l->boxes); } -static struct wrap_line *split_paragraph(struct wrap_line *boxes, int *n, - int *eop) +static struct boxvec *split_paragraph(struct boxvec *boxes, int *n, int *eop) { int i; int start = *n; int end; - if ( start >= boxes->n_boxes ) return NULL; + if ( start >= bv_len(boxes) ) return NULL; *eop = 0; - for ( i=start; i<boxes->n_boxes; i++ ) { - if ( boxes->boxes[i].space == WRAP_SPACE_EOP ) { + for ( i=start; i<bv_len(boxes); i++ ) { + if ( bv_box(boxes, i)->space == WRAP_SPACE_EOP ) { *eop = 1; break; } } end = i + 1; *n = end; - if ( i == boxes->n_boxes ) end--; + if ( i == bv_len(boxes) ) end--; if ( end-start > 0 ) { - struct wrap_line *para; - para = malloc(sizeof(struct wrap_line)); - para->boxes = NULL; - para->max_boxes = end-start; - para->n_boxes = end-start; - alloc_boxes(para); + struct boxvec *para = bv_new(); + bv_ensure_space(para, end-start); for ( i=start; i<end; i++ ) { - para->boxes[i-start] = boxes->boxes[i]; - para->boxes[i-start].cf = &boxes->boxes[i]; + bv_add(para, bv_box(boxes, i)); } return para; } @@ -910,7 +848,7 @@ static struct wrap_line *split_paragraph(struct wrap_line *boxes, int *n, } -void show_boxes(struct wrap_line *boxes) +void show_boxes(struct boxvec *boxes) { int i; @@ -919,8 +857,8 @@ void show_boxes(struct wrap_line *boxes) return; } - for ( i=0; i<boxes->n_boxes; i++ ) { - struct wrap_box *box = &boxes->boxes[i]; + for ( i=0; i<bv_len(boxes); i++ ) { + struct wrap_box *box = bv_box(boxes, i); char *box_text; printf("%3i", i); if ( box->scblock != NULL ) { @@ -971,7 +909,7 @@ static int wrap_everything(struct frame *fr, double wrap_w) * and generate fr->lines */ int wrap_contents(struct frame *fr) { - struct wrap_line *para; + struct boxvec *para; int i, eop = 0; //const double rho = 2.0; const double wrap_w = fr->w - fr->pad_l - fr->pad_r; @@ -1016,54 +954,6 @@ int wrap_contents(struct frame *fr) return 0; } - /* If the last paragraph ended with an EOP, add an extra line */ - if ( eop || (fr->n_lines == 0) ) { - - struct wrap_line *l; - struct wrap_box *last_box; - - if ( fr->n_lines > 0 ) { - l = &fr->lines[fr->n_lines-1]; - last_box = &l->boxes[l->n_boxes-1]; - } else { - last_box = NULL; - } - - if ( fr->n_lines + 1 > fr->max_lines ) { - fr->max_lines += 32; - alloc_lines(fr); - if ( fr->n_lines == fr->max_lines ) return 1; - } - - l = &fr->lines[fr->n_lines]; - fr->n_lines++; - initialise_line(l); - - l->max_boxes = 1; - alloc_boxes(l); - l->n_boxes = 1; - l->boxes[0].type = WRAP_BOX_NOTHING; - l->boxes[0].editable = 1; - l->boxes[0].space = WRAP_SPACE_NONE; - - if ( last_box != NULL ) { - l->boxes[0].scblock = last_box->scblock; - l->boxes[0].offs_char = last_box->len_chars - + last_box->offs_char; - l->boxes[0].ascent = last_box->ascent; - l->boxes[0].height = last_box->height; - l->boxes[0].width = 0; - /* FIXME: Get ascent and descent from font metrics for - * whichever font will be used in this box */ - } else { - l->boxes[0].scblock = find_last_child(fr->scblocks); - l->boxes[0].offs_char = 0; - l->boxes[0].ascent = 10000; - l->boxes[0].height = 10000; - l->boxes[0].width = 0; - } - } - for ( i=0; i<fr->n_lines; i++ ) { struct wrap_line *line = &fr->lines[i]; @@ -1071,8 +961,8 @@ int wrap_contents(struct frame *fr) //distribute_spaces(line, wrap_w, rho); /* Strip any sentinel boxes added by the wrapping algorithm */ - if ( line->boxes[line->n_boxes-1].type == WRAP_BOX_SENTINEL ) { - line->n_boxes--; + if ( bv_last(line->boxes)->type == WRAP_BOX_SENTINEL ) { + line->boxes->n_boxes--; } } @@ -1105,6 +995,8 @@ int insert_box(struct wrap_line *l, int pos) { int i; +/* FIXME ! */ +#if 0 if ( l->n_boxes == l->max_boxes ) { l->max_boxes += 32; if ( alloc_boxes(l) ) return 1; @@ -1116,6 +1008,8 @@ int insert_box(struct wrap_line *l, int pos) } l->n_boxes++; +#endif +return 1; return 0; } @@ -3,7 +3,7 @@ * * Text wrapping, hyphenation, justification and shaping * - * Copyright © 2014-2015 Thomas White <taw@bitwiz.org.uk> + * Copyright © 2014-2016 Thomas White <taw@bitwiz.org.uk> * * This file is part of Colloquium. * @@ -81,7 +81,6 @@ struct wrap_box SCBlock *scblock; int offs_char; /* offset (in characters, not bytes) into scblock */ - struct wrap_box *cf; /* Copied from */ /* Pango units */ int width; @@ -109,22 +108,20 @@ struct wrap_box }; +/* An actual wrap line, with geometry etc */ struct wrap_line { + struct boxvec *boxes; + int width; /* Pango units */ int height; /* Pango units */ int ascent; /* Pango units */ - int n_boxes; - int max_boxes; - struct wrap_box *boxes; - int overfull; int underfull; int last_line; }; - extern int wrap_contents(struct frame *fr); extern void get_cursor_pos(struct wrap_box *box, int pos, @@ -137,7 +134,7 @@ extern int alloc_boxes(struct wrap_line *l); extern void initialise_line(struct wrap_line *l); extern void wrap_line_free(struct wrap_line *l); -extern void show_boxes(struct wrap_line *boxes); +extern void show_boxes(struct boxvec *boxes); extern double total_height(struct frame *fr); extern int insert_box(struct wrap_line *l, int pos); |