X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-output-view.c;h=f48b1ade4f5e8fa88a057d6e3e66a3cf56ec1e15;hb=e6b6e7d67f173867d731ebca6b8fbad5a2f82560;hp=433cf79b4334928437d6e9d11c9fa634607f0601;hpb=3d272bb64adfda361a9bda8daae757c26b758f55;p=pspp diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c index 433cf79b43..f48b1ade4f 100644 --- a/src/ui/gui/psppire-output-view.c +++ b/src/ui/gui/psppire-output-view.c @@ -18,6 +18,7 @@ #include "ui/gui/psppire-output-view.h" +#include #include #include @@ -26,7 +27,8 @@ #endif #include "libpspp/assertion.h" #include "libpspp/string-map.h" -#include "output/cairo.h" +#include "output/cairo-fsm.h" +#include "output/cairo-pager.h" #include "output/driver-provider.h" #include "output/driver.h" #include "output/chart-item.h" @@ -53,15 +55,14 @@ struct output_view_item struct psppire_output_view { - struct xr_driver *xr; - int font_height; + struct xr_fsm_style *style; + int object_spacing; GtkLayout *output; int render_width; int max_width; glong y; - struct string_map render_opts; GtkTreeView *overview; GtkTreePath *cur_group; @@ -75,7 +76,10 @@ struct psppire_output_view /* Variables pertaining to printing */ GtkPrintSettings *print_settings; - struct xr_driver *print_xrd; + + struct xr_fsm_style *fsm_style; + struct xr_page_style *page_style; + struct xr_pager *pager; int print_item; int print_n_pages; gboolean paginated; @@ -114,7 +118,7 @@ draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data) if (!gdk_cairo_get_clip_rectangle (cr, &clip)) return TRUE; - struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering"); + struct xr_fsm *fsm = g_object_get_data (G_OBJECT (widget), "fsm"); /* Draw the background based on the state of the widget which can be selected or not selected */ @@ -127,83 +131,47 @@ draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data) GdkRGBA color; gtk_style_context_get_color (context, state, &color); cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha); - xr_rendering_draw (r, cr, clip.x, clip.y, - clip.x + clip.width, clip.y + clip.height); + xr_fsm_draw_region (fsm, cr, clip.x, clip.y, clip.width, clip.height); return TRUE; } static void -free_rendering (gpointer rendering_) +free_fsm (gpointer fsm_) { - struct xr_rendering *rendering = rendering_; - xr_rendering_destroy (rendering); + struct xr_fsm *fsm = fsm_; + xr_fsm_destroy (fsm); } -static void -get_xr_options (struct psppire_output_view *view, struct string_map *options) +static struct xr_fsm_style * +get_xr_fsm_style (struct psppire_output_view *view) { - string_map_clear (options); - GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (view->output)); GtkStateFlags state = gtk_widget_get_state_flags (GTK_WIDGET (view->output)); - /* Use GTK+ default font as proportional font. */ - PangoFontDescription *font_desc; - gtk_style_context_get (context, state, "font", &font_desc, NULL); - char *font_name = pango_font_description_to_string (font_desc); - string_map_insert (options, "prop-font", font_name); - g_free (font_name); - - /* Derived emphasized font from proportional font. */ - pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC); - font_name = pango_font_description_to_string (font_desc); - string_map_insert (options, "emph-font", font_name); - g_free (font_name); - pango_font_description_free (font_desc); - - /* Pretend that the "page" has a reasonable width and a very big length, - so that most tables can be conveniently viewed on-screen with vertical - scrolling only. (The length should not be increased very much because - it is already close enough to INT_MAX when expressed as thousands of a - point.) */ - string_map_insert_nocopy (options, xstrdup ("paper-size"), - xasprintf ("%dx1000000pt", view->render_width)); - string_map_insert (options, "left-margin", "0"); - string_map_insert (options, "right-margin", "0"); - string_map_insert (options, "top-margin", "0"); - string_map_insert (options, "bottom-margin", "0"); - - string_map_insert (options, "transparent", "true"); - string_map_insert (options, "systemcolors", "true"); -} - -static void -create_xr (struct psppire_output_view *view) -{ - get_xr_options (view, &view->render_opts); - - struct string_map options; - string_map_clone (&options, &view->render_opts); - - GdkWindow *win = gtk_layout_get_bin_window (view->output); - cairo_region_t *region = gdk_window_get_visible_region (win); - GdkDrawingContext *ctx = gdk_window_begin_draw_frame (win, region); - cairo_t *cr = gdk_drawing_context_get_cairo_context (ctx); - - view->xr = xr_driver_create (cr, &options); - string_map_destroy (&options); - - struct text_item *text_item = text_item_create (TEXT_ITEM_LOG, "X"); - struct xr_rendering *r - = xr_rendering_create (view->xr, text_item_super (text_item), cr); - xr_rendering_measure (r, NULL, &view->font_height); - xr_rendering_destroy (r); - text_item_unref (text_item); + int xr_width = view->render_width * 1000; + + PangoFontDescription *pf; + gtk_style_context_get (context, state, "font", &pf, NULL); + PangoFontDescription *ff = pango_font_description_from_string ("Monospace"); + pango_font_description_set_size (ff, pango_font_description_get_size (pf)); + + struct xr_fsm_style *style = xmalloc (sizeof *style); + *style = (struct xr_fsm_style) { + .ref_cnt = 1, + .size = { [TABLE_HORZ] = xr_width, [TABLE_VERT] = INT_MAX }, + .min_break = { [TABLE_HORZ] = xr_width / 2, [TABLE_VERT] = 0 }, + .fonts = { + [XR_FONT_PROPORTIONAL] = pf, + [XR_FONT_FIXED] = ff, + }, + .use_system_colors = true, + .transparent = true, + .font_resolution = 96.0, + }; - gdk_window_end_draw_frame (win, ctx); - cairo_region_destroy (region); + return style; } /* Return the horizontal position to place a widget whose @@ -310,11 +278,11 @@ drag_data_get_cb (GtkWidget *widget, GdkDragContext *context, static void create_drawing_area (struct psppire_output_view *view, - GtkWidget *drawing_area, struct xr_rendering *r, + GtkWidget *drawing_area, struct xr_fsm *r, int tw, int th, const struct output_item *item) { g_object_set_data_full (G_OBJECT (drawing_area), - "rendering", r, free_rendering); + "fsm", r, free_fsm); g_signal_connect (drawing_area, "button-press-event", G_CALLBACK (button_press_event_cb), view); gtk_widget_add_events (drawing_area, GDK_BUTTON_PRESS_MASK); @@ -351,8 +319,8 @@ rerender (struct psppire_output_view *view) if (!view->n_items || ! gdkw) return; - if (view->xr == NULL) - create_xr (view); + if (!view->style) + view->style = get_xr_fsm_style (view); GdkWindow *win = gtk_layout_get_bin_window (view->output); cairo_region_t *region = gdk_window_get_visible_region (win); @@ -363,24 +331,24 @@ rerender (struct psppire_output_view *view) view->max_width = 0; for (item = view->items; item < &view->items[view->n_items]; item++) { - struct xr_rendering *r; + struct xr_fsm *r; GtkAllocation alloc; int tw, th; if (view->y > 0) - view->y += view->font_height / 2; + view->y += view->object_spacing; if (is_group_open_item (item->item)) continue; - r = xr_rendering_create (view->xr, item->item, cr); + r = xr_fsm_create (item->item, view->style, cr); if (r == NULL) { g_warn_if_reached (); continue; } - xr_rendering_measure (r, &tw, &th); + xr_fsm_measure (r, cr, &tw, &th); gint xpos = get_xpos (view, tw); @@ -392,7 +360,7 @@ rerender (struct psppire_output_view *view) else { g_object_set_data_full (G_OBJECT (item->drawing_area), - "rendering", r, free_rendering); + "fsm", r, free_fsm); gtk_widget_set_size_request (item->drawing_area, tw, th); gtk_layout_move (view->output, item->drawing_area, xpos, view->y); } @@ -421,8 +389,8 @@ rerender (struct psppire_output_view *view) } gtk_layout_set_size (view->output, - view->max_width + view->font_height, - view->y + view->font_height); + view->max_width + view->object_spacing, + view->y + view->object_spacing); gdk_window_end_draw_frame (win, ctx); cairo_region_destroy (region); @@ -472,17 +440,17 @@ psppire_output_view_put (struct psppire_output_view *view, { view_item->drawing_area = drawing_area = gtk_drawing_area_new (); - if (view->xr == NULL) - create_xr (view); + if (!view->style) + view->style = get_xr_fsm_style (view); cairo_region_t *region = gdk_window_get_visible_region (win); GdkDrawingContext *ctx = gdk_window_begin_draw_frame (win, region); cairo_t *cr = gdk_drawing_context_get_cairo_context (ctx); if (view->y > 0) - view->y += view->font_height / 2; + view->y += view->object_spacing; - struct xr_rendering *r = xr_rendering_create (view->xr, item, cr); + struct xr_fsm *r = xr_fsm_create (item, view->style, cr); if (r == NULL) { gdk_window_end_draw_frame (win, ctx); @@ -490,7 +458,7 @@ psppire_output_view_put (struct psppire_output_view *view, return; } - xr_rendering_measure (r, &tw, &th); + xr_fsm_measure (r, cr, &tw, &th); create_drawing_area (view, drawing_area, r, tw, th, item); gdk_window_end_draw_frame (win, ctx); cairo_region_destroy (region); @@ -613,18 +581,16 @@ on_style_updated (GtkWidget *toplevel, struct psppire_output_view *view) return; /* GTK+ fires this signal for trivial changes like the mouse moving in or out - of the window. Check whether the actual rendering options changed and + of the window. Check whether the actual fsm options changed and re-render only if they did. */ - struct string_map options = STRING_MAP_INITIALIZER (options); - get_xr_options (view, &options); - if (!string_map_equals (&options, &view->render_opts)) + struct xr_fsm_style *style = get_xr_fsm_style (view); + if (!view->style || !xr_fsm_style_equals (style, view->style)) { - xr_driver_destroy (view->xr); - view->xr = NULL; - + xr_fsm_style_unref (view->style); + view->style = xr_fsm_style_ref (style); rerender (view); } - string_map_destroy (&options); + xr_fsm_style_unref (style); } enum { @@ -729,8 +695,29 @@ clipboard_get_cb (GtkClipboard *clipboard, (info == SELECT_FMT_SVG) ) { GtkWidget *widget = view->selected_item->drawing_area; - struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering"); - xr_draw_svg_file (r, filename); + struct xr_fsm *fsm = g_object_get_data (G_OBJECT (widget), "fsm"); + + GdkWindow *win = gtk_layout_get_bin_window (view->output); + cairo_region_t *region = gdk_window_get_visible_region (win); + GdkDrawingContext *ctx = gdk_window_begin_draw_frame (win, region); + cairo_t *cr = gdk_drawing_context_get_cairo_context (ctx); + + int w, h; + xr_fsm_measure (fsm, cr, &w, &h); + + gdk_window_end_draw_frame (win, ctx); + cairo_region_destroy (region); + + cairo_surface_t *surface = cairo_svg_surface_create (filename, w, h); + if (surface) + { + cairo_t *cr = cairo_create (surface); + xr_fsm_draw_all (fsm, cr); + cairo_destroy (cr); + cairo_surface_destroy (surface); + } + else + g_error ("Could not create cairo svg surface with file %s", filename); } else { @@ -876,25 +863,12 @@ psppire_output_view_new (GtkLayout *output, GtkTreeView *overview) GtkTreeModel *model; view = xmalloc (sizeof *view); - view->xr = NULL; - view->font_height = 0; - view->output = output; - view->render_width = 0; - view->max_width = 0; - view->y = 0; - string_map_init (&view->render_opts); - view->overview = overview; - view->cur_group = NULL; - view->toplevel = gtk_widget_get_toplevel (GTK_WIDGET (output)); - view->buttontime = 0; - view->items = NULL; - view->n_items = view->allocated_items = 0; - view->selected_item = NULL; - view->print_settings = NULL; - view->print_xrd = NULL; - view->print_item = 0; - view->print_n_pages = 0; - view->paginated = FALSE; + *view = (struct psppire_output_view) { + .object_spacing = 10, + .output = output, + .overview = overview, + .toplevel = gtk_widget_get_toplevel (GTK_WIDGET (output)), + }; g_signal_connect (output, "draw", G_CALLBACK (layout_draw_callback), NULL); @@ -945,7 +919,7 @@ psppire_output_view_destroy (struct psppire_output_view *view) g_signal_handlers_disconnect_by_func (view->output, G_CALLBACK (on_style_updated), view); - string_map_destroy (&view->render_opts); + xr_fsm_style_unref (view->style); for (i = 0; i < view->n_items; i++) output_item_unref (view->items[i].item); @@ -956,8 +930,6 @@ psppire_output_view_destroy (struct psppire_output_view *view) if (view->print_settings != NULL) g_object_unref (view->print_settings); - xr_driver_destroy (view->xr); - if (view->cur_group) gtk_tree_path_free (view->cur_group); @@ -1008,55 +980,68 @@ static cairo_t * get_cairo_context_from_print_context (GtkPrintContext *context) { cairo_t *cr = gtk_print_context_get_cairo_context (context); - - /* - For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72. - Windows returns 600. - */ - double xres = gtk_print_context_get_dpi_x (context); - double yres = gtk_print_context_get_dpi_y (context); - - /* This means that the cairo context now has its dimensions in Points */ - cairo_scale (cr, xres / 72.0, yres / 72.0); - - return cr; + return cairo_reference (cr); } - static void create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view) { - struct string_map options; - GtkPageSetup *page_setup; - double width, height; - double left_margin; - double right_margin; - double top_margin; - double bottom_margin; - - page_setup = gtk_print_context_get_page_setup (context); - width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM); - height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM); - left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM); - right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM); - top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM); - bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM); + GtkPageSetup *ps = gtk_print_context_get_page_setup (context); - string_map_init (&options); - string_map_insert_nocopy (&options, xstrdup ("paper-size"), - c_xasprintf("%.2fx%.2fmm", width, height)); - string_map_insert_nocopy (&options, xstrdup ("left-margin"), - c_xasprintf ("%.2fmm", left_margin)); - string_map_insert_nocopy (&options, xstrdup ("right-margin"), - c_xasprintf ("%.2fmm", right_margin)); - string_map_insert_nocopy (&options, xstrdup ("top-margin"), - c_xasprintf ("%.2fmm", top_margin)); - string_map_insert_nocopy (&options, xstrdup ("bottom-margin"), - c_xasprintf ("%.2fmm", bottom_margin)); - - view->print_xrd = xr_driver_create (get_cairo_context_from_print_context (context), &options); - - string_map_destroy (&options); + enum { H = TABLE_HORZ, V = TABLE_VERT }; + int paper[TABLE_N_AXES] = { + [H] = gtk_page_setup_get_paper_width (ps, GTK_UNIT_POINTS) * XR_POINT, + [V] = gtk_page_setup_get_paper_height (ps, GTK_UNIT_POINTS) * XR_POINT, + }; + + /* These are all 1/2 inch. The "margins" that GTK+ gives us are useless: + they are the printer's imagable area. */ + int margins[TABLE_N_AXES][2] = { + [H][0] = XR_POINT * 36, + [H][1] = XR_POINT * 36, + [V][0] = XR_POINT * 36, + [V][1] = XR_POINT * 36, + }; + + double size[TABLE_N_AXES]; + for (int a = 0; a < TABLE_N_AXES; a++) + size[a] = paper[a] - margins[a][0] - margins[a][1]; + + PangoFontDescription *proportional_font + = pango_font_description_from_string ("Sans Serif 10"); + PangoFontDescription *fixed_font + = pango_font_description_from_string ("Monospace 10"); + + view->page_style = xmalloc (sizeof *view->page_style); + *view->page_style = (struct xr_page_style) { + .ref_cnt = 1, + + .margins = { + [H] = { margins[H][0], margins[H][1] }, + [V] = { margins[V][0], margins[V][1] }, + }, + .bg = { .alpha = 0 }, + .initial_page_number = 1, + .object_spacing = 12 * XR_POINT, + }; + + view->fsm_style = xmalloc (sizeof *view->fsm_style); + *view->fsm_style = (struct xr_fsm_style) { + .ref_cnt = 1, + + .size = { [H] = size[H], [V] = size[V] }, + .min_break = { [H] = size[H] / 2, [V] = size[V] / 2 }, + .fonts = { + [XR_FONT_PROPORTIONAL] = proportional_font, + [XR_FONT_FIXED] = fixed_font, + }, + .fg = CELL_COLOR_BLACK, + .use_system_colors = false, + .transparent = false, + .font_resolution = 72.0 + }; + + view->pager = xr_pager_create (view->page_style, view->fsm_style); } static gboolean @@ -1072,22 +1057,22 @@ paginate (GtkPrintOperation *operation, } else if (view->print_item < view->n_items) { - xr_driver_output_item (view->print_xrd, - view->items[view->print_item++].item); - while (xr_driver_need_new_page (view->print_xrd)) + xr_pager_add_item (view->pager, view->items[view->print_item++].item); + while (xr_pager_needs_new_page (view->pager)) { - xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context)); + xr_pager_add_page (view->pager, + get_cairo_context_from_print_context (context)); view->print_n_pages ++; } return FALSE; } else { - gtk_print_operation_set_n_pages (operation, view->print_n_pages); + gtk_print_operation_set_n_pages (operation, MAX (1, view->print_n_pages)); /* Re-create the driver to do the real printing. */ - xr_driver_destroy (view->print_xrd); - create_xr_print_driver (context, view); + xr_pager_destroy (view->pager); + view->pager = xr_pager_create (view->page_style, view->fsm_style); view->print_item = 0; view->paginated = TRUE; @@ -1103,7 +1088,7 @@ begin_print (GtkPrintOperation *operation, create_xr_print_driver (context, view); view->print_item = 0; - view->print_n_pages = 1; + view->print_n_pages = 0; view->paginated = FALSE; } @@ -1112,7 +1097,8 @@ end_print (GtkPrintOperation *operation, GtkPrintContext *context, struct psppire_output_view *view) { - xr_driver_destroy (view->print_xrd); + xr_pager_destroy (view->pager); + view->pager = NULL; } @@ -1122,10 +1108,11 @@ draw_page (GtkPrintOperation *operation, gint page_number, struct psppire_output_view *view) { - xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context)); - while (!xr_driver_need_new_page (view->print_xrd) + xr_pager_add_page (view->pager, + get_cairo_context_from_print_context (context)); + while (!xr_pager_needs_new_page (view->pager) && view->print_item < view->n_items) - xr_driver_output_item (view->print_xrd, view->items [view->print_item++].item); + xr_pager_add_item (view->pager, view->items [view->print_item++].item); } @@ -1140,6 +1127,9 @@ psppire_output_view_print (struct psppire_output_view *view, if (view->print_settings != NULL) gtk_print_operation_set_print_settings (print, view->print_settings); + gtk_print_operation_set_use_full_page (print, TRUE); + gtk_print_operation_set_unit (print, GTK_UNIT_POINTS); + g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view); g_signal_connect (print, "end_print", G_CALLBACK (end_print), view); g_signal_connect (print, "paginate", G_CALLBACK (paginate), view);