mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-23 20:46:50 +03:00
c105738fa3
This changes the LOG macro to be varadic removing the need for all callsites to have double bracketing and allows for future improvement on how we use the logging macros. The callsites were changed with coccinelle and the changes checked by hand. Compile tested for several frontends but not all. A formatting annotation has also been added which allows the compiler to check the parameters and types passed to the logging.
976 lines
25 KiB
C
976 lines
25 KiB
C
/*
|
|
* 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 "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);
|
|
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);
|
|
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)
|
|
warn_user("PrintErrorRO2", 0);
|
|
else
|
|
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);
|
|
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);
|
|
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) {
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
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;
|
|
|
|
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++;
|
|
}
|
|
|