summaryrefslogtreecommitdiff
path: root/frontends/riscos/print.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/riscos/print.c')
-rw-r--r--frontends/riscos/print.c976
1 files changed, 976 insertions, 0 deletions
diff --git a/frontends/riscos/print.c b/frontends/riscos/print.c
new file mode 100644
index 000000000..95730d6be
--- /dev/null
+++ b/frontends/riscos/print.c
@@ -0,0 +1,976 @@
+/*
+ * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <string.h>
+#include <swis.h>
+#include <oslib/font.h>
+#include <oslib/hourglass.h>
+#include <oslib/osfile.h>
+#include <oslib/osfind.h>
+#include <oslib/pdriver.h>
+#include <oslib/wimp.h>
+#include <rufl.h>
+#include <limits.h>
+
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/nsoption.h"
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "desktop/browser.h"
+#include "desktop/plotters.h"
+
+#include "riscos/gui.h"
+#include "riscos/dialog.h"
+#include "riscos/menus.h"
+#include "riscos/print.h"
+#include "riscos/wimp.h"
+#include "riscos/wimp_event.h"
+#include "riscos/filetype.h"
+#include "riscos/font.h"
+
+
+#define ICON_PRINT_TO_BOTTOM 1
+#define ICON_PRINT_SHEETS 2
+#define ICON_PRINT_SHEETS_VALUE 3
+#define ICON_PRINT_SHEETS_DOWN 4
+#define ICON_PRINT_SHEETS_UP 5
+#define ICON_PRINT_SHEETS_TEXT 6
+#define ICON_PRINT_FG_IMAGES 7
+#define ICON_PRINT_BG_IMAGES 8
+#define ICON_PRINT_IN_BACKGROUND 9
+#define ICON_PRINT_UPRIGHT 10
+#define ICON_PRINT_SIDEWAYS 11
+#define ICON_PRINT_COPIES 12
+#define ICON_PRINT_COPIES_DOWN 13
+#define ICON_PRINT_COPIES_UP 14
+#define ICON_PRINT_CANCEL 15
+#define ICON_PRINT_PRINT 16
+#define ICON_PRINT_TEXT_BLACK 20
+
+
+/** \todo landscape format pages
+ * \todo be somewhat more intelligent and try not to crop pages
+ * half way up a line of text
+ * \todo make use of print stylesheets
+ */
+
+struct gui_window *ro_print_current_window = NULL;
+bool print_text_black = false;
+bool print_active = false;
+
+/* 1 millipoint == 1/400 OS unit == 1/800 browser units */
+
+static int print_prev_message = 0;
+static bool print_in_background = false;
+static float print_scale = 1.0;
+static int print_num_copies = 1;
+static bool print_bg_images = false;
+static int print_max_sheets = -1;
+static bool print_sideways = false;
+/** List of fonts in current print. */
+static char **print_fonts_list = 0;
+/** Number of entries in print_fonts_list. */
+static unsigned int print_fonts_count;
+/** Error in print_fonts_plot_text() or print_fonts_callback(). */
+static const char *print_fonts_error;
+
+void gui_window_redraw_window(struct gui_window *g);
+
+static bool ro_gui_print_click(wimp_pointer *pointer);
+static bool ro_gui_print_apply(wimp_w w);
+static void print_update_sheets_shaded_state(bool on);
+static void print_send_printsave(hlcache_handle *h);
+static bool print_send_printtypeknown(wimp_message *m);
+static bool print_document(struct gui_window *g, const char *filename);
+static const char *print_declare_fonts(hlcache_handle *h);
+static bool print_fonts_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
+static bool print_fonts_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style);
+static bool print_fonts_plot_polygon(const int *p, unsigned int n, const plot_style_t *style);
+static bool print_fonts_plot_clip(const struct rect *clip);
+static bool print_fonts_plot_text(int x, int y, const char *text, size_t length,
+ const plot_font_style_t *fstyle);
+static bool print_fonts_plot_disc(int x, int y, int radius, const plot_style_t *style);
+static bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style);
+static bool print_fonts_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bitmap_flags_t flags);
+static bool print_fonts_plot_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6]);
+static void print_fonts_callback(void *context,
+ const char *font_name, unsigned int font_size,
+ const char *s8, unsigned short *s16, unsigned int n,
+ int x, int y);
+
+
+/** Plotter for print_declare_fonts(). All the functions do nothing except for
+ * print_fonts_plot_text, which records the fonts used. */
+static const struct plotter_table print_fonts_plotters = {
+ .rectangle = print_fonts_plot_rectangle,
+ .line = print_fonts_plot_line,
+ .polygon = print_fonts_plot_polygon,
+ .clip = print_fonts_plot_clip,
+ .text = print_fonts_plot_text,
+ .disc = print_fonts_plot_disc,
+ .arc = print_fonts_plot_arc,
+ .bitmap = print_fonts_plot_bitmap,
+ .path = print_fonts_plot_path,
+ .option_knockout = false,
+};
+
+
+/**
+ * Initialise the print dialog.
+ */
+
+void ro_gui_print_init(void)
+{
+ wimp_i radio_print_type[] = {ICON_PRINT_TO_BOTTOM, ICON_PRINT_SHEETS,
+ -1};
+ wimp_i radio_print_orientation[] = {ICON_PRINT_UPRIGHT,
+ ICON_PRINT_SIDEWAYS, -1};
+
+ dialog_print = ro_gui_dialog_create("print");
+ ro_gui_wimp_event_register_radio(dialog_print, radio_print_type);
+ ro_gui_wimp_event_register_radio(dialog_print, radio_print_orientation);
+ ro_gui_wimp_event_register_checkbox(dialog_print, ICON_PRINT_FG_IMAGES);
+ ro_gui_wimp_event_register_checkbox(dialog_print, ICON_PRINT_BG_IMAGES);
+ ro_gui_wimp_event_register_checkbox(dialog_print,
+ ICON_PRINT_IN_BACKGROUND);
+ ro_gui_wimp_event_register_checkbox(dialog_print,
+ ICON_PRINT_TEXT_BLACK);
+ ro_gui_wimp_event_register_text_field(dialog_print,
+ ICON_PRINT_SHEETS_TEXT);
+ ro_gui_wimp_event_register_numeric_field(dialog_print,
+ ICON_PRINT_COPIES, ICON_PRINT_COPIES_UP,
+ ICON_PRINT_COPIES_DOWN, 1, 99, 1, 0);
+ ro_gui_wimp_event_register_numeric_field(dialog_print,
+ ICON_PRINT_SHEETS_VALUE, ICON_PRINT_SHEETS_UP,
+ ICON_PRINT_SHEETS_DOWN, 1, 99, 1, 0);
+ ro_gui_wimp_event_register_cancel(dialog_print, ICON_PRINT_CANCEL);
+ ro_gui_wimp_event_register_mouse_click(dialog_print,
+ ro_gui_print_click);
+ ro_gui_wimp_event_register_ok(dialog_print, ICON_PRINT_PRINT,
+ ro_gui_print_apply);
+ ro_gui_wimp_event_set_help_prefix(dialog_print, "HelpPrint");
+}
+
+
+/**
+ * Prepares all aspects of the print dialog prior to opening.
+ *
+ * \param g parent window
+ */
+
+void ro_gui_print_prepare(struct gui_window *g)
+{
+ char *desc;
+ bool printers_exists = true;
+ os_error *error;
+
+ assert(g);
+
+ ro_print_current_window = g;
+ print_prev_message = 0;
+
+ /* Read Printer Driver name */
+ error = xpdriver_info(0, 0, 0, 0, &desc, 0, 0, 0);
+ if (error) {
+ LOG("xpdriver_info: 0x%x: %s", error->errnum, error->errmess);
+ printers_exists = false;
+ }
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_TO_BOTTOM,
+ true);
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_SHEETS, false);
+ ro_gui_set_icon_integer(dialog_print, ICON_PRINT_SHEETS_VALUE, 1);
+ print_update_sheets_shaded_state(true);
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_FG_IMAGES,
+ true);
+ ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_FG_IMAGES, true);
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_BG_IMAGES,
+ print_bg_images);
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_IN_BACKGROUND,
+ false);
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_UPRIGHT, true);
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_SIDEWAYS,
+ false);
+
+ ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_TEXT_BLACK,
+ false);
+
+ ro_gui_set_icon_integer(dialog_print, ICON_PRINT_COPIES, 1);
+
+ ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_PRINT,
+ !printers_exists);
+ if (printers_exists)
+ ro_gui_set_window_title(dialog_print, desc);
+
+ ro_gui_wimp_event_memorise(dialog_print);
+}
+
+
+/**
+ * Handle mouse clicks in print dialog
+ *
+ * \param pointer wimp_pointer block
+ */
+
+bool ro_gui_print_click(wimp_pointer *pointer)
+{
+ if (pointer->buttons == wimp_CLICK_MENU)
+ return true;
+
+ switch (pointer->i) {
+ case ICON_PRINT_TO_BOTTOM:
+ case ICON_PRINT_SHEETS:
+ print_update_sheets_shaded_state(pointer->i !=
+ ICON_PRINT_SHEETS);
+ break;
+ }
+ return false;
+}
+
+
+/**
+ * Handle click on the Print button in the print dialog.
+ */
+
+bool ro_gui_print_apply(wimp_w w)
+{
+ int copies = atoi(ro_gui_get_icon_string(dialog_print,
+ ICON_PRINT_COPIES));
+ int sheets = atoi(ro_gui_get_icon_string(dialog_print,
+ ICON_PRINT_SHEETS_VALUE));
+
+ print_in_background = ro_gui_get_icon_selected_state(dialog_print,
+ ICON_PRINT_IN_BACKGROUND);
+ print_text_black = ro_gui_get_icon_selected_state(dialog_print,
+ ICON_PRINT_TEXT_BLACK);
+ print_sideways = ro_gui_get_icon_selected_state(dialog_print,
+ ICON_PRINT_SIDEWAYS);
+ print_num_copies = copies;
+ if (ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_SHEETS))
+ print_max_sheets = sheets;
+ else
+ print_max_sheets = -1;
+ print_bg_images = ro_gui_get_icon_selected_state(dialog_print,
+ ICON_PRINT_BG_IMAGES);
+
+ print_send_printsave(browser_window_get_content(
+ ro_print_current_window->bw));
+
+ return true;
+}
+
+
+/**
+ * Set shaded state of sheets
+ *
+ * \param on whether to turn shading on or off
+ */
+
+void print_update_sheets_shaded_state(bool on)
+{
+ ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_VALUE, on);
+ ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_DOWN, on);
+ ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_UP, on);
+ ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_TEXT, on);
+ ro_gui_set_caret_first(dialog_print);
+}
+
+
+/**
+ * Send a message_PRINT_SAVE
+ *
+ * \param h handle to content to print.
+ */
+
+void print_send_printsave(hlcache_handle *h)
+{
+ wimp_full_message_data_xfer m;
+ os_error *e;
+ int len;
+
+ len = strlen(content_get_title(h)) + 1;
+ if (212 < len)
+ len = 212;
+
+ m.size = ((44+len+3) & ~3);
+ m.your_ref = 0;
+ m.action = message_PRINT_SAVE;
+ m.w = (wimp_w)0;
+ m.i = m.pos.x = m.pos.y = 0;
+ m.est_size = 1024; /* arbitrary value - it really doesn't matter */
+ m.file_type = ro_content_filetype(h);
+ strncpy(m.file_name, content_get_title(h), 211);
+ m.file_name[211] = 0;
+ e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED,
+ (wimp_message *)&m, 0);
+ if (e) {
+ LOG("xwimp_send_message: 0x%x: %s", e->errnum, e->errmess);
+ ro_warn_user("WimpError", e->errmess);
+ ro_print_cleanup();
+ }
+ print_prev_message = m.my_ref;
+}
+
+
+/**
+ * Send a message_PRINT_TYPE_KNOWN
+ *
+ * \param m message to reply to
+ * \return true on success, false otherwise
+ */
+
+bool print_send_printtypeknown(wimp_message *m)
+{
+ os_error *e;
+
+ m->size = 20;
+ m->your_ref = m->my_ref;
+ m->action = message_PRINT_TYPE_KNOWN;
+ e = xwimp_send_message(wimp_USER_MESSAGE, m, m->sender);
+ if (e) {
+ LOG("xwimp_send_message: 0x%x: %s", e->errnum, e->errmess);
+ ro_warn_user("WimpError", e->errmess);
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Handle a bounced message_PRINT_SAVE
+ *
+ * \param m the bounced message
+ */
+
+void ro_print_save_bounce(wimp_message *m)
+{
+ if (m->my_ref == 0 || m->my_ref != print_prev_message)
+ return;
+
+ /* try to print anyway (we're graphics printing) */
+ if (ro_print_current_window) {
+ print_document(ro_print_current_window, "printer:");
+ }
+ ro_print_cleanup();
+}
+
+
+/**
+ * Handle message_PRINT_ERROR
+ *
+ * \param m the message containing the error
+ */
+
+void ro_print_error(wimp_message *m)
+{
+ pdriver_message_print_error *p = (pdriver_message_print_error*)&m->data;
+ if (m->your_ref == 0 || m->your_ref != print_prev_message)
+ return;
+
+ if (m->size == 20)
+ ro_warn_user("PrintErrorRO2", 0);
+ else
+ ro_warn_user("PrintError", p->errmess);
+
+ ro_print_cleanup();
+}
+
+
+/**
+ * Handle message_PRINT_TYPE_ODD
+ *
+ * \param m the message to handle
+ */
+
+void ro_print_type_odd(wimp_message *m)
+{
+ if ((m->your_ref == 0 || m->your_ref == print_prev_message) &&
+ !print_in_background) {
+ /* reply to a previous message (ie printsave) */
+ if (ro_print_current_window && print_send_printtypeknown(m)) {
+ print_document(ro_print_current_window, "printer:");
+ }
+ ro_print_cleanup();
+ }
+ else {
+ /* broadcast message */
+ /* no need to do anything */
+ }
+
+}
+
+
+/**
+ * Handle message_DATASAVE_ACK for the printing protocol.
+ *
+ * \param m the message to handle
+ * \return true if message successfully handled, false otherwise
+ *
+ * We cheat here and, instead of giving Printers what it asked for (a copy of
+ * the file so it can poke us later via a broadcast of PrintTypeOdd), we give
+ * it a file that it can print itself without having to bother us further. For
+ * PostScript printers (type 0) we give it a PostScript file. Otherwise, we give
+ * it a PrintOut file.
+ *
+ * This method has a couple of advantages:
+ * - we can reuse this code for background printing (we simply ignore the
+ * PrintTypeOdd reply)
+ * - there's no need to ensure all components of a page queued to be printed
+ * still exist when it reaches the top of the queue. (which reduces complexity
+ * a fair bit)
+ */
+
+bool ro_print_ack(wimp_message *m)
+{
+ pdriver_info_type info_type;
+ pdriver_type type;
+ os_error *error;
+
+ if (m->your_ref == 0 || m->your_ref != print_prev_message ||
+ !ro_print_current_window)
+ return false;
+
+ /* read printer driver type */
+ error = xpdriver_info(&info_type, 0, 0, 0, 0, 0, 0, 0);
+ if (error) {
+ LOG("xpdriver_info: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ ro_print_cleanup();
+ return true;
+ }
+ type = info_type >> 16;
+
+ /* print to file */
+ if (!print_document(ro_print_current_window,
+ m->data.data_xfer.file_name)) {
+ ro_print_cleanup();
+ return true;
+ }
+
+ /* send dataload */
+ m->your_ref = m->my_ref;
+ m->action = message_DATA_LOAD;
+
+ if (type == pdriver_TYPE_PS)
+ m->data.data_xfer.file_type = osfile_TYPE_POSTSCRIPT;
+ else
+ m->data.data_xfer.file_type = osfile_TYPE_PRINTOUT;
+
+ error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, m, m->sender);
+ if (error) {
+ LOG("xwimp_send_message: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("WimpError", error->errmess);
+ /* and delete temporary file */
+ xosfile_delete(m->data.data_xfer.file_name,
+ 0, 0, 0, 0, 0);
+ }
+ print_prev_message = m->my_ref;
+
+ ro_print_cleanup();
+ return true;
+}
+
+
+/**
+ * Handle a bounced dataload message
+ *
+ * \param m the message to handle
+ */
+
+void ro_print_dataload_bounce(wimp_message *m)
+{
+ if (m->your_ref == 0 || m->your_ref != print_prev_message)
+ return;
+
+ xosfile_delete(m->data.data_xfer.file_name, 0, 0, 0, 0, 0);
+ ro_print_cleanup();
+}
+
+
+/**
+ * Cleanup after printing
+ */
+
+void ro_print_cleanup(void)
+{
+ ro_print_current_window = NULL;
+ print_text_black = false;
+ print_prev_message = 0;
+ print_max_sheets = -1;
+ ro_gui_menu_destroy();
+ ro_gui_dialog_close(dialog_print);
+}
+
+
+/**
+ * Print a document.
+ *
+ * \param g gui_window containing the document to print
+ * \param filename name of file to print to
+ * \return true on success, false on error and error reported
+ */
+
+bool print_document(struct gui_window *g, const char *filename)
+{
+ int left, right, top, bottom, width, height;
+ int saved_width, saved_height;
+ int yscroll = 0, sheets = print_max_sheets;
+ hlcache_handle *h = browser_window_get_content(g->bw);
+ const char *error_message;
+ pdriver_features features;
+ os_fw fhandle, old_job = 0;
+ os_error *error;
+
+ /* no point printing a blank page */
+ if (!h) {
+ ro_warn_user("PrintError", "nothing to print");
+ return false;
+ }
+
+ /* read printer driver features */
+ error = xpdriver_info(0, 0, 0, &features, 0, 0, 0, 0);
+ if (error) {
+ LOG("xpdriver_info: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ return false;
+ }
+
+ /* read page size */
+ error = xpdriver_page_size(0, 0, &left, &bottom, &right, &top);
+ if (error) {
+ LOG("xpdriver_page_size: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ return false;
+ }
+
+ if (print_sideways) {
+ width = (top - bottom) / 800;
+ height = (right - left) / 800;
+ } else {
+ width = (right - left) / 800;
+ height = (top - bottom) / 800;
+ }
+
+ /* layout the document to the correct width */
+ saved_width = content_get_width(h);
+ saved_height = content_get_height(h);
+ if (content_get_type(h) == CONTENT_HTML)
+ content_reformat(h, false, width, height);
+
+ /* open printer file */
+ error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR |
+ osfind_ERROR_IF_ABSENT, filename, 0, &fhandle);
+ if (error) {
+ LOG("xosfind_openoutw: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ return false;
+ }
+
+ /* select print job */
+ error = xpdriver_select_jobw(fhandle, "NetSurf", &old_job);
+ if (error) {
+ LOG("xpdriver_select_jobw: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ xosfind_closew(fhandle);
+ return false;
+ }
+
+ rufl_invalidate_cache();
+
+ /* declare fonts, if necessary */
+ if (features & pdriver_FEATURE_DECLARE_FONT) {
+ if ((error_message = print_declare_fonts(h)))
+ goto error;
+ }
+
+ ro_gui_current_redraw_gui = g;
+
+ /* print is now active */
+ print_active = true;
+
+ do {
+ struct rect clip;
+ os_box b;
+ os_hom_trfm t;
+ os_coord p;
+ osbool more;
+
+ if (print_sideways) {
+ b.x0 = bottom / 400 -2;
+ b.y0 = left / 400 - 2;
+ b.x1 = top / 400 + 2;
+ b.y1 = right / 400 + 2;
+ t.entries[0][0] = 0;
+ t.entries[0][1] = 65536;
+ t.entries[1][0] = -65536;
+ t.entries[1][1] = 0;
+ p.x = right;
+ p.y = bottom;
+ ro_plot_origin_x = bottom / 400;
+ ro_plot_origin_y = right / 400 + yscroll * 2;
+ } else {
+ b.x0 = left / 400 -2;
+ b.y0 = bottom / 400 - 2;
+ b.x1 = right / 400 + 2;
+ b.y1 = top / 400 + 2;
+ t.entries[0][0] = 65536;
+ t.entries[0][1] = 0;
+ t.entries[1][0] = 0;
+ t.entries[1][1] = 65536;
+ p.x = left;
+ p.y = bottom;
+ ro_plot_origin_x = left / 400;
+ ro_plot_origin_y = top / 400 + yscroll * 2;
+ }
+
+ xhourglass_percentage((int) (yscroll * 100 /
+ content_get_height(h)));
+
+ /* give page rectangle */
+ error = xpdriver_give_rectangle(0, &b, &t, &p, os_COLOUR_WHITE);
+ if (error) {
+ LOG("xpdriver_give_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ error_message = error->errmess;
+ goto error;
+ }
+
+ LOG("given rectangle: [(%d, %d), (%d, %d)]", b.x0, b.y0, b.x1, b.y1);
+
+ /* and redraw the document */
+ error = xpdriver_draw_page(print_num_copies, &b, 0, 0,
+ &more, 0);
+ if (error) {
+ LOG("xpdriver_draw_page: 0x%x: %s", error->errnum, error->errmess);
+ error_message = error->errmess;
+ goto error;
+ }
+
+ while (more) {
+ struct content_redraw_data data;
+ /* TODO: turn knockout off for print */
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = print_bg_images,
+ .plot = &ro_plotters
+ };
+
+ LOG("redrawing area: [(%d, %d), (%d, %d)]", b.x0, b.y0, b.x1, b.y1);
+ clip.x0 = (b.x0 - ro_plot_origin_x) / 2;
+ clip.y0 = (ro_plot_origin_y - b.y1) / 2;
+ clip.x1 = (b.x1 - ro_plot_origin_x) / 2;
+ clip.y1 = (ro_plot_origin_y - b.y0) / 2;
+
+ data.x = 0;
+ data.y = 0;
+ data.width = content_get_width(h);
+ data.height = content_get_height(h);
+ data.background_colour = 0xFFFFFF;
+ data.scale = print_scale;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ if (!content_redraw(h, &data, &clip, &ctx)) {
+ error_message = "redraw error";
+ goto error;
+ }
+
+ error = xpdriver_get_rectangle(&b, &more, 0);
+ if (error) {
+ LOG("xpdriver_get_rectangle: 0x%x: %s", error->errnum, error->errmess);
+ error_message = error->errmess;
+ goto error;
+ }
+ }
+
+ yscroll += height;
+ } while (yscroll <= content_get_height(h) && --sheets != 0);
+
+ /* make print inactive */
+ print_active = false;
+ ro_gui_current_redraw_gui = 0;
+
+ /* clean up
+ *
+ * Call PDriver_EndJob via _swix() so that r9 is preserved. This
+ * prevents a crash if the SWI corrupts it on exit (as seems to
+ * happen on some versions of RISC OS 6).
+ */
+
+ error = (os_error *) _swix(PDriver_EndJob, _IN(0), (int) fhandle);
+ if (error) {
+ LOG("xpdriver_end_jobw: 0x%x: %s", error->errnum, error->errmess);
+ error_message = error->errmess;
+ goto error;
+ }
+
+ error = xosfind_closew(fhandle);
+ if (error) {
+ LOG("xosfind_closew: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ return false;
+ }
+
+ if (old_job) {
+ error = xpdriver_select_jobw(old_job, 0, 0);
+ if (error) {
+ LOG("xpdriver_select_jobw: 0x%x: %s", error->errnum, error->errmess);
+ ro_warn_user("PrintError", error->errmess);
+ /* the printing succeeded anyway */
+ return true;
+ }
+ }
+
+ rufl_invalidate_cache();
+
+ /* restore document layout and redraw browser window */
+ if (content_get_type(h) == CONTENT_HTML)
+ content_reformat(h, false, saved_width, saved_height);
+
+ gui_window_redraw_window(g);
+
+ return true;
+
+error:
+ xpdriver_abort_job(fhandle);
+ xosfind_closew(fhandle);
+ if (old_job)
+ xpdriver_select_jobw(old_job, 0, 0);
+ print_active = false;
+ ro_gui_current_redraw_gui = 0;
+
+ ro_warn_user("PrintError", error_message);
+
+ rufl_invalidate_cache();
+
+ /* restore document layout */
+ if (content_get_type(h) == CONTENT_HTML)
+ content_reformat(h, false, saved_width, saved_height);
+
+ return false;
+}
+
+
+/**
+ * Declare fonts to the printer driver.
+ *
+ * \param h handle to content being printed
+ * \return 0 on success, error message on error
+ */
+
+const char *print_declare_fonts(hlcache_handle *h)
+{
+ unsigned int i;
+ struct rect clip;
+ struct content_redraw_data data;
+ const char *error_message = 0;
+ os_error *error;
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = false,
+ .plot = &print_fonts_plotters
+ };
+
+ free(print_fonts_list);
+ print_fonts_list = 0;
+ print_fonts_count = 0;
+ print_fonts_error = 0;
+
+ clip.x0 = clip.y0 = INT_MIN;
+ clip.x1 = clip.y1 = INT_MAX;
+
+ data.x = 0;
+ data.y = 0;
+ data.width = content_get_width(h);
+ data.height = content_get_height(h);
+ data.background_colour = 0xFFFFFF;
+ data.scale = 1;
+ data.repeat_x = false;
+ data.repeat_y = false;
+
+ if (!content_redraw(h, &data, &clip, &ctx)) {
+ if (print_fonts_error)
+ return print_fonts_error;
+ return "Declaring fonts failed.";
+ }
+
+ for (i = 0; i != print_fonts_count; ++i) {
+ LOG("%u %s", i, print_fonts_list[i]);
+ error = xpdriver_declare_font(0, print_fonts_list[i],
+ pdriver_KERNED);
+ if (error) {
+ LOG("xpdriver_declare_font: 0x%x: %s", error->errnum, error->errmess);
+ error_message = error->errmess;
+ goto end;
+ }
+ }
+ error = xpdriver_declare_font(0, 0, 0);
+ if (error) {
+ LOG("xpdriver_declare_font: 0x%x: %s", error->errnum, error->errmess);
+ error_message = error->errmess;
+ goto end;
+ }
+
+end:
+ for (i = 0; i != print_fonts_count; i++)
+ free(print_fonts_list[i]);
+ free(print_fonts_list);
+ print_fonts_list = 0;
+
+ return error_message;
+}
+
+
+bool print_fonts_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ return true;
+}
+
+
+bool print_fonts_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ return true;
+}
+
+bool print_fonts_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+{
+ return true;
+}
+
+
+bool print_fonts_plot_clip(const struct rect *clip)
+{
+ return true;
+}
+
+bool print_fonts_plot_disc(int x, int y, int radius, const plot_style_t *style)
+{
+ return true;
+}
+
+bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2,
+ const plot_style_t *style)
+{
+ return true;
+}
+
+bool print_fonts_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg, bitmap_flags_t flags)
+{
+ return true;
+}
+
+bool print_fonts_plot_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6])
+{
+ return true;
+}
+
+
+/**
+ * Plotter for text plotting during font listing.
+ */
+
+bool print_fonts_plot_text(int x, int y, const char *text, size_t length,
+ const plot_font_style_t *fstyle)
+{
+ const char *font_family;
+ unsigned int font_size;
+ rufl_style font_style;
+ rufl_code code;
+
+ nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
+
+ code = rufl_paint_callback(font_family, font_style, font_size,
+ text, length, 0, 0, print_fonts_callback, 0);
+ if (code != rufl_OK) {
+ if (code == rufl_FONT_MANAGER_ERROR) {
+ LOG("rufl_paint_callback: rufl_FONT_MANAGER_ERROR: ""0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess);
+ print_fonts_error = rufl_fm_error->errmess;
+ } else {
+ LOG("rufl_paint_callback: 0x%x", code);
+ }
+ return false;
+ }
+ if (print_fonts_error)
+ return false;
+
+ return true;
+}
+
+
+/**
+ * Callback for print_fonts_plot_text().
+ *
+ * The font name is added to print_fonts_list.
+ */
+
+void print_fonts_callback(void *context,
+ const char *font_name, unsigned int font_size,
+ const char *s8, unsigned short *s16, unsigned int n,
+ int x, int y)
+{
+ unsigned int i;
+ char **fonts_list;
+
+ (void) context; /* unused */
+ (void) font_size; /* unused */
+ (void) x; /* unused */
+ (void) y; /* unused */
+
+ assert(s8 || s16);
+
+ /* check if the font name is new */
+ for (i = 0; i != print_fonts_count &&
+ strcmp(print_fonts_list[i], font_name) != 0; i++)
+ ;
+ if (i != print_fonts_count)
+ return;
+
+ /* add to list of fonts */
+ fonts_list = realloc(print_fonts_list,
+ sizeof print_fonts_list[0] *
+ (print_fonts_count + 1));
+ if (!fonts_list) {
+ print_fonts_error = messages_get("NoMemory");
+ return;
+ }
+ fonts_list[print_fonts_count] = strdup(font_name);
+ if (!fonts_list[print_fonts_count]) {
+ print_fonts_error = messages_get("NoMemory");
+ return;
+ }
+ print_fonts_list = fonts_list;
+ print_fonts_count++;
+}
+