aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2012-12-10 00:09:41 +0100
committerThomas White <taw@bitwiz.org.uk>2012-12-10 00:09:41 +0100
commite01d6d8d4d429ebb8ec8d3b8c9ad56f89891fef1 (patch)
treeec9f1a6a55b1450e4d06468cd972d64985d1833a
parentdfb4e34da6565028d94858d837cba3a1ea04850d (diff)
WIP on paragraph renderer
-rw-r--r--src/render.c261
-rw-r--r--tests/render_test.c1
2 files changed, 180 insertions, 82 deletions
diff --git a/src/render.c b/src/render.c
index 1a885cb..512f260 100644
--- a/src/render.c
+++ b/src/render.c
@@ -29,7 +29,6 @@
#include <cairo-pdf.h>
#include <pango/pangocairo.h>
#include <assert.h>
-#include <gdk/gdk.h>
#include <string.h>
#include <stdlib.h>
@@ -41,20 +40,56 @@
#include "render.h"
+enum wrap_box_type
+{
+ WRAP_BOX_PANGO,
+};
+
+
+struct wrap_box
+{
+ enum wrap_box_type type;
+
+ /* WRAP_BOX_PANGO */
+ PangoGlyphItem *glyph_item;
+ const char *text;
+};
+
+
+struct wrap_line
+{
+ int n_boxes;
+ struct wrap_box *boxes;
+};
+
+
struct renderstuff
{
cairo_t *cr;
PangoContext *pc;
PangoFontMap *fontmap;
- PangoLogAttr *log_attrs;
- struct frame *fr;
+ PangoAttrList *attrs;
+
+ /* Text for the block currently being processed */
+ const char *cur_text;
+ PangoLogAttr *cur_log_attrs;
+
+ double ascent;
+ double descent;
+
double width;
double height;
- double ascent;
+
+ double wrap_w;
+
+ /* Lines of boxes, where each box can be a load of glyphs, an image,
+ * etc */
+ int n_lines;
+ struct wrap_line *lines;
};
-static void calc_width(gpointer data, gpointer user_data)
+static void wrap_text(gpointer data, gpointer user_data)
{
struct renderstuff *s = user_data;
PangoItem *item = data;
@@ -63,7 +98,7 @@ static void calc_width(gpointer data, gpointer user_data)
glyphs = pango_glyph_string_new();
- pango_shape(s->fr->sc+item->offset, item->length, &item->analysis,
+ pango_shape(s->cur_text+item->offset, item->length, &item->analysis,
glyphs);
pango_glyph_string_extents_range(glyphs, item->offset,
@@ -74,82 +109,136 @@ static void calc_width(gpointer data, gpointer user_data)
s->width += extents.width;
s->height = extents.height; /* FIXME: Total rubbish */
s->ascent = PANGO_ASCENT(extents);
+ s->descent = PANGO_DESCENT(extents);
pango_glyph_string_free(glyphs);
}
-static void render_segment(gpointer data, gpointer user_data)
+static void process_sc_block(struct renderstuff *s, const char *sc_name,
+ const char *sc_options, const char *sc_contents)
{
- struct renderstuff *s = user_data;
- PangoItem *item = data;
- PangoGlyphString *glyphs;
- PangoGlyphItem gitem;
- GdkColor col;
+ 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;
+ }
- glyphs = pango_glyph_string_new();
+ /* Empty block? */
+ if ( sc_contents == NULL ) return;
- pango_shape(s->fr->sc+item->offset, item->length, &item->analysis,
- glyphs);
+ len = strlen(sc_contents);
+ if ( len == 0 ) return;
- gitem.item = item;
- gitem.glyphs = glyphs;
+ s->cur_log_attrs = calloc(len+1, sizeof(PangoLogAttr));
+ if ( s->cur_log_attrs == NULL ) {
+ fprintf(stderr, "Failed to allocate memory for log attrs\n");
+ return;
+ }
- /* FIXME: Honour alpha as well */
- gdk_color_parse("#000000", &col);
- gdk_cairo_set_source_color(s->cr, &col);
- cairo_set_source_rgb(s->cr, 0.0, 1.0, 0.0);
- pango_cairo_show_glyph_item(s->cr, s->fr->sc+item->offset, &gitem);
+ pango_get_log_attrs(sc_contents, len, -1, pango_language_get_default(),
+ s->cur_log_attrs, len+1);
- pango_glyph_string_free(glyphs);
- pango_item_free(item);
+ /* Create glyph string */
+ item_list = pango_itemize(s->pc, sc_contents, 0, len, s->attrs, NULL);
+ s->cur_text = sc_contents;
+ g_list_foreach(item_list, wrap_text, &s);
+
+ g_list_free(item_list);
+ free(s->cur_log_attrs);
+}
+
+
+static void render_boxes(struct wrap_line *line, struct renderstuff *s)
+{
+ int j;
+ double x_pos = 0.0;
+
+ for ( j=0; j<line->n_boxes; j++ ) {
+
+ struct wrap_box *box;
+
+ box = &line->boxes[j];
+ cairo_rel_move_to(s->cr, x_pos, 0.0);
+
+ switch ( line->boxes[j].type ) {
+
+ case WRAP_BOX_PANGO :
+ pango_cairo_show_glyph_item(s->cr, box->text,
+ box->glyph_item);
+ x_pos += pango_glyph_string_get_width(box->glyph_item->glyphs);
+ break;
+
+ }
+
+ }
+}
+
+
+static void render_lines(struct renderstuff *s)
+{
+ int i;
+ double spacing = (s->ascent+s->descent)/PANGO_SCALE;
+ double ascent = s->ascent/PANGO_SCALE;
+
+ cairo_set_source_rgba(s->cr, 0.4, 0.0, 0.7, 1.0);
+ for ( i=0; i<s->n_lines; i++ ) {
+
+ /* Move to beginning of the line */
+ cairo_move_to(s->cr, 0.0, ascent + i*spacing);
+
+ /* Render the line */
+ render_boxes(&s->lines[i], s);
+
+ }
}
/* Render Level 1 Storycode (no subframes) */
-int render_sc(struct frame *fr, cairo_t *cr, double max_w, double max_h)
+static int render_sc(struct frame *fr, double max_w, double max_h)
{
PangoFontDescription *fontdesc;
struct renderstuff s;
- GList *list;
double w, h;
- int len;
- PangoAttrList *attrs;
PangoAttribute *attr_font;
+ SCBlockList *bl;
+ SCBlockListIterator *iter;
+ struct scblock *b;
if ( fr->sc == NULL ) return 0;
- s.pc = pango_cairo_create_context(cr);
- s.fr = fr;
+ bl = sc_find_blocks(fr->sc, NULL);
- /* If a minimum size is set, start there */
- if ( fr->lop.use_min_w ) w = fr->lop.min_w;
- if ( fr->lop.use_min_h ) h = fr->lop.min_h;
+ if ( bl == NULL ) {
+ printf("Failed to find blocks.\n");
+ return 0;
+ }
- /* FIXME: Handle images as well */
+ s.wrap_w = max_w;
/* Find and load font */
s.fontmap = pango_cairo_font_map_get_default();
- fontdesc = pango_font_description_from_string("Sans 24");
+ s.pc = pango_font_map_create_context(s.fontmap);
+ fontdesc = pango_font_description_from_string("Sorts Mill Goudy Bold 24");
- attrs = pango_attr_list_new();
+ /* 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(attrs, attr_font);
+ pango_attr_list_insert_before(s.attrs, attr_font);
pango_font_description_free(fontdesc);
- len = strlen(fr->sc);
- s.log_attrs = calloc(len+1, sizeof(PangoLogAttr));
- if ( s.log_attrs == NULL ) {
- fprintf(stderr, "Failed to allocate memory for log attrs\n");
- return 1;
+ /* 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);
}
- pango_get_log_attrs(fr->sc, len, -1,
- pango_language_get_default(), s.log_attrs, len+1);
-
- /* Create glyph string */
- list = pango_itemize(s.pc, fr->sc, 0, strlen(fr->sc), attrs, NULL);
- s.width = 0;
- g_list_foreach(list, calc_width, &s);
+ sc_block_list_free(bl);
/* Determine width */
w = s.width / PANGO_SCALE;
@@ -169,20 +258,13 @@ int render_sc(struct frame *fr, cairo_t *cr, double max_w, double max_h)
/* Having decided on the size, create surface and render the contents */
if ( fr->contents != NULL ) cairo_surface_destroy(fr->contents);
fr->contents = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
- cr = cairo_create(fr->contents);
- s.cr = cr;
+ s.cr = cairo_create(fr->contents);
- cairo_rectangle(cr, w/2, h/2, w/2, h/2);
- cairo_set_source_rgb(cr, 0.0, 0.8, 1.0);
- cairo_fill(cr);
+ cairo_translate(s.cr, -fr->lop.pad_l, -fr->lop.pad_t);
+ render_lines(&s);
- cairo_move_to(cr, fr->lop.pad_l, fr->lop.pad_t + s.ascent/PANGO_SCALE);
- g_list_foreach(list, render_segment, &s);
-
- cairo_destroy(cr);
- g_list_free(list);
- free(s.log_attrs);
- pango_attr_list_unref(attrs);
+ cairo_destroy(s.cr);
+ pango_attr_list_unref(s.attrs);
g_object_unref(s.pc);
fr->w = w;
@@ -192,7 +274,7 @@ int render_sc(struct frame *fr, cairo_t *cr, double max_w, double max_h)
}
-static void get_max_size(struct frame *fr, struct frame *parent,
+static int get_max_size(struct frame *fr, struct frame *parent,
int this_subframe, double fixed_x, double fixed_y,
double parent_max_width, double parent_max_height,
double *p_width, double *p_height)
@@ -236,6 +318,7 @@ static void get_max_size(struct frame *fr, struct frame *parent,
*p_width = w;
*p_height = h;
+ return 0;
}
@@ -269,34 +352,48 @@ static void position_frame(struct frame *fr, struct frame *parent)
static int render_frame(struct frame *fr, cairo_t *cr,
double max_w, double max_h)
{
- int i;
+ if ( fr->num_children > 0 ) {
- /* Render all subframes */
- for ( i=0; i<fr->num_children; i++ ) {
+ int i;
- double x, y, child_max_w, child_max_h;
- struct frame *ch = fr->children[i];
+ /* Render all subframes */
+ for ( i=0; i<fr->num_children; i++ ) {
- if ( ch->style != NULL ) {
- memcpy(&ch->lop, &ch->style->lop,
- sizeof(struct layout_parameters));
- }
+ double x, y, child_max_w, child_max_h;
+ struct frame *ch = fr->children[i];
+ int changed;
- /* Determine the maximum possible size this subframe can be */
- get_max_size(ch, fr, i, x, y,
- max_w, max_h, &child_max_w, &child_max_h);
+ if ( ch->style != NULL ) {
+ memcpy(&ch->lop, &ch->style->lop,
+ sizeof(struct layout_parameters));
+ }
- /* Render it and hence (recursives) find out how much space it
- * actually needs.*/
- render_frame(ch, cr, child_max_w, child_max_h);
+ get_max_size(ch, fr, i, x, y, max_w, max_h,
+ &child_max_w, &child_max_h);
- /* Position the frame within the parent */
- position_frame(ch, fr);
+ do {
- }
+ /* Render it and hence (recursively) find out
+ * how much space it actually needs.*/
+ render_frame(ch, cr, child_max_w, child_max_h);
+
+ changed = get_max_size(ch, fr, i, x, y,
+ max_w, max_h,
+ &child_max_w,
+ &child_max_h);
+
+ } while ( changed );
+
+ /* Position the frame within the parent */
+ position_frame(ch, fr);
+
+ }
+
+ } else {
- /* Render the actual contents of this frame in the remaining space */
- render_sc(fr, cr, max_w, max_h);
+ render_sc(fr, max_w, max_h);
+
+ }
return 0;
}
diff --git a/tests/render_test.c b/tests/render_test.c
index fcc77fc..1d667a7 100644
--- a/tests/render_test.c
+++ b/tests/render_test.c
@@ -104,6 +104,7 @@ int main(int argc, char *argv[])
fr2 = calloc(1, sizeof(struct frame));
if ( fr2 == NULL ) return 1;
fr2->sc = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.";
+ //fr2->sc = "Lorem ipsum AT";
fr2->children = NULL;
fr2->num_children = 0;
fr2->style = sty2;