X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fcairo-fsm.c;h=2b47615be58d8fd9010123267e1c6f5014168181;hb=f8659933d48c5682010d1e1f04ae7acb5cbcd611;hp=39f1cf02e990fd33ff345975f35daac2dd88aaff;hpb=61b107f4f5e3ee7a468c91bc7fa269e268c5bc84;p=pspp diff --git a/src/output/cairo-fsm.c b/src/output/cairo-fsm.c index 39f1cf02e9..2b47615be5 100644 --- a/src/output/cairo-fsm.c +++ b/src/output/cairo-fsm.c @@ -38,9 +38,12 @@ #include "output/charts/scree.h" #include "output/charts/spreadlevel-plot.h" #include "output/group-item.h" +#include "output/image-item.h" #include "output/message-item.h" #include "output/page-eject-item.h" #include "output/page-setup-item.h" +#include "output/pivot-output.h" +#include "output/pivot-table.h" #include "output/render.h" #include "output/table-item.h" #include "output/text-item.h" @@ -74,9 +77,8 @@ xr_fsm_style_unshare (struct xr_fsm_style *old) struct xr_fsm_style *new = xmemdup (old, sizeof *old); new->ref_cnt = 1; - for (int i = 0; i < XR_N_FONTS; i++) - if (old->fonts[i]) - new->fonts[i] = pango_font_description_copy (old->fonts[i]); + if (old->font) + new->font = pango_font_description_copy (old->font); return new; } @@ -89,8 +91,7 @@ xr_fsm_style_unref (struct xr_fsm_style *style) assert (style->ref_cnt > 0); if (!--style->ref_cnt) { - for (size_t i = 0; i < XR_N_FONTS; i++) - pango_font_description_free (style->fonts[i]); + pango_font_description_free (style->font); free (style); } } @@ -104,29 +105,42 @@ xr_fsm_style_equals (const struct xr_fsm_style *a, || a->size[V] != b->size[V] || a->min_break[H] != b->min_break[H] || a->min_break[V] != b->min_break[V] + || !pango_font_description_equal (a->font, b->font) || a->use_system_colors != b->use_system_colors + || a->object_spacing != b->object_spacing || a->font_resolution != b->font_resolution) return false; - for (size_t i = 0; i < XR_N_FONTS; i++) - if (!pango_font_description_equal (a->fonts[i], b->fonts[i])) - return false; - return true; } +/* Renders a single output_item to an output device in one of two ways: + + - 'print == true': Broken across multiple pages if necessary. + + - 'print == false': In a single region that the user may scroll around if + needed. + + Normally 'output_item' corresponds to a single rendering. There is a + special case when 'print == true' and 'output_item' is a table_item with + multiple layers and 'item->pt->table_look->print_all_layers == true'. In + that case, each layer is rendered separately from the FSM's internal point + of view; from the client's point of view, it is all one operation. +*/ struct xr_fsm { struct xr_fsm_style *style; struct output_item *item; + bool print; + + /* Print mode only. */ + bool done; /* Table items only. */ + size_t *layer_indexes; struct render_params rp; struct render_pager *p; cairo_t *cairo; /* XXX should this be here?! */ - - /* Chart and page-eject items only. */ - bool done; }; /* The unit used for internal measurements is inch/(72 * XR_POINT). @@ -416,31 +430,32 @@ xrr_measure_cell_width (void *xr_, const struct table_cell *cell, bb[H][1] = 1; xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL); + const int (*margin)[2] = cell->cell_style->margin; if (*min_width > 0) - *min_width += px_to_xr (cell->style->cell_style.margin[H][0] - + cell->style->cell_style.margin[H][1]); + *min_width += px_to_xr (margin[H][0] + margin[H][1]); if (*max_width > 0) - *max_width += px_to_xr (cell->style->cell_style.margin[H][0] - + cell->style->cell_style.margin[H][1]); + *max_width += px_to_xr (margin[H][0] + margin[H][1]); } static int xrr_measure_cell_height (void *xr_, const struct table_cell *cell, int width) { struct xr_fsm *xr = xr_; - int bb[TABLE_N_AXES][2]; - int clip[TABLE_N_AXES][2]; - int w, h; - bb[H][0] = 0; - bb[H][1] = width - px_to_xr (cell->style->cell_style.margin[H][0] - + cell->style->cell_style.margin[H][1]); - bb[V][0] = 0; - bb[V][1] = INT_MAX; - clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; + const int (*margin)[2] = cell->cell_style->margin; + + int bb[TABLE_N_AXES][2] = { + [H][0] = 0, + [H][1] = width - px_to_xr (margin[H][0] + margin[H][1]), + [V][0] = 0, + [V][1] = INT_MAX, + }; + + int clip[TABLE_N_AXES][2] = { { 0, 0 }, { 0, 0 } }; + + int w, h; xr_layout_cell (xr, cell, bb, clip, &w, &h, NULL); - h += px_to_xr (cell->style->cell_style.margin[V][0] - + cell->style->cell_style.margin[V][1]); + h += px_to_xr (margin[V][0] + margin[V][1]); return h; } @@ -455,7 +470,7 @@ xrr_draw_cell (void *xr_, const struct table_cell *cell, int color_idx, struct xr_fsm *xr = xr_; int w, h, brk; - const struct cell_color *bg = &cell->style->font_style.bg[color_idx]; + const struct cell_color *bg = &cell->font_style->bg[color_idx]; if ((bg->r != 255 || bg->g != 255 || bg->b != 255) && bg->alpha) { cairo_save (xr->cairo); @@ -481,14 +496,14 @@ xrr_draw_cell (void *xr_, const struct table_cell *cell, int color_idx, } cairo_save (xr->cairo); if (!xr->style->use_system_colors) - xr_set_source_rgba (xr->cairo, &cell->style->font_style.fg[color_idx]); + xr_set_source_rgba (xr->cairo, &cell->font_style->fg[color_idx]); bb[V][0] += valign_offset; for (int axis = 0; axis < TABLE_N_AXES; axis++) { - bb[axis][0] += px_to_xr (cell->style->cell_style.margin[axis][0]); - bb[axis][1] -= px_to_xr (cell->style->cell_style.margin[axis][1]); + bb[axis][0] += px_to_xr (cell->cell_style->margin[axis][0]); + bb[axis][1] -= px_to_xr (cell->cell_style->margin[axis][1]); } if (bb[H][0] < bb[H][1] && bb[V][0] < bb[V][1]) xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk); @@ -500,22 +515,24 @@ xrr_adjust_break (void *xr_, const struct table_cell *cell, int width, int height) { struct xr_fsm *xr = xr_; - int bb[TABLE_N_AXES][2]; - int clip[TABLE_N_AXES][2]; - int w, h, brk; if (xrr_measure_cell_height (xr_, cell, width) < height) return -1; - bb[H][0] = 0; - bb[H][1] = width - px_to_xr (cell->style->cell_style.margin[H][0] - + cell->style->cell_style.margin[H][1]); + const int (*margin)[2] = cell->cell_style->margin; + + int bb[TABLE_N_AXES][2] = { + [H][0] = 0, + [V][0] = 0, + [H][1] = width - px_to_xr (margin[H][0] + margin[H][1]), + [V][1] = height - px_to_xr (margin[V][0] + margin[V][1]), + }; if (bb[H][1] <= 0) return 0; - bb[V][0] = 0; - bb[V][1] = height - px_to_xr (cell->style->cell_style.margin[V][0] - + cell->style->cell_style.margin[V][1]); - clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; + + int clip[TABLE_N_AXES][2] = { { 0, 0 }, { 0, 0 } }; + + int w, h, brk; xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk); return brk; } @@ -552,10 +569,9 @@ add_attr (PangoAttrList *list, PangoAttribute *attr, } static void -markup_escape (struct string *out, unsigned int options, - const char *in, size_t len) +markup_escape (struct string *out, bool markup, const char *in, size_t len) { - if (!(options & TAB_MARKUP)) + if (!markup) { ds_put_substring (out, ss_buffer (in, len == -1 ? strlen (in) : len)); return; @@ -623,17 +639,15 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *widthp, int *brk) { - const struct font_style *font_style = &cell->style->font_style; - const struct cell_style *cell_style = &cell->style->cell_style; + const struct pivot_table *pt = to_table_item (xr->item)->pt; + const struct font_style *font_style = cell->font_style; + const struct cell_style *cell_style = cell->cell_style; unsigned int options = cell->options; enum table_axis X = options & TAB_ROTATE ? V : H; enum table_axis Y = !X; int R = options & TAB_ROTATE ? 0 : 1; - enum xr_font_type font_type = (options & TAB_FIX - ? XR_FONT_FIXED - : XR_FONT_PROPORTIONAL); PangoFontDescription *desc = NULL; if (font_style->typeface) desc = parse_font ( @@ -641,7 +655,7 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, font_style->size ? font_style->size * 1000 : 10000, font_style->bold, font_style->italic); if (!desc) - desc = xr->style->fonts[font_type]; + desc = xr->style->font; assert (xr->cairo); PangoContext *context = pango_cairo_create_context (xr->cairo); @@ -651,14 +665,19 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, pango_layout_set_font_description (layout, desc); - const char *text = cell->text; + struct string body = DS_EMPTY_INITIALIZER; + bool numeric = pivot_value_format_body (cell->value, pt, &body); + enum table_halign halign = table_halign_interpret ( - cell_style->halign, cell->options & TAB_NUMERIC); - if (cell_style->halign == TABLE_HALIGN_DECIMAL && !(options & TAB_ROTATE)) + cell->cell_style->halign, numeric); + + if (cell_style->halign == TABLE_HALIGN_DECIMAL + && !(cell->options & TAB_ROTATE)) { int margin_adjustment = -px_to_xr (cell_style->decimal_offset); - const char *decimal = strrchr (text, cell_style->decimal_char); + const char *decimal = strrchr (ds_cstr (&body), + cell_style->decimal_char); if (decimal) { pango_layout_set_text (layout, decimal, strlen (decimal)); @@ -670,7 +689,6 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, bb[H][1] += margin_adjustment; } - struct string tmp = DS_EMPTY_INITIALIZER; PangoAttrList *attrs = NULL; /* Deal with an oddity of the Unicode line-breaking algorithm (or perhaps in @@ -687,33 +705,39 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, happen with grouping like 1,234,567.89 or 1.234.567,89 because if groups are present then there will always be a digit on both sides of every period and comma. */ - if (options & TAB_MARKUP) + bool markup = cell->font_style->markup; + if (markup) { PangoAttrList *new_attrs; char *new_text; - if (pango_parse_markup (text, -1, 0, &new_attrs, &new_text, NULL, NULL)) + if (pango_parse_markup (ds_cstr (&body), -1, 0, + &new_attrs, &new_text, NULL, NULL)) { attrs = new_attrs; - tmp.ss = ss_cstr (new_text); - tmp.capacity = tmp.ss.length; + ds_destroy (&body); + body.ss = ss_cstr (new_text); + body.capacity = body.ss.length; } else { /* XXX should we report the error? */ - ds_put_cstr (&tmp, text); } } else if (options & TAB_ROTATE || bb[H][1] != INT_MAX) { + const char *text = ds_cstr (&body); const char *decimal = text + strcspn (text, ".,"); if (decimal[0] && c_isdigit (decimal[1]) && (decimal == text || !c_isdigit (decimal[-1]))) { - ds_extend (&tmp, strlen (text) + 16); - markup_escape (&tmp, options, text, decimal - text + 1); + struct string tmp = DS_EMPTY_INITIALIZER; + ds_extend (&tmp, ds_length (&body) + 16); + markup_escape (&tmp, markup, text, decimal - text + 1); ds_put_unichar (&tmp, 0x2060 /* U+2060 WORD JOINER */); - markup_escape (&tmp, options, decimal + 1, -1); + markup_escape (&tmp, markup, decimal + 1, -1); + ds_swap (&tmp, &body); + ds_destroy (&tmp); } } @@ -725,39 +749,36 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, PANGO_UNDERLINE_SINGLE)); } - if (cell->n_footnotes || cell->n_subscripts) + const struct pivot_value *value = cell->value; + if (value->n_footnotes || value->n_subscripts) { - /* If we haven't already put TEXT into tmp, do it now. */ - if (ds_is_empty (&tmp)) - { - ds_extend (&tmp, strlen (text) + 16); - markup_escape (&tmp, options, text, -1); - } - - size_t subscript_ofs = ds_length (&tmp); - for (size_t i = 0; i < cell->n_subscripts; i++) + size_t subscript_ofs = ds_length (&body); + for (size_t i = 0; i < value->n_subscripts; i++) { if (i) - ds_put_byte (&tmp, ','); - ds_put_cstr (&tmp, cell->subscripts[i]); + ds_put_byte (&body, ','); + ds_put_cstr (&body, value->subscripts[i]); } - size_t footnote_ofs = ds_length (&tmp); - for (size_t i = 0; i < cell->n_footnotes; i++) + size_t footnote_ofs = ds_length (&body); + for (size_t i = 0; i < value->n_footnotes; i++) { if (i) - ds_put_byte (&tmp, ','); - ds_put_cstr (&tmp, cell->footnotes[i]->marker); + ds_put_byte (&body, ','); + + size_t idx = value->footnote_indexes[i]; + const struct pivot_footnote *f = pt->footnotes[idx]; + pivot_value_format (f->marker, pt, &body); } /* Allow footnote markers to occupy the right margin. That way, numbers in the column are still aligned. */ - if (cell->n_footnotes && halign == TABLE_HALIGN_RIGHT) + if (value->n_footnotes && halign == TABLE_HALIGN_RIGHT) { /* Measure the width of the footnote marker, so we know how much we need to make room for. */ - pango_layout_set_text (layout, ds_cstr (&tmp) + footnote_ofs, - ds_length (&tmp) - footnote_ofs); + pango_layout_set_text (layout, ds_cstr (&body) + footnote_ofs, + ds_length (&body) - footnote_ofs); PangoAttrList *fn_attrs = pango_attr_list_new (); pango_attr_list_insert ( @@ -787,10 +808,10 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, PANGO_ATTR_INDEX_TO_TEXT_END); add_attr (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL), subscript_ofs, PANGO_ATTR_INDEX_TO_TEXT_END); - if (cell->n_subscripts) + if (value->n_subscripts) add_attr (attrs, pango_attr_rise_new (-3000), subscript_ofs, footnote_ofs - subscript_ofs); - if (cell->n_footnotes) + if (value->n_footnotes) add_attr (attrs, pango_attr_rise_new (3000), footnote_ofs, PANGO_ATTR_INDEX_TO_TEXT_END); } @@ -803,11 +824,7 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, } /* Set the text. */ - if (ds_is_empty (&tmp)) - pango_layout_set_text (layout, text, -1); - else - pango_layout_set_text (layout, ds_cstr (&tmp), ds_length (&tmp)); - ds_destroy (&tmp); + pango_layout_set_text (layout, ds_cstr (&body), ds_length (&body)); pango_layout_set_alignment (layout, (halign == TABLE_HALIGN_RIGHT ? PANGO_ALIGN_RIGHT @@ -921,9 +938,10 @@ xr_layout_cell_text (struct xr_fsm *xr, const struct table_cell *cell, pango_layout_set_attributes (layout, NULL); - if (desc != xr->style->fonts[font_type]) + if (desc != xr->style->font) pango_font_description_free (desc); g_object_unref (G_OBJECT (layout)); + ds_destroy (&body); return h; } @@ -957,9 +975,10 @@ xr_layout_cell (struct xr_fsm *xr, const struct table_cell *cell, #define CHART_WIDTH 500 #define CHART_HEIGHT 375 -struct xr_fsm * +static struct xr_fsm * xr_fsm_create (const struct output_item *item_, - const struct xr_fsm_style *style, cairo_t *cr) + const struct xr_fsm_style *style, cairo_t *cr, + bool print) { if (is_page_setup_item (item_) || is_group_open_item (item_) @@ -969,6 +988,7 @@ xr_fsm_create (const struct output_item *item_, struct output_item *item; if (is_table_item (item_) || is_chart_item (item_) + || is_image_item (item_) || is_page_eject_item (item_)) item = output_item_ref (item_); else if (is_message_item (item_)) @@ -992,14 +1012,25 @@ xr_fsm_create (const struct output_item *item_, item = table_item_super ( text_item_to_table_item ( text_item_create (TEXT_ITEM_TITLE, - to_group_open_item (item_)->command_name))); + to_group_open_item (item_)->command_name, + NULL))); } else NOT_REACHED (); assert (is_table_item (item) || is_chart_item (item) + || is_image_item (item) || is_page_eject_item (item)); + size_t *layer_indexes = NULL; + if (is_table_item (item)) + { + const struct table_item *table_item = to_table_item (item); + layer_indexes = pivot_output_next_layer (table_item->pt, NULL, print); + if (!layer_indexes) + return NULL; + } + static const struct render_ops xrr_render_ops = { .measure_cell_width = xrr_measure_cell_width, .measure_cell_height = xrr_measure_cell_height, @@ -1024,6 +1055,8 @@ xr_fsm_create (const struct output_item *item_, *fsm = (struct xr_fsm) { .style = xr_fsm_style_ref (style), .item = item, + .print = print, + .layer_indexes = layer_indexes, .rp = { .ops = &xrr_render_ops, .aux = fsm, @@ -1032,41 +1065,49 @@ xr_fsm_create (const struct output_item *item_, .min_break = { [H] = style->min_break[H], [V] = style->min_break[V] }, .supports_margins = true, .rtl = render_direction_rtl (), + .printing = print, } }; - if (is_table_item (item)) - { - fsm->cairo = cr; - fsm->p = render_pager_create (&fsm->rp, to_table_item (item)); - fsm->cairo = NULL; - } + /* Get font size. */ + PangoContext *context = pango_cairo_create_context (cr); + pango_cairo_context_set_resolution (context, style->font_resolution); + PangoLayout *layout = pango_layout_new (context); + g_object_unref (context); - for (int i = 0; i < XR_N_FONTS; i++) - { - PangoContext *context = pango_cairo_create_context (cr); - pango_cairo_context_set_resolution (context, style->font_resolution); - PangoLayout *layout = pango_layout_new (context); - g_object_unref (context); + pango_layout_set_font_description (layout, style->font); - pango_layout_set_font_description (layout, style->fonts[i]); + pango_layout_set_text (layout, "0", 1); - pango_layout_set_text (layout, "0", 1); + int char_size[TABLE_N_AXES]; + pango_layout_get_size (layout, &char_size[H], &char_size[V]); + for (int a = 0; a < TABLE_N_AXES; a++) + { + int csa = pango_to_xr (char_size[a]); + fsm->rp.font_size[a] = MAX (fsm->rp.font_size[a], csa); + } - int char_size[TABLE_N_AXES]; - pango_layout_get_size (layout, &char_size[H], &char_size[V]); - for (int a = 0; a < TABLE_N_AXES; a++) - { - int csa = pango_to_xr (char_size[a]); - fsm->rp.font_size[a] = MAX (fsm->rp.font_size[a], csa); - } + g_object_unref (G_OBJECT (layout)); + + if (is_table_item (item)) + { + struct table_item *table_item = to_table_item (item); - g_object_unref (G_OBJECT (layout)); + fsm->cairo = cr; + fsm->p = render_pager_create (&fsm->rp, table_item, fsm->layer_indexes); + fsm->cairo = NULL; } return fsm; } +struct xr_fsm * +xr_fsm_create_for_printing (const struct output_item *item, + const struct xr_fsm_style *style, cairo_t *cr) +{ + return xr_fsm_create (item, style, cr, true); +} + void xr_fsm_destroy (struct xr_fsm *fsm) { @@ -1074,17 +1115,27 @@ xr_fsm_destroy (struct xr_fsm *fsm) { xr_fsm_style_unref (fsm->style); output_item_unref (fsm->item); + free (fsm->layer_indexes); render_pager_destroy (fsm->p); assert (!fsm->cairo); free (fsm); } } + +/* Scrolling API. */ + +struct xr_fsm * +xr_fsm_create_for_scrolling (const struct output_item *item, + const struct xr_fsm_style *style, cairo_t *cr) +{ + return xr_fsm_create (item, style, cr, false); +} -/* This is primarily meant for use with screen rendering since the result is a - fixed value for charts. */ void xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp) { + assert (!fsm->print); + int w, h; if (is_table_item (fsm->item)) @@ -1099,6 +1150,12 @@ xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp) w = CHART_WIDTH; h = CHART_HEIGHT; } + else if (is_image_item (fsm->item)) + { + cairo_surface_t *image = to_image_item (fsm->item)->image; + w = cairo_image_surface_get_width (image); + h = cairo_image_surface_get_height (image); + } else NOT_REACHED (); @@ -1108,38 +1165,10 @@ xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp) *hp = h; } -static int -xr_fsm_draw_table (struct xr_fsm *fsm, int space) -{ - return (render_pager_has_next (fsm->p) - ? render_pager_draw_next (fsm->p, space) - : 0); -} - -static int -xr_fsm_draw_chart (struct xr_fsm *fsm, int space) -{ - const int chart_height = 0.8 * MIN (fsm->rp.size[H], fsm->rp.size[V]); - if (space < chart_height) - return 0; - - fsm->done = true; - xr_draw_chart (to_chart_item (fsm->item), fsm->cairo, - xr_to_pt (fsm->rp.size[H]), xr_to_pt (chart_height)); - return chart_height; -} - -static int -xr_fsm_draw_eject (struct xr_fsm *fsm, int space) -{ - if (space >= fsm->rp.size[V]) - fsm->done = true; - return 0; -} - void xr_fsm_draw_all (struct xr_fsm *fsm, cairo_t *cr) { + assert (!fsm->print); xr_fsm_draw_region (fsm, cr, 0, 0, INT_MAX, INT_MAX); } @@ -1151,10 +1180,23 @@ mul_XR_POINT (int x) : x * XR_POINT); } +static void +draw_image (cairo_surface_t *image, cairo_t *cr) +{ + cairo_save (cr); + cairo_set_source_surface (cr, image, 0, 0); + cairo_rectangle (cr, 0, 0, cairo_image_surface_get_width (image), + cairo_image_surface_get_height (image)); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); +} + void xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr, int x, int y, int w, int h) { + assert (!fsm->print); if (is_table_item (fsm->item)) { fsm->cairo = cr; @@ -1162,6 +1204,8 @@ xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr, mul_XR_POINT (w), mul_XR_POINT (h)); fsm->cairo = NULL; } + else if (is_image_item (fsm->item)) + draw_image (to_image_item (fsm->item)->image, cr); else if (is_chart_item (fsm->item)) xr_draw_chart (to_chart_item (fsm->item), cr, CHART_WIDTH, CHART_HEIGHT); else if (is_page_eject_item (fsm->item)) @@ -1171,17 +1215,115 @@ xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr, else NOT_REACHED (); } + +/* Printing API. */ + +static int +xr_fsm_draw_table (struct xr_fsm *fsm, int space) +{ + struct table_item *table_item = to_table_item (fsm->item); + int used = render_pager_draw_next (fsm->p, space); + if (!render_pager_has_next (fsm->p)) + { + render_pager_destroy (fsm->p); + + fsm->layer_indexes = pivot_output_next_layer (table_item->pt, + fsm->layer_indexes, true); + if (fsm->layer_indexes) + { + fsm->p = render_pager_create (&fsm->rp, table_item, + fsm->layer_indexes); + if (table_item->pt->look->paginate_layers) + used = space; + else + used += fsm->style->object_spacing; + } + else + { + fsm->p = NULL; + fsm->done = true; + } + } + return MIN (used, space); +} + +static int +xr_fsm_draw_chart (struct xr_fsm *fsm, int space) +{ + const int chart_height = 0.8 * MIN (fsm->rp.size[H], fsm->rp.size[V]); + if (space < chart_height) + return 0; + + fsm->done = true; + xr_draw_chart (to_chart_item (fsm->item), fsm->cairo, + xr_to_pt (fsm->rp.size[H]), xr_to_pt (chart_height)); + return chart_height; +} + +static int +xr_fsm_draw_image (struct xr_fsm *fsm, int space) +{ + cairo_surface_t *image = to_image_item (fsm->item)->image; + int width = cairo_image_surface_get_width (image) * XR_POINT; + int height = cairo_image_surface_get_height (image) * XR_POINT; + if (!width || !height) + goto error; + + if (height > fsm->rp.size[V]) + { + double scale = fsm->rp.size[V] / (double) height; + width *= scale; + height *= scale; + if (!width || !height) + goto error; + + cairo_scale (fsm->cairo, scale, scale); + } + + if (width > fsm->rp.size[H]) + { + double scale = fsm->rp.size[H] / (double) width; + width *= scale; + height *= scale; + if (!width || !height) + goto error; + + cairo_scale (fsm->cairo, scale, scale); + } + + if (space < height) + return 0; + + draw_image (image, fsm->cairo); + fsm->done = true; + return height; + +error: + fsm->done = true; + return 0; +} + +static int +xr_fsm_draw_eject (struct xr_fsm *fsm, int space) +{ + if (space >= fsm->rp.size[V]) + fsm->done = true; + return 0; +} int xr_fsm_draw_slice (struct xr_fsm *fsm, cairo_t *cr, int space) { - if (xr_fsm_is_empty (fsm)) + assert (fsm->print); + + if (fsm->done || space <= 0) return 0; cairo_save (cr); fsm->cairo = cr; int used = (is_table_item (fsm->item) ? xr_fsm_draw_table (fsm, space) : is_chart_item (fsm->item) ? xr_fsm_draw_chart (fsm, space) + : is_image_item (fsm->item) ? xr_fsm_draw_image (fsm, space) : is_page_eject_item (fsm->item) ? xr_fsm_draw_eject (fsm, space) : (abort (), 0)); fsm->cairo = NULL; @@ -1190,11 +1332,10 @@ xr_fsm_draw_slice (struct xr_fsm *fsm, cairo_t *cr, int space) return used; } - bool xr_fsm_is_empty (const struct xr_fsm *fsm) { - return (is_table_item (fsm->item) - ? !render_pager_has_next (fsm->p) - : fsm->done); + assert (fsm->print); + + return fsm->done; }