X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fcairo.c;h=fa9b2e18725e89c5f8c6edd9ccf9d7e6ffda8495;hb=5b5099296b3c7212623991de8920e1459e234922;hp=87bca8cb449c5cebfb90bc5d7b9682092bc5d52f;hpb=00e10850124d68e722d9fba5b8c9467fff6863a3;p=pspp diff --git a/src/output/cairo.c b/src/output/cairo.c index 87bca8cb44..fa9b2e1872 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -89,6 +89,7 @@ enum xr_font_type XR_FONT_PROPORTIONAL, XR_FONT_EMPHASIS, XR_FONT_FIXED, + XR_FONT_MARKER, XR_N_FONTS }; @@ -131,6 +132,8 @@ struct xr_driver int line_space; /* Space between lines. */ int line_width; /* Width of lines. */ + int cell_margin; + int min_break[TABLE_N_AXES]; /* Min cell size to break across pages. */ struct xr_color bg; /* Background color */ @@ -157,13 +160,13 @@ static void xr_driver_run_fsm (struct xr_driver *); static void xr_draw_line (void *, int bb[TABLE_N_AXES][2], enum render_line_style styles[TABLE_N_AXES][2]); static void xr_measure_cell_width (void *, const struct table_cell *, - int *min, int *max); + int footnote_idx, int *min, int *max); static int xr_measure_cell_height (void *, const struct table_cell *, - int width); -static void xr_draw_cell (void *, const struct table_cell *, + int footnote_idx, int width); +static void xr_draw_cell (void *, const struct table_cell *, int footnote_idx, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]); -static int xr_adjust_break (void *, const struct table_cell *, +static int xr_adjust_break (void *, const struct table_cell *, int footnote_idx, int width, int height); static struct xr_render_fsm *xr_render_output_item ( @@ -280,8 +283,10 @@ apply_options (struct xr_driver *xr, struct string_map *o) "serif", font_size); xr->fonts[XR_FONT_EMPHASIS].desc = parse_font (d, o, "emph-font", "serif italic", font_size); + xr->fonts[XR_FONT_MARKER].desc = parse_font (d, o, "marker-font", "serif", + font_size * PANGO_SCALE_X_SMALL); - xr->line_gutter = parse_dimension (opt (d, o, "gutter", "3pt")) * scale; + xr->line_gutter = 0; xr->line_space = XR_POINT; xr->line_width = XR_POINT / 2; xr->page_number = 0; @@ -363,6 +368,7 @@ xr_set_cairo (struct xr_driver *xr, cairo_t *cairo) xr->char_width = MAX (xr->char_width, pango_to_xr (char_width)); xr->char_height = MAX (xr->char_height, pango_to_xr (char_height)); } + xr->cell_margin = xr->char_width; if (xr->params == NULL) { @@ -531,43 +537,6 @@ xr_flush (struct output_driver *driver) cairo_surface_flush (cairo_get_target (xr->cairo)); } -static void -xr_init_caption_cell (const char *caption, struct table_cell *cell, - struct cell_contents *contents) -{ - contents->options = TAB_LEFT; - contents->text = CONST_CAST (char *, caption); - contents->table = NULL; - cell->contents = contents; - cell->n_contents = 1; - cell->destructor = NULL; -} - -static struct render_page * -xr_render_table_item (struct xr_driver *xr, const struct table_item *item, - int *caption_widthp, int *caption_heightp) -{ - const char *caption = table_item_get_caption (item); - - if (caption != NULL) - { - /* XXX doesn't do well with very large captions */ - struct cell_contents contents; - int min_width, max_width; - struct table_cell cell; - - xr_init_caption_cell (caption, &cell, &contents); - - xr_measure_cell_width (xr, &cell, &min_width, &max_width); - *caption_widthp = MIN (max_width, xr->width); - *caption_heightp = xr_measure_cell_height (xr, &cell, *caption_widthp); - } - else - *caption_heightp = 0; - - return render_page_create (xr->params, table_item_get_table (item)); -} - static void xr_submit (struct output_driver *driver, const struct output_item *output_item) { @@ -664,7 +633,7 @@ xr_driver_run_fsm (struct xr_driver *xr) } static void -xr_layout_cell (struct xr_driver *, const struct table_cell *, +xr_layout_cell (struct xr_driver *, const struct table_cell *, int footnote_idx, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *width, int *height, int *brk); @@ -842,7 +811,7 @@ xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2], static void xr_measure_cell_width (void *xr_, const struct table_cell *cell, - int *min_width, int *max_width) + int footnote_idx, int *min_width, int *max_width) { struct xr_driver *xr = xr_; int bb[TABLE_N_AXES][2]; @@ -854,14 +823,20 @@ xr_measure_cell_width (void *xr_, const struct table_cell *cell, bb[V][0] = 0; bb[V][1] = INT_MAX; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - xr_layout_cell (xr, cell, bb, clip, max_width, &h, NULL); + xr_layout_cell (xr, cell, footnote_idx, bb, clip, max_width, &h, NULL); bb[H][1] = 1; - xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL); + xr_layout_cell (xr, cell, footnote_idx, bb, clip, min_width, &h, NULL); + + if (*min_width > 0) + *min_width += xr->cell_margin * 2; + if (*max_width > 0) + *max_width += xr->cell_margin * 2; } static int -xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width) +xr_measure_cell_height (void *xr_, const struct table_cell *cell, + int footnote_idx, int width) { struct xr_driver *xr = xr_; int bb[TABLE_N_AXES][2]; @@ -869,26 +844,32 @@ xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width) int w, h; bb[H][0] = 0; - bb[H][1] = width; + bb[H][1] = width - xr->cell_margin * 2; + if (bb[H][1] <= 0) + return 0; bb[V][0] = 0; bb[V][1] = INT_MAX; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - xr_layout_cell (xr, cell, bb, clip, &w, &h, NULL); + xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, NULL); return h; } static void -xr_draw_cell (void *xr_, const struct table_cell *cell, +xr_draw_cell (void *xr_, const struct table_cell *cell, int footnote_idx, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]) { struct xr_driver *xr = xr_; int w, h, brk; - xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk); + bb[H][0] += xr->cell_margin; + bb[H][1] -= xr->cell_margin; + if (bb[H][0] >= bb[H][1]) + return; + xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, &brk); } static int -xr_adjust_break (void *xr_, const struct table_cell *cell, +xr_adjust_break (void *xr_, const struct table_cell *cell, int footnote_idx, int width, int height) { struct xr_driver *xr = xr_; @@ -896,15 +877,17 @@ xr_adjust_break (void *xr_, const struct table_cell *cell, int clip[TABLE_N_AXES][2]; int w, h, brk; - if (xr_measure_cell_height (xr_, cell, width) < height) + if (xr_measure_cell_height (xr_, cell, footnote_idx, width) < height) return -1; bb[H][0] = 0; - bb[H][1] = width; + bb[H][1] = width - 2 * xr->cell_margin; + if (bb[H][1] <= 0) + return 0; bb[V][0] = 0; bb[V][1] = height; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk); + xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, &brk); return brk; } @@ -923,21 +906,99 @@ xr_clip (struct xr_driver *xr, int clip[TABLE_N_AXES][2]) } } +static void +add_attr_with_start (PangoAttrList *list, PangoAttribute *attr, guint start_index) +{ + attr->start_index = start_index; + pango_attr_list_insert (list, attr); +} + static int xr_layout_cell_text (struct xr_driver *xr, - const struct cell_contents *contents, + const struct cell_contents *contents, int footnote_idx, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int y, int *widthp, int *brk) { unsigned int options = contents->options; struct xr_font *font; + bool merge_footnotes; + size_t length; int w, h; + if (contents->n_footnotes == 0) + merge_footnotes = false; + else if (contents->n_footnotes == 1 && (options & TAB_ALIGNMENT) == TAB_RIGHT) + { + PangoAttrList *attrs; + char marker[16]; + + font = &xr->fonts[XR_FONT_MARKER]; + + str_format_26adic (footnote_idx + 1, false, marker, sizeof marker); + pango_layout_set_text (font->layout, marker, strlen (marker)); + + attrs = pango_attr_list_new (); + pango_attr_list_insert (attrs, pango_attr_rise_new (7000)); + pango_layout_set_attributes (font->layout, attrs); + pango_attr_list_unref (attrs); + + pango_layout_get_size (font->layout, &w, &h); + merge_footnotes = w > xr->cell_margin; + if (!merge_footnotes && clip[H][0] != clip[H][1]) + { + cairo_save (xr->cairo); + xr_clip (xr, clip); + cairo_translate (xr->cairo, + xr_to_pt (bb[H][1] + xr->x), + xr_to_pt (y + xr->y)); + pango_layout_set_alignment (font->layout, PANGO_ALIGN_LEFT); + pango_layout_set_width (font->layout, -1); + pango_cairo_show_layout (xr->cairo, font->layout); + cairo_restore (xr->cairo); + } + + pango_layout_set_attributes (font->layout, NULL); + } + else + merge_footnotes = true; + font = (options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED] : options & TAB_EMPH ? &xr->fonts[XR_FONT_EMPHASIS] : &xr->fonts[XR_FONT_PROPORTIONAL]); - pango_layout_set_text (font->layout, contents->text, -1); + length = strlen (contents->text); + if (merge_footnotes) + { + PangoAttrList *attrs; + struct string s; + size_t i; + + bb[H][1] += xr->cell_margin; + + ds_init_empty (&s); + ds_extend (&s, length + contents->n_footnotes * 10); + ds_put_cstr (&s, contents->text); + for (i = 0; i < contents->n_footnotes; i++) + { + char marker[16]; + + if (i > 0) + ds_put_byte (&s, ','); + str_format_26adic (footnote_idx + i + 1, false, marker, sizeof marker); + ds_put_cstr (&s, marker); + } + pango_layout_set_text (font->layout, ds_cstr (&s), ds_length (&s)); + ds_destroy (&s); + + attrs = pango_attr_list_new (); + add_attr_with_start (attrs, pango_attr_rise_new (7000), length); + add_attr_with_start ( + attrs, pango_attr_font_desc_new (xr->fonts[XR_FONT_MARKER].desc), length); + pango_layout_set_attributes (font->layout, attrs); + pango_attr_list_unref (attrs); + } + else + pango_layout_set_text (font->layout, contents->text, -1); pango_layout_set_alignment ( font->layout, @@ -1035,19 +1096,21 @@ xr_layout_cell_text (struct xr_driver *xr, } } } + + pango_layout_set_attributes (font->layout, NULL); return y + h; } static int xr_layout_cell_subtable (struct xr_driver *xr, const struct cell_contents *contents, + int footnote_idx UNUSED, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *widthp, int *brk) { - const struct table *table = contents->table; int single_width, double_width; struct render_params params; - struct render_page *page; + struct render_pager *p; int r[TABLE_N_AXES][2]; int width, height; int i; @@ -1073,11 +1136,11 @@ xr_layout_cell_subtable (struct xr_driver *xr, } xr->nest++; - page = render_page_create (¶ms, table); - width = render_page_get_size (page, H); - height = render_page_get_size (page, V); + p = render_pager_create (¶ms, contents->table); + width = render_pager_get_size (p, H); + height = render_pager_get_size (p, V); if (bb[V][0] + height >= bb[V][1]) - *brk = bb[V][0] + render_page_get_best_breakpoint (page, bb[V][1] - bb[V][0]); + *brk = bb[V][0] + render_pager_get_best_breakpoint (p, bb[V][1] - bb[V][0]); /* r = intersect(bb, clip) - bb. */ for (i = 0; i < TABLE_N_AXES; i++) @@ -1099,13 +1162,13 @@ xr_layout_cell_subtable (struct xr_driver *xr, else if (alignment == TAB_CENTER) xr->x += (params.size[H] - width) / 2; xr->y += bb[V][0]; - render_page_draw_region (page, r[H][0], r[V][0], - r[H][1] - r[H][0], r[V][1] - r[V][0]); + render_pager_draw_region (p, r[H][0], r[V][0], + r[H][1] - r[H][0], r[V][1] - r[V][0]); xr->y -= bb[V][0]; xr->x = save_x; cairo_restore (xr->cairo); } - render_page_unref (page); + render_pager_destroy (p); xr->nest--; if (width > *widthp) @@ -1115,6 +1178,7 @@ xr_layout_cell_subtable (struct xr_driver *xr, static void xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell, + int footnote_idx, int bb_[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *width, int *height, int *brk) { @@ -1161,29 +1225,15 @@ xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell, } if (contents->text) - bb[V][0] = xr_layout_cell_text (xr, contents, bb, clip, + bb[V][0] = xr_layout_cell_text (xr, contents, footnote_idx, bb, clip, bb[V][0], width, brk); else - bb[V][0] = xr_layout_cell_subtable (xr, contents, bb, clip, width, brk); + bb[V][0] = xr_layout_cell_subtable (xr, contents, footnote_idx, + bb, clip, width, brk); + footnote_idx += contents->n_footnotes; } *height = bb[V][0] - bb_[V][0]; } - -static void -xr_draw_title (struct xr_driver *xr, const char *title, - int title_width, int title_height) -{ - struct cell_contents contents; - struct table_cell cell; - int bb[TABLE_N_AXES][2]; - - xr_init_caption_cell (title, &cell, &contents); - bb[H][0] = 0; - bb[H][1] = title_width; - bb[V][0] = 0; - bb[V][1] = title_height; - xr_draw_cell (xr, &cell, bb, bb); -} struct output_driver_factory pdf_driver_factory = { "pdf", "pspp.pdf", xr_pdf_create }; @@ -1207,10 +1257,8 @@ struct xr_rendering struct output_item *item; /* Table items. */ - struct render_page *page; + struct render_pager *p; struct xr_driver *xr; - int title_width; - int title_height; }; #define CHART_WIDTH 500 @@ -1285,8 +1333,7 @@ xr_rendering_create (struct xr_driver *xr, const struct output_item *item, r->item = output_item_ref (item); r->xr = xr; xr_set_cairo (xr, cr); - r->page = xr_render_table_item (xr, to_table_item (item), - &r->title_width, &r->title_height); + r->p = render_pager_create (xr->params, to_table_item (item)); } else if (is_chart_item (item)) { @@ -1303,7 +1350,7 @@ xr_rendering_destroy (struct xr_rendering *r) if (r) { output_item_unref (r->item); - render_page_unref (r->page); + render_pager_destroy (r->p); free (r); } } @@ -1313,10 +1360,8 @@ xr_rendering_measure (struct xr_rendering *r, int *w, int *h) { if (is_table_item (r->item)) { - int w0 = render_page_get_size (r->page, H); - int w1 = r->title_width; - *w = MAX (w0, w1) / XR_POINT; - *h = (render_page_get_size (r->page, V) + r->title_height) / XR_POINT; + *w = render_pager_get_size (r->p, H) / XR_POINT; + *h = render_pager_get_size (r->p, V) / XR_POINT; } else { @@ -1340,17 +1385,10 @@ xr_rendering_draw (struct xr_rendering *r, cairo_t *cr, xr_set_cairo (xr, cr); - if (r->title_height > 0) - { - xr->y = 0; - xr_draw_title (xr, table_item_get_caption (to_table_item (r->item)), - r->title_width, r->title_height); - } - - xr->y = r->title_height; - render_page_draw_region (r->page, - x * XR_POINT, (y * XR_POINT) - r->title_height, - w * XR_POINT, h * XR_POINT); + xr->y = 0; + render_pager_draw_region (r->p, + x * XR_POINT, y * XR_POINT, + w * XR_POINT, h * XR_POINT); } else xr_draw_chart (to_chart_item (r->item), cr, @@ -1437,7 +1475,6 @@ struct xr_table_state struct xr_render_fsm fsm; struct table_item *table_item; struct render_pager *p; - int caption_height; }; static bool @@ -1447,29 +1484,16 @@ xr_table_render (struct xr_render_fsm *fsm, struct xr_driver *xr) while (render_pager_has_next (ts->p)) { - int space = xr->length - xr->y - ts->caption_height; - struct render_page *slice = render_pager_next (ts->p, space); + int used; - if (!slice) + used = render_pager_draw_next (ts->p, xr->length - xr->y); + if (!used) { assert (xr->y > 0); return true; } - - if (ts->caption_height) - { - if (xr->cairo) - xr_draw_title (xr, table_item_get_caption (ts->table_item), - xr->width, ts->caption_height); - - xr->y += ts->caption_height; - ts->caption_height = 0; - } - - if (xr->cairo) - render_page_draw (slice); - xr->y += render_page_get_size (slice, V); - render_page_unref (slice); + else + xr->y += used; } return false; } @@ -1488,8 +1512,6 @@ static struct xr_render_fsm * xr_render_table (struct xr_driver *xr, const struct table_item *table_item) { struct xr_table_state *ts; - struct render_page *page; - int caption_width; ts = xmalloc (sizeof *ts); ts->fsm.render = xr_table_render; @@ -1499,11 +1521,7 @@ xr_render_table (struct xr_driver *xr, const struct table_item *table_item) if (xr->y > 0) xr->y += xr->char_height; - page = xr_render_table_item (xr, table_item, - &caption_width, &ts->caption_height); - xr->params->size[V] = xr->length - ts->caption_height; - - ts->p = render_pager_create (page); + ts->p = render_pager_create (xr->params, table_item); return &ts->fsm; }