aboutsummaryrefslogtreecommitdiff
path: root/src/render.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/render.c')
-rw-r--r--src/render.c416
1 files changed, 72 insertions, 344 deletions
diff --git a/src/render.c b/src/render.c
index 0650f96..3077c36 100644
--- a/src/render.c
+++ b/src/render.c
@@ -38,293 +38,22 @@
#include "presentation.h"
#include "frame.h"
#include "render.h"
+#include "wrap.h"
-struct renderstuff
+static void render_glyph_box(cairo_t *cr, struct wrap_box *box)
{
- cairo_t *cr;
- PangoContext *pc;
- PangoFontMap *fontmap;
- PangoAttrList *attrs;
-
- /* Text for the block currently being processed */
- const char *cur_text;
- int cur_len;
-
- int wrap_w; /* Pango units */
-
- struct frame *fr;
-};
-
-
-static void free_line_bits(struct wrap_line *l)
-{
- int i;
- for ( i=0; i<l->n_boxes; i++ ) {
-
- switch ( l->boxes[i].type ) {
-
- case WRAP_BOX_PANGO :
- pango_glyph_item_free(l->boxes[i].glyph_item);
- free(l->boxes[i].text);
- break;
-
- }
-
- }
-
- free(l->boxes);
-}
-
-
-static void alloc_lines(struct frame *fr)
-{
- struct wrap_line *lines_new;
-
- lines_new = realloc(fr->lines, fr->max_lines * sizeof(struct wrap_line));
- if ( lines_new == NULL ) {
- fprintf(stderr, "Couldn't allocate memory for lines!\n");
- return;
- }
-
- fr->lines = lines_new;
-}
-
-
-static void 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;
- }
-
- l->boxes = boxes_new;
-}
-
-
-static void add_glyph_box_to_line(struct wrap_line *line, PangoGlyphItem *gi,
- char *text)
-{
- PangoRectangle rect;
- int ascent;
-
- if ( line->n_boxes == line->max_boxes ) {
- line->max_boxes += 32;
- alloc_boxes(line);
- if ( line->n_boxes == line->max_boxes ) return;
- }
-
- pango_glyph_string_extents(gi->glyphs, gi->item->analysis.font,
- NULL, &rect);
-
- line->boxes[line->n_boxes].type = WRAP_BOX_PANGO;
- line->boxes[line->n_boxes].glyph_item = gi;
- line->boxes[line->n_boxes].text = text;
- line->boxes[line->n_boxes].width = rect.width;
- line->n_boxes++;
-
- line->width += rect.width;
- if ( line->height < rect.height ) line->height = rect.height;
-
- ascent = PANGO_ASCENT(rect);
- if ( ascent > line->ascent ) line->ascent = ascent;
-}
-
-
-static const char *add_chars_to_line(struct renderstuff *s,
- PangoGlyphItem *orig, int n,
- const char *cur_text_ptr)
-{
- int split_len;
- char *split_ptr;
- char *before_text;
-
- split_ptr = g_utf8_offset_to_pointer(cur_text_ptr, n);
- before_text = strndup(cur_text_ptr, split_ptr-cur_text_ptr);
- if ( before_text == NULL ) {
- fprintf(stderr, "Failed to split text\n");
- /* But continue */
- }
-
- if ( n < orig->item->num_chars ) {
-
- PangoGlyphItem *before;
-
- split_len = split_ptr - cur_text_ptr;
-
- before = pango_glyph_item_split(orig, cur_text_ptr, split_len);
-
- add_glyph_box_to_line(&s->fr->lines[s->fr->n_lines],
- before, before_text);
-
- orig->item->offset = 0;
-
- } else {
-
- PangoGlyphItem *copy;
- copy = pango_glyph_item_copy(orig);
- add_glyph_box_to_line(&s->fr->lines[s->fr->n_lines],
- copy, before_text);
-
- }
-
- return split_ptr;
-}
-
-
-static 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;
- alloc_boxes(l);
-}
-
-
-static void dispatch_line(struct renderstuff *s)
-{
- s->fr->n_lines++;
-
- if ( s->fr->n_lines == s->fr->max_lines ) {
- s->fr->max_lines += 32;
- alloc_lines(s->fr);
- if ( s->fr->n_lines == s->fr->max_lines ) return;
- }
-
- initialise_line(&s->fr->lines[s->fr->n_lines]);
-}
-
-
-static void wrap_text(gpointer data, gpointer user_data)
-{
- struct renderstuff *s = user_data;
- PangoItem *item = data;
- PangoGlyphString *glyphs;
- PangoLogAttr *log_attrs;
- PangoGlyphItem gitem;
- int *log_widths;
- int width_remain;
- int width_used;
- int i, pos, n;
- const char *ptr;
-
- log_attrs = calloc(item->num_chars+1, sizeof(PangoLogAttr));
- if ( log_attrs == NULL ) {
- fprintf(stderr, "Failed to allocate memory for log attrs\n");
- return;
- }
-
- log_widths = calloc(item->num_chars+1, sizeof(int));
- if ( log_widths == NULL ) {
- fprintf(stderr, "Failed to allocate memory for log widths\n");
- return;
- }
-
- pango_get_log_attrs(s->cur_text, s->cur_len, -1,
- pango_language_get_default(),
- log_attrs, item->num_chars+1);
-
- glyphs = pango_glyph_string_new();
- pango_shape(s->cur_text+item->offset, item->length, &item->analysis,
- glyphs);
-
- pango_glyph_string_get_logical_widths(glyphs, s->cur_text+item->offset,
- item->length, 0, log_widths);
- gitem.glyphs = glyphs;
- gitem.item = item;
-
- /* FIXME: Replace this with a real typesetting algorithm */
- width_remain = s->wrap_w*PANGO_SCALE
- - s->fr->lines[s->fr->n_lines].width;
- width_used = 0;
- pos = 0;
- n = item->num_chars;
- ptr = s->cur_text;
- for ( i=0; i<n; i++ ) {
-
- if ( !log_attrs[i].is_char_break ) {
- width_used += log_widths[i];
- pos++;
- continue;
- }
-
- if ( log_attrs[i].is_mandatory_break
- || (log_widths[i] + width_used > width_remain) ) {
-
- ptr = add_chars_to_line(s, &gitem, pos, ptr);
-
- /* New line */
- dispatch_line(s);
- width_remain = s->wrap_w * PANGO_SCALE;
- width_used = 0;
- pos = 0;
-
- }
-
- pos++;
- width_used += log_widths[i];
-
- }
- ptr = add_chars_to_line(s, &gitem, pos, ptr);
-
- /* Don't dispatch the last line, because the next item might add
- * more text to it, or the next SC block might add something else. */
-
- free(log_widths);
- free(log_attrs);
-}
-
-
-static void process_sc_block(struct renderstuff *s, const char *sc_name,
- const char *sc_options, const char *sc_contents)
-{
- size_t len;
- GList *item_list;
-
- /* Only process textual blocks, for now */
- if ( sc_name != NULL ) return;
- if ( sc_options != NULL ) {
- fprintf(stderr, "Block has options. WTF?\n");
- return;
- }
-
- /* Empty block? */
- if ( sc_contents == NULL ) return;
-
- len = strlen(sc_contents);
- if ( len == 0 ) return;
-
- /* Create glyph string */
- item_list = pango_itemize(s->pc, sc_contents, 0, len, s->attrs, NULL);
- s->cur_text = sc_contents;
- s->cur_len = len;
- g_list_foreach(item_list, wrap_text, s);
-
- g_list_free(item_list);
-}
-
-
-static double render_glyph_box(cairo_t *cr, struct wrap_box *box)
-{
- double box_w;
- if ( box->glyph_item == NULL ) {
+ if ( box->glyphs == NULL ) {
fprintf(stderr, "Box %p has NULL pointer.\n", box);
- return 0.0;
+ return;
}
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); /* FIXME: Colour */
- pango_cairo_show_glyph_item(cr, box->text, box->glyph_item);
- box_w = pango_glyph_string_get_width(box->glyph_item->glyphs);
- return box_w;
+ cairo_set_source_rgba(cr, box->col[0], box->col[1], box->col[2],
+ box->col[3]);
+ pango_cairo_glyph_string_path(cr, box->font, box->glyphs);
}
-static void render_boxes(struct wrap_line *line, struct renderstuff *s)
+static void render_boxes(struct wrap_line *line, cairo_t *cr)
{
int j;
double x_pos = 0.0;
@@ -333,65 +62,89 @@ static void render_boxes(struct wrap_line *line, struct renderstuff *s)
struct wrap_box *box;
- cairo_save(s->cr);
+ cairo_save(cr);
box = &line->boxes[j];
- cairo_rel_move_to(s->cr, x_pos, 0.0);
+ cairo_rel_move_to(cr, x_pos, 0.0);
switch ( line->boxes[j].type ) {
case WRAP_BOX_PANGO :
- render_glyph_box(s->cr, box);
+ render_glyph_box(cr, box);
+ break;
+
+ case WRAP_BOX_IMAGE :
+ /* FIXME ! */
break;
}
x_pos += (double)line->boxes[j].width / PANGO_SCALE;
- cairo_restore(s->cr);
+ cairo_restore(cr);
}
}
-static void render_lines(struct renderstuff *s)
+static void render_lines(struct frame *fr, cairo_t *cr)
{
int i;
double y_pos = 0.0;
- for ( i=0; i<s->fr->n_lines; i++ ) {
+ for ( i=0; i<fr->n_lines; i++ ) {
- double asc = s->fr->lines[i].ascent/PANGO_SCALE;
+ double asc = fr->lines[i].ascent/PANGO_SCALE;
- //cairo_move_to(s->cr, 0, y_pos+asc+0.5);
- //cairo_line_to(s->cr, s->lines[i].width, y_pos+asc+0.5);
- //cairo_set_source_rgb(s->cr, 0.0, 0.0, 0.0);
- //cairo_set_line_width(s->cr, 1.0);
- //cairo_stroke(s->cr);
+ //cairo_move_to(cr, 0, y_pos+asc+0.5);
+ //cairo_line_to(cr, s->lines[i].width, y_pos+asc+0.5);
+ //cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ //cairo_set_line_width(cr, 1.0);
+ //cairo_stroke(cr);
/* Move to beginning of the line */
- cairo_move_to(s->cr, 0.0, asc+y_pos);
+ cairo_move_to(cr, 0.0, asc+y_pos);
/* Render the line */
- render_boxes(&s->fr->lines[i], s);
+ render_boxes(&fr->lines[i], cr);
/* FIXME: line spacing */
- y_pos += s->fr->lines[i].height/PANGO_SCALE + 0.0;
+ y_pos += fr->lines[i].height/PANGO_SCALE + 0.0;
+
+ }
+}
+
+
+static void free_line_bits(struct wrap_line *l)
+{
+ int i;
+ for ( i=0; i<l->n_boxes; i++ ) {
+
+ switch ( l->boxes[i].type ) {
+
+ case WRAP_BOX_PANGO :
+ pango_glyph_string_free(l->boxes[i].glyphs);
+ free(l->boxes[i].text);
+ break;
+
+ case WRAP_BOX_IMAGE :
+ break;
+
+ }
}
+
+ free(l->boxes);
}
/* Render Level 1 Storycode (no subframes) */
static int render_sc(struct frame *fr)
{
- PangoFontDescription *fontdesc;
- struct renderstuff s;
- PangoAttribute *attr_font;
- SCBlockList *bl;
- SCBlockListIterator *iter;
- struct scblock *b;
int i;
+ cairo_t *cr;
+ PangoFontMap *fontmap;
+ PangoContext *pc;
for ( i=0; i<fr->n_lines; i++ ) {
free_line_bits(&fr->lines[i]);
@@ -403,62 +156,37 @@ static int render_sc(struct frame *fr)
if ( fr->sc == NULL ) return 0;
- bl = sc_find_blocks(fr->sc, NULL);
-
- if ( bl == NULL ) {
- printf("Failed to find blocks.\n");
- return 0;
- }
-
- s.wrap_w = fr->w - fr->lop.pad_l - fr->lop.pad_r;
- s.fr = fr;
- s.fr->lines = NULL;
- s.fr->n_lines = 0;
- s.fr->max_lines = 64;
- alloc_lines(s.fr);
- initialise_line(&s.fr->lines[0]);
-
- /* Find and load font */
- s.fontmap = pango_cairo_font_map_get_default();
- s.pc = pango_font_map_create_context(s.fontmap);
- fontdesc = pango_font_description_from_string("Sorts Mill Goudy 16");
-
- /* Set up attribute list to use the font */
- s.attrs = pango_attr_list_new();
- attr_font = pango_attr_font_desc_new(fontdesc);
- pango_attr_list_insert_before(s.attrs, attr_font);
- pango_font_description_free(fontdesc);
-
- /* Iterate through SC blocks and send each one in turn for processing */
- for ( b = sc_block_list_first(bl, &iter);
- b != NULL;
- b = sc_block_list_next(bl, iter) )
- {
- process_sc_block(&s, b->name, b->options, b->contents);
- }
- sc_block_list_free(bl);
- dispatch_line(&s);
-
- /* Create surface and render the contents */
+ /* Create surface and Cairo stuff */
if ( fr->contents != NULL ) cairo_surface_destroy(fr->contents);
fr->contents = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
fr->w, fr->h);
- s.cr = cairo_create(fr->contents);
+ cr = cairo_create(fr->contents);
cairo_font_options_t *fopts;
fopts = cairo_font_options_create();
cairo_font_options_set_hint_style(fopts, CAIRO_HINT_STYLE_NONE);
cairo_font_options_set_hint_metrics(fopts, CAIRO_HINT_METRICS_DEFAULT);
cairo_font_options_set_antialias(fopts, CAIRO_ANTIALIAS_GRAY);
- cairo_set_font_options(s.cr, fopts);
+ cairo_set_font_options(cr, fopts);
- cairo_translate(s.cr, fr->lop.pad_l, fr->lop.pad_t);
- render_lines(&s);
+ /* Find and load font */
+ fontmap = pango_cairo_font_map_get_default();
+ pc = pango_font_map_create_context(fontmap);
+ /* Set up lines */
+ if ( wrap_contents(fr, pc) ) {
+ fprintf(stderr, "Failed to wrap lines.\n");
+ return 1;
+ }
+
+ /* Actually render the lines */
+ cairo_translate(cr, fr->lop.pad_l, fr->lop.pad_t);
+ render_lines(fr, cr);
+
+ /* Tidy up */
cairo_font_options_destroy(fopts);
- cairo_destroy(s.cr);
- pango_attr_list_unref(s.attrs);
- g_object_unref(s.pc);
+ cairo_destroy(cr);
+ g_object_unref(pc);
return 0;
}