return x / (double) XR_POINT;
}
-/* Conversion from 1/96" units ("pixels") to Cairo/Pango units. */
-static int
-px_to_xr (int x)
-{
- return x * (PANGO_SCALE * 72 / 96);
-}
-
/* Dimensions for drawing lines in tables. */
#define XR_LINE_WIDTH (XR_POINT / 2) /* Width of an ordinary line. */
#define XR_LINE_SPACE XR_POINT /* Space between double lines. */
int headings_height[2];
/* Internal state. */
- struct render_params *params;
struct xr_fsm_style *style;
double font_scale;
int char_width, char_height;
static void xr_driver_destroy_fsm (struct xr_driver *);
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],
- struct cell_color colors[TABLE_N_AXES][2]);
-static void xr_measure_cell_width (void *, const struct table_cell *,
- 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 color_idx,
- int bb[TABLE_N_AXES][2], int valign_offset,
- int spill[TABLE_N_AXES][2],
- int clip[TABLE_N_AXES][2]);
-static int xr_adjust_break (void *, const struct table_cell *,
- int width, int height);
\f
/* Output driver basics. */
pango_layout_set_font_description (font->layout, font->desc);
}
- if (xr->params == NULL)
- {
- static const struct render_ops xr_render_ops = {
- .draw_line = xr_draw_line,
- .measure_cell_width = xr_measure_cell_width,
- .measure_cell_height = xr_measure_cell_height,
- .adjust_break = xr_adjust_break,
- .draw_cell = xr_draw_cell,
- };
-
- xr->params = xmalloc (sizeof *xr->params);
- xr->params->ops = &xr_render_ops;
- xr->params->aux = xr;
- xr->params->size[H] = xr->width;
- xr->params->size[V] = xr->length;
- xr->params->font_size[H] = xr->char_width;
- xr->params->font_size[V] = xr->char_height;
-
- enum { LW = XR_LINE_WIDTH, LS = XR_LINE_SPACE };
- static const int xr_line_widths[RENDER_N_LINES] =
- {
- [RENDER_LINE_NONE] = 0,
- [RENDER_LINE_SINGLE] = LW,
- [RENDER_LINE_DASHED] = LW,
- [RENDER_LINE_THICK] = LW * 2,
- [RENDER_LINE_THIN] = LW / 2,
- [RENDER_LINE_DOUBLE] = 2 * LW + LS,
- };
- xr->params->line_widths = xr_line_widths;
-
- for (int i = 0; i < TABLE_N_AXES; i++)
- xr->params->min_break[i] = xr->min_break[i];
- xr->params->supports_margins = true;
- xr->params->rtl = render_direction_rtl ();
- }
-
if (xr->style == NULL)
{
xr->style = xmalloc (sizeof *xr->style);
}
xr_fsm_style_unref (xr->style);
- free (xr->params);
free (xr);
}
}
}
\f
-static void
-xr_layout_cell (struct xr_driver *, const struct table_cell *,
- int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
- int *width, int *height, int *brk);
-
-static void
-set_source_rgba (cairo_t *cairo, const struct cell_color *color)
-{
- cairo_set_source_rgba (cairo,
- color->r / 255., color->g / 255., color->b / 255.,
- color->alpha / 255.);
-}
-
-static void
-dump_line (struct xr_driver *xr, int x0, int y0, int x1, int y1, int style,
- const struct cell_color *color)
-{
- cairo_new_path (xr->cairo);
- if (!xr->systemcolors)
- set_source_rgba (xr->cairo, color);
- cairo_set_line_width (
- xr->cairo,
- xr_to_pt (style == RENDER_LINE_THICK ? XR_LINE_WIDTH * 2
- : style == RENDER_LINE_THIN ? XR_LINE_WIDTH / 2
- : XR_LINE_WIDTH));
- cairo_move_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y0 + xr->y));
- cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y1 + xr->y));
- cairo_stroke (xr->cairo);
-}
-
-static void UNUSED
-dump_rectangle (struct xr_driver *xr, int x0, int y0, int x1, int y1)
-{
- cairo_new_path (xr->cairo);
- cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
- cairo_close_path (xr->cairo);
- cairo_stroke (xr->cairo);
- cairo_move_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y0 + xr->y));
- cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y0 + xr->y));
- cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y1 + xr->y));
- cairo_line_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y1 + xr->y));
-}
-
-static void
-fill_rectangle (struct xr_driver *xr, int x0, int y0, int x1, int y1)
-{
- cairo_new_path (xr->cairo);
- cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
- cairo_rectangle (xr->cairo,
- xr_to_pt (x0), xr_to_pt (y0 + xr->y),
- xr_to_pt (x1 - x0), xr_to_pt (y1 - y0));
- cairo_fill (xr->cairo);
-}
-
-/* Draws a horizontal line X0...X2 at Y if LEFT says so,
- shortening it to X0...X1 if SHORTEN is true.
- Draws a horizontal line X1...X3 at Y if RIGHT says so,
- shortening it to X2...X3 if SHORTEN is true. */
-static void
-horz_line (struct xr_driver *xr, int x0, int x1, int x2, int x3, int y,
- enum render_line_style left, enum render_line_style right,
- const struct cell_color *left_color,
- const struct cell_color *right_color,
- bool shorten)
-{
- if (left != RENDER_LINE_NONE && right != RENDER_LINE_NONE && !shorten
- && cell_color_equal (left_color, right_color))
- dump_line (xr, x0, y, x3, y, left, left_color);
- else
- {
- if (left != RENDER_LINE_NONE)
- dump_line (xr, x0, y, shorten ? x1 : x2, y, left, left_color);
- if (right != RENDER_LINE_NONE)
- dump_line (xr, shorten ? x2 : x1, y, x3, y, right, right_color);
- }
-}
-
-/* Draws a vertical line Y0...Y2 at X if TOP says so,
- shortening it to Y0...Y1 if SHORTEN is true.
- Draws a vertical line Y1...Y3 at X if BOTTOM says so,
- shortening it to Y2...Y3 if SHORTEN is true. */
-static void
-vert_line (struct xr_driver *xr, int y0, int y1, int y2, int y3, int x,
- enum render_line_style top, enum render_line_style bottom,
- const struct cell_color *top_color,
- const struct cell_color *bottom_color,
- bool shorten)
-{
- if (top != RENDER_LINE_NONE && bottom != RENDER_LINE_NONE && !shorten
- && cell_color_equal (top_color, bottom_color))
- dump_line (xr, x, y0, x, y3, top, top_color);
- else
- {
- if (top != RENDER_LINE_NONE)
- dump_line (xr, x, y0, x, shorten ? y1 : y2, top, top_color);
- if (bottom != RENDER_LINE_NONE)
- dump_line (xr, x, shorten ? y2 : y1, x, y3, bottom, bottom_color);
- }
-}
-
-static void
-xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2],
- enum render_line_style styles[TABLE_N_AXES][2],
- struct cell_color colors[TABLE_N_AXES][2])
-{
- const int x0 = bb[H][0];
- const int y0 = bb[V][0];
- const int x3 = bb[H][1];
- const int y3 = bb[V][1];
- const int top = styles[H][0];
- const int bottom = styles[H][1];
-
- int start_side = render_direction_rtl();
- int end_side = !start_side;
- const int start_of_line = styles[V][start_side];
- const int end_of_line = styles[V][end_side];
- const struct cell_color *top_color = &colors[H][0];
- const struct cell_color *bottom_color = &colors[H][1];
- const struct cell_color *start_color = &colors[V][start_side];
- const struct cell_color *end_color = &colors[V][end_side];
-
- /* The algorithm here is somewhat subtle, to allow it to handle
- all the kinds of intersections that we need.
-
- Three additional ordinates are assigned along the x axis. The
- first is xc, midway between x0 and x3. The others are x1 and
- x2; for a single vertical line these are equal to xc, and for
- a double vertical line they are the ordinates of the left and
- right half of the double line.
-
- yc, y1, and y2 are assigned similarly along the y axis.
-
- The following diagram shows the coordinate system and output
- for double top and bottom lines, single left line, and no
- right line:
-
- x0 x1 xc x2 x3
- y0 ________________________
- | # # |
- | # # |
- | # # |
- | # # |
- | # # |
- y1 = y2 = yc |######### # |
- | # # |
- | # # |
- | # # |
- | # # |
- y3 |________#_____#_______|
- */
- struct xr_driver *xr = xr_;
-
- /* Offset from center of each line in a pair of double lines. */
- int double_line_ofs = (XR_LINE_SPACE + XR_LINE_WIDTH) / 2;
-
- /* Are the lines along each axis single or double?
- (It doesn't make sense to have different kinds of line on the
- same axis, so we don't try to gracefully handle that case.) */
- bool double_vert = top == RENDER_LINE_DOUBLE || bottom == RENDER_LINE_DOUBLE;
- bool double_horz = start_of_line == RENDER_LINE_DOUBLE || end_of_line == RENDER_LINE_DOUBLE;
-
- /* When horizontal lines are doubled,
- the left-side line along y1 normally runs from x0 to x2,
- and the right-side line along y1 from x3 to x1.
- If the top-side line is also doubled, we shorten the y1 lines,
- so that the left-side line runs only to x1,
- and the right-side line only to x2.
- Otherwise, the horizontal line at y = y1 below would cut off
- the intersection, which looks ugly:
- x0 x1 x2 x3
- y0 ________________________
- | # # |
- | # # |
- | # # |
- | # # |
- y1 |######### ########|
- | |
- | |
- y2 |######################|
- | |
- | |
- y3 |______________________|
- It is more of a judgment call when the horizontal line is
- single. We actually choose to cut off the line anyhow, as
- shown in the first diagram above.
- */
- bool shorten_y1_lines = top == RENDER_LINE_DOUBLE;
- bool shorten_y2_lines = bottom == RENDER_LINE_DOUBLE;
- bool shorten_yc_line = shorten_y1_lines && shorten_y2_lines;
- int horz_line_ofs = double_vert ? double_line_ofs : 0;
- int xc = (x0 + x3) / 2;
- int x1 = xc - horz_line_ofs;
- int x2 = xc + horz_line_ofs;
-
- bool shorten_x1_lines = start_of_line == RENDER_LINE_DOUBLE;
- bool shorten_x2_lines = end_of_line == RENDER_LINE_DOUBLE;
- bool shorten_xc_line = shorten_x1_lines && shorten_x2_lines;
- int vert_line_ofs = double_horz ? double_line_ofs : 0;
- int yc = (y0 + y3) / 2;
- int y1 = yc - vert_line_ofs;
- int y2 = yc + vert_line_ofs;
-
- if (!double_horz)
- horz_line (xr, x0, x1, x2, x3, yc, start_of_line, end_of_line,
- start_color, end_color, shorten_yc_line);
- else
- {
- horz_line (xr, x0, x1, x2, x3, y1, start_of_line, end_of_line,
- start_color, end_color, shorten_y1_lines);
- horz_line (xr, x0, x1, x2, x3, y2, start_of_line, end_of_line,
- start_color, end_color, shorten_y2_lines);
- }
-
- if (!double_vert)
- vert_line (xr, y0, y1, y2, y3, xc, top, bottom, top_color, bottom_color,
- shorten_xc_line);
- else
- {
- vert_line (xr, y0, y1, y2, y3, x1, top, bottom, top_color, bottom_color,
- shorten_x1_lines);
- vert_line (xr, y0, y1, y2, y3, x2, top, bottom, top_color, bottom_color,
- shorten_x2_lines);
- }
-}
-
-static void
-xr_measure_cell_width (void *xr_, const struct table_cell *cell,
- int *min_width, int *max_width)
-{
- struct xr_driver *xr = xr_;
- int bb[TABLE_N_AXES][2];
- int clip[TABLE_N_AXES][2];
- int h;
-
- bb[H][0] = 0;
- bb[H][1] = INT_MAX;
- 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);
-
- bb[H][1] = 1;
- xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL);
-
- if (*min_width > 0)
- *min_width += px_to_xr (cell->style->cell_style.margin[H][0]
- + cell->style->cell_style.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]);
-}
-
-static int
-xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width)
-{
- struct xr_driver *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;
- 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]);
- return h;
-}
-
-static void xr_clip (struct xr_driver *, int clip[TABLE_N_AXES][2]);
-
-static void
-xr_draw_cell (void *xr_, const struct table_cell *cell, int color_idx,
- int bb[TABLE_N_AXES][2], int valign_offset,
- int spill[TABLE_N_AXES][2],
- int clip[TABLE_N_AXES][2])
-{
- struct xr_driver *xr = xr_;
- int w, h, brk;
-
- if (!xr->transparent)
- {
- cairo_save (xr->cairo);
- int bg_clip[TABLE_N_AXES][2];
- for (int axis = 0; axis < TABLE_N_AXES; axis++)
- {
- bg_clip[axis][0] = clip[axis][0];
- if (bb[axis][0] == clip[axis][0])
- bg_clip[axis][0] -= spill[axis][0];
-
- bg_clip[axis][1] = clip[axis][1];
- if (bb[axis][1] == clip[axis][1])
- bg_clip[axis][1] += spill[axis][1];
- }
- xr_clip (xr, bg_clip);
- set_source_rgba (xr->cairo, &cell->style->font_style.bg[color_idx]);
- fill_rectangle (xr,
- bb[H][0] - spill[H][0],
- bb[V][0] - spill[V][0],
- bb[H][1] + spill[H][1],
- bb[V][1] + spill[V][1]);
- cairo_restore (xr->cairo);
- }
- cairo_save (xr->cairo);
- if (!xr->systemcolors)
- set_source_rgba (xr->cairo, &cell->style->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]);
- }
- if (bb[H][0] < bb[H][1] && bb[V][0] < bb[V][1])
- xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
- cairo_restore (xr->cairo);
-}
-
-static int
-xr_adjust_break (void *xr_, const struct table_cell *cell,
- int width, int height)
-{
- struct xr_driver *xr = xr_;
- int bb[TABLE_N_AXES][2];
- int clip[TABLE_N_AXES][2];
- int w, h, brk;
-
- if (xr_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]);
- 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;
- xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
- return brk;
-}
-\f
-static void
-xr_clip (struct xr_driver *xr, int clip[TABLE_N_AXES][2])
-{
- if (clip[H][1] != INT_MAX || clip[V][1] != INT_MAX)
- {
- double x0 = xr_to_pt (clip[H][0]);
- double y0 = xr_to_pt (clip[V][0] + xr->y);
- double x1 = xr_to_pt (clip[H][1]);
- double y1 = xr_to_pt (clip[V][1] + xr->y);
-
- cairo_rectangle (xr->cairo, x0, y0, x1 - x0, y1 - y0);
- cairo_clip (xr->cairo);
- }
-}
-
-static void
-add_attr (PangoAttrList *list, PangoAttribute *attr,
- guint start_index, guint end_index)
-{
- attr->start_index = start_index;
- attr->end_index = end_index;
- pango_attr_list_insert (list, attr);
-}
-
-static void
-markup_escape (struct string *out, unsigned int options,
- const char *in, size_t len)
-{
- if (!(options & TAB_MARKUP))
- {
- ds_put_substring (out, ss_buffer (in, len == -1 ? strlen (in) : len));
- return;
- }
-
- while (len-- > 0)
- {
- int c = *in++;
- switch (c)
- {
- case 0:
- return;
- case '&':
- ds_put_cstr (out, "&");
- break;
- case '<':
- ds_put_cstr (out, "<");
- break;
- case '>':
- ds_put_cstr (out, ">");
- break;
- default:
- ds_put_byte (out, c);
- break;
- }
- }
-}
-
-static int
-get_layout_dimension (PangoLayout *layout, enum table_axis axis)
-{
- int size[TABLE_N_AXES];
- pango_layout_get_size (layout, &size[H], &size[V]);
- return size[axis];
-}
-
-static int
-xr_layout_cell_text (struct xr_driver *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;
- 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;
-
- struct xr_font *font = (options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED]
- : &xr->fonts[XR_FONT_PROPORTIONAL]);
- struct xr_font local_font;
- if (font_style->typeface)
- {
- PangoFontDescription *desc = parse_font (
- font_style->typeface,
- font_style->size ? font_style->size * 1000 * xr->font_scale : 10000,
- font_style->bold, font_style->italic);
- if (desc)
- {
- PangoLayout *layout = pango_cairo_create_layout (xr->cairo);
- pango_layout_set_font_description (layout, desc);
-
- local_font.desc = desc;
- local_font.layout = layout;
- font = &local_font;
- }
- }
-
- const char *text = cell->text;
- enum table_halign halign = table_halign_interpret (
- cell_style->halign, cell->options & TAB_NUMERIC);
- if (cell_style->halign == TABLE_HALIGN_DECIMAL && !(options & TAB_ROTATE))
- {
- int margin_adjustment = -px_to_xr (cell_style->decimal_offset);
-
- const char *decimal = strrchr (text, cell_style->decimal_char);
- if (decimal)
- {
- pango_layout_set_text (font->layout, decimal, strlen (decimal));
- pango_layout_set_width (font->layout, -1);
- margin_adjustment += get_layout_dimension (font->layout, H);
- }
-
- if (margin_adjustment < 0)
- 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
- Pango's implementation of it): it will break after a period or a comma
- that precedes a digit, e.g. in ".000" it will break after the period.
- This code looks for such a situation and inserts a U+2060 WORD JOINER
- to prevent the break.
-
- This isn't necessary when the decimal point is between two digits
- (e.g. "0.000" won't be broken) or when the display width is not limited so
- that word wrapping won't happen.
-
- It isn't necessary to look for more than one period or comma, as would
- 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)
- {
- PangoAttrList *new_attrs;
- char *new_text;
- if (pango_parse_markup (text, -1, 0, &new_attrs, &new_text, NULL, NULL))
- {
- attrs = new_attrs;
- tmp.ss = ss_cstr (new_text);
- tmp.capacity = tmp.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 *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);
- ds_put_unichar (&tmp, 0x2060 /* U+2060 WORD JOINER */);
- markup_escape (&tmp, options, decimal + 1, -1);
- }
- }
-
- if (font_style->underline)
- {
- if (!attrs)
- attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_underline_new (
- PANGO_UNDERLINE_SINGLE));
- }
-
- if (cell->n_footnotes || cell->n_subscripts || cell->superscript)
- {
- /* 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++)
- {
- if (i)
- ds_put_byte (&tmp, ',');
- ds_put_cstr (&tmp, cell->subscripts[i]);
- }
-
- size_t superscript_ofs = ds_length (&tmp);
- if (cell->superscript)
- ds_put_cstr (&tmp, cell->superscript);
-
- size_t footnote_ofs = ds_length (&tmp);
- for (size_t i = 0; i < cell->n_footnotes; i++)
- {
- if (i)
- ds_put_byte (&tmp, ',');
- ds_put_cstr (&tmp, cell->footnotes[i]->marker);
- }
-
- /* 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)
- {
- /* Measure the width of the footnote marker, so we know how much we
- need to make room for. */
- pango_layout_set_text (font->layout, ds_cstr (&tmp) + footnote_ofs,
- ds_length (&tmp) - footnote_ofs);
-
- PangoAttrList *fn_attrs = pango_attr_list_new ();
- pango_attr_list_insert (
- fn_attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
- pango_attr_list_insert (fn_attrs, pango_attr_rise_new (3000));
- pango_layout_set_attributes (font->layout, fn_attrs);
- pango_attr_list_unref (fn_attrs);
- int footnote_width = get_layout_dimension (font->layout, X);
-
- /* Bound the adjustment by the width of the right margin. */
- int right_margin = px_to_xr (cell_style->margin[X][R]);
- int footnote_adjustment = MIN (footnote_width, right_margin);
-
- /* Adjust the bounding box. */
- if (options & TAB_ROTATE)
- footnote_adjustment = -footnote_adjustment;
- bb[X][R] += footnote_adjustment;
-
- /* Clean up. */
- pango_layout_set_attributes (font->layout, NULL);
- }
-
- /* Set attributes. */
- if (!attrs)
- attrs = pango_attr_list_new ();
- add_attr (attrs, pango_attr_font_desc_new (font->desc), subscript_ofs,
- 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)
- add_attr (attrs, pango_attr_rise_new (-3000), subscript_ofs,
- superscript_ofs - subscript_ofs);
- if (cell->superscript || cell->n_footnotes)
- add_attr (attrs, pango_attr_rise_new (3000), superscript_ofs,
- PANGO_ATTR_INDEX_TO_TEXT_END);
- }
-
- /* Set the attributes, if any. */
- if (attrs)
- {
- pango_layout_set_attributes (font->layout, attrs);
- pango_attr_list_unref (attrs);
- }
-
- /* Set the text. */
- if (ds_is_empty (&tmp))
- pango_layout_set_text (font->layout, text, -1);
- else
- pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
- ds_destroy (&tmp);
-
- pango_layout_set_alignment (font->layout,
- (halign == TABLE_HALIGN_RIGHT ? PANGO_ALIGN_RIGHT
- : halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
- : PANGO_ALIGN_CENTER));
- pango_layout_set_width (
- font->layout,
- bb[X][1] == INT_MAX ? -1 : xr_to_pango (bb[X][1] - bb[X][0]));
- pango_layout_set_wrap (font->layout, PANGO_WRAP_WORD);
-
- if (clip[H][0] != clip[H][1])
- {
- cairo_save (xr->cairo);
- if (!(options & TAB_ROTATE))
- xr_clip (xr, clip);
- if (options & TAB_ROTATE)
- {
- cairo_translate (xr->cairo,
- xr_to_pt (bb[H][0]),
- xr_to_pt (bb[V][1] + xr->y));
- cairo_rotate (xr->cairo, -M_PI_2);
- }
- else
- cairo_translate (xr->cairo,
- xr_to_pt (bb[H][0]),
- xr_to_pt (bb[V][0] + xr->y));
- pango_cairo_show_layout (xr->cairo, font->layout);
-
- /* If enabled, this draws a blue rectangle around the extents of each
- line of text, which can be rather useful for debugging layout
- issues. */
- if (0)
- {
- PangoLayoutIter *iter;
- iter = pango_layout_get_iter (font->layout);
- do
- {
- PangoRectangle extents;
-
- pango_layout_iter_get_line_extents (iter, &extents, NULL);
- cairo_save (xr->cairo);
- cairo_set_source_rgb (xr->cairo, 1, 0, 0);
- dump_rectangle (xr,
- pango_to_xr (extents.x),
- pango_to_xr (extents.y) - xr->y,
- pango_to_xr (extents.x + extents.width),
- pango_to_xr (extents.y + extents.height) - xr->y);
- cairo_restore (xr->cairo);
- }
- while (pango_layout_iter_next_line (iter));
- pango_layout_iter_free (iter);
- }
-
- cairo_restore (xr->cairo);
- }
-
- int size[TABLE_N_AXES];
- pango_layout_get_size (font->layout, &size[H], &size[V]);
- int w = pango_to_xr (size[X]);
- int h = pango_to_xr (size[Y]);
- if (w > *widthp)
- *widthp = w;
- if (bb[V][0] + h >= bb[V][1] && !(options & TAB_ROTATE))
- {
- PangoLayoutIter *iter;
- int best = 0;
-
- /* Choose a breakpoint between lines instead of in the middle of one. */
- iter = pango_layout_get_iter (font->layout);
- do
- {
- PangoRectangle extents;
- int y0, y1;
- int bottom;
-
- pango_layout_iter_get_line_extents (iter, NULL, &extents);
- pango_layout_iter_get_line_yrange (iter, &y0, &y1);
- extents.x = pango_to_xr (extents.x);
- extents.y = pango_to_xr (y0);
- extents.width = pango_to_xr (extents.width);
- extents.height = pango_to_xr (y1 - y0);
- bottom = bb[V][0] + extents.y + extents.height;
- if (bottom < bb[V][1])
- {
- if (brk && clip[H][0] != clip[H][1])
- best = bottom;
- if (brk)
- *brk = bottom;
- }
- else
- break;
- }
- while (pango_layout_iter_next_line (iter));
- pango_layout_iter_free (iter);
-
- /* If enabled, draws a green line across the chosen breakpoint, which can
- be useful for debugging issues with breaking. */
- if (0)
- {
- if (best)
- dump_line (xr, -xr->left_margin, best,
- xr->width + xr->right_margin, best,
- RENDER_LINE_SINGLE,
- &(struct cell_color) CELL_COLOR (0, 255, 0));
- }
- }
-
- pango_layout_set_attributes (font->layout, NULL);
-
- if (font == &local_font)
- {
- g_object_unref (G_OBJECT (font->layout));
- pango_font_description_free (font->desc);
- }
-
- return h;
-}
-
-static void
-xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell,
- int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
- int *width, int *height, int *brk)
-{
- *width = 0;
- *height = 0;
-
- /* If enabled, draws a blue rectangle around the cell extents, which can be
- useful for debugging layout. */
- if (0)
- {
- if (clip[H][0] != clip[H][1])
- {
- cairo_save (xr->cairo);
- cairo_set_source_rgb (xr->cairo, 0, 0, 1);
- dump_rectangle (xr, bb[H][0], bb[V][0], bb[H][1], bb[V][1]);
- cairo_restore (xr->cairo);
- }
- }
-
- if (brk)
- *brk = bb[V][0];
- *height = xr_layout_cell_text (xr, cell, bb, clip, width, brk);
-}
-\f
struct output_driver_factory pdf_driver_factory =
{ "pdf", "pspp.pdf", xr_pdf_create };
struct output_driver_factory ps_driver_factory =