1 /*
2  * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
3  * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
4  *
5  * This file is part of NetSurf, http://www.netsurf-browser.org/
6  *
7  * NetSurf is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * NetSurf is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "utils/config.h"
21 
22 #include <assert.h>
23 #include <string.h>
24 #include <swis.h>
25 #include <oslib/font.h>
26 #include <oslib/hourglass.h>
27 #include <oslib/osfile.h>
28 #include <oslib/osfind.h>
29 #include <oslib/pdriver.h>
30 #include <oslib/wimp.h>
31 #include <rufl.h>
32 #include <limits.h>
33 
34 #include "utils/config.h"
35 #include "utils/log.h"
36 #include "utils/messages.h"
37 #include "utils/nsoption.h"
38 #include "netsurf/browser_window.h"
39 #include "netsurf/plotters.h"
40 #include "netsurf/content.h"
41 #include "content/content.h"
42 
43 #include "riscos/gui.h"
44 #include "riscos/window.h"
45 #include "riscos/dialog.h"
46 #include "riscos/menus.h"
47 #include "riscos/print.h"
48 #include "riscos/wimp.h"
49 #include "riscos/wimp_event.h"
50 #include "riscos/filetype.h"
51 #include "riscos/font.h"
52 
53 
54 #define ICON_PRINT_TO_BOTTOM 1
55 #define ICON_PRINT_SHEETS 2
56 #define ICON_PRINT_SHEETS_VALUE 3
57 #define ICON_PRINT_SHEETS_DOWN 4
58 #define ICON_PRINT_SHEETS_UP 5
59 #define ICON_PRINT_SHEETS_TEXT 6
60 #define ICON_PRINT_FG_IMAGES 7
61 #define ICON_PRINT_BG_IMAGES 8
62 #define ICON_PRINT_IN_BACKGROUND 9
63 #define ICON_PRINT_UPRIGHT 10
64 #define ICON_PRINT_SIDEWAYS 11
65 #define ICON_PRINT_COPIES 12
66 #define ICON_PRINT_COPIES_DOWN 13
67 #define ICON_PRINT_COPIES_UP 14
68 #define ICON_PRINT_CANCEL 15
69 #define ICON_PRINT_PRINT 16
70 #define ICON_PRINT_TEXT_BLACK 20
71 
72 
73 /** \todo landscape format pages
74  *  \todo be somewhat more intelligent and try not to crop pages
75  *        half way up a line of text
76  *  \todo make use of print stylesheets
77  */
78 
79 struct gui_window *ro_print_current_window = NULL;
80 bool print_text_black = false;
81 bool print_active = false;
82 
83 /* 1 millipoint == 1/400 OS unit == 1/800 browser units */
84 
85 static int print_prev_message = 0;
86 static bool print_in_background = false;
87 static float print_scale = 1.0;
88 static int print_num_copies = 1;
89 static bool print_bg_images = false;
90 static int print_max_sheets = -1;
91 static bool print_sideways = false;
92 /** List of fonts in current print. */
93 static char **print_fonts_list = 0;
94 /** Number of entries in print_fonts_list. */
95 static unsigned int print_fonts_count;
96 /** Error in print_fonts_plot_text() or print_fonts_callback(). */
97 static const char *print_fonts_error;
98 
99 
100 static bool ro_gui_print_click(wimp_pointer *pointer);
101 static bool ro_gui_print_apply(wimp_w w);
102 static void print_update_sheets_shaded_state(bool on);
103 static void print_send_printsave(struct hlcache_handle *h);
104 static bool print_send_printtypeknown(wimp_message *m);
105 static bool print_document(struct gui_window *g, const char *filename);
106 static const char *print_declare_fonts(struct hlcache_handle *h);
107 static void print_fonts_callback(void *context,
108 		const char *font_name, unsigned int font_size,
109 		const char *s8, unsigned short *s16, unsigned int n,
110 		int x, int y);
111 
112 
113 
114 
115 /**
116  * Initialise the print dialog.
117  */
118 
ro_gui_print_init(void)119 void ro_gui_print_init(void)
120 {
121   	wimp_i radio_print_type[] = {ICON_PRINT_TO_BOTTOM, ICON_PRINT_SHEETS,
122   			-1};
123   	wimp_i radio_print_orientation[] = {ICON_PRINT_UPRIGHT,
124   			ICON_PRINT_SIDEWAYS, -1};
125 
126 	dialog_print = ro_gui_dialog_create("print");
127 	ro_gui_wimp_event_register_radio(dialog_print, radio_print_type);
128 	ro_gui_wimp_event_register_radio(dialog_print, radio_print_orientation);
129 	ro_gui_wimp_event_register_checkbox(dialog_print, ICON_PRINT_FG_IMAGES);
130 	ro_gui_wimp_event_register_checkbox(dialog_print, ICON_PRINT_BG_IMAGES);
131 	ro_gui_wimp_event_register_checkbox(dialog_print,
132 			ICON_PRINT_IN_BACKGROUND);
133 	ro_gui_wimp_event_register_checkbox(dialog_print,
134 			ICON_PRINT_TEXT_BLACK);
135 	ro_gui_wimp_event_register_text_field(dialog_print,
136 			ICON_PRINT_SHEETS_TEXT);
137 	ro_gui_wimp_event_register_numeric_field(dialog_print,
138 			ICON_PRINT_COPIES, ICON_PRINT_COPIES_UP,
139 			ICON_PRINT_COPIES_DOWN, 1, 99, 1, 0);
140 	ro_gui_wimp_event_register_numeric_field(dialog_print,
141 			ICON_PRINT_SHEETS_VALUE, ICON_PRINT_SHEETS_UP,
142 			ICON_PRINT_SHEETS_DOWN, 1, 99, 1, 0);
143 	ro_gui_wimp_event_register_cancel(dialog_print, ICON_PRINT_CANCEL);
144 	ro_gui_wimp_event_register_mouse_click(dialog_print,
145 			ro_gui_print_click);
146 	ro_gui_wimp_event_register_ok(dialog_print, ICON_PRINT_PRINT,
147 			ro_gui_print_apply);
148 	ro_gui_wimp_event_set_help_prefix(dialog_print, "HelpPrint");
149 }
150 
151 
152 /**
153  * Prepares all aspects of the print dialog prior to opening.
154  *
155  * \param g parent window
156  */
157 
ro_gui_print_prepare(struct gui_window * g)158 void ro_gui_print_prepare(struct gui_window *g)
159 {
160 	char *desc;
161 	bool printers_exists = true;
162 	os_error *error;
163 
164 	assert(g);
165 
166 	ro_print_current_window = g;
167 	print_prev_message = 0;
168 
169 	/* Read Printer Driver name */
170 	error = xpdriver_info(0, 0, 0, 0, &desc, 0, 0, 0);
171 	if (error) {
172 		NSLOG(netsurf, INFO, "xpdriver_info: 0x%x: %s",
173 		      error->errnum, error->errmess);
174 		printers_exists = false;
175 	}
176 
177 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_TO_BOTTOM,
178 			true);
179 
180 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_SHEETS, false);
181 	ro_gui_set_icon_integer(dialog_print, ICON_PRINT_SHEETS_VALUE, 1);
182 	print_update_sheets_shaded_state(true);
183 
184 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_FG_IMAGES,
185 			true);
186 	ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_FG_IMAGES, true);
187 
188 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_BG_IMAGES,
189 			print_bg_images);
190 
191 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_IN_BACKGROUND,
192 			false);
193 
194 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_UPRIGHT, true);
195 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_SIDEWAYS,
196 			false);
197 
198 	ro_gui_set_icon_selected_state(dialog_print, ICON_PRINT_TEXT_BLACK,
199 			false);
200 
201 	ro_gui_set_icon_integer(dialog_print, ICON_PRINT_COPIES, 1);
202 
203 	ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_PRINT,
204 			!printers_exists);
205 	if (printers_exists)
206 		ro_gui_set_window_title(dialog_print, desc);
207 
208 	ro_gui_wimp_event_memorise(dialog_print);
209 }
210 
211 
212 /**
213  * Handle mouse clicks in print dialog
214  *
215  * \param pointer wimp_pointer block
216  */
217 
ro_gui_print_click(wimp_pointer * pointer)218 bool ro_gui_print_click(wimp_pointer *pointer)
219 {
220 	if (pointer->buttons == wimp_CLICK_MENU)
221 		return true;
222 
223 	switch (pointer->i) {
224 		case ICON_PRINT_TO_BOTTOM:
225 		case ICON_PRINT_SHEETS:
226 			print_update_sheets_shaded_state(pointer->i !=
227 					ICON_PRINT_SHEETS);
228 			break;
229 	}
230 	return false;
231 }
232 
233 
234 /**
235  * Handle click on the Print button in the print dialog.
236  */
237 
ro_gui_print_apply(wimp_w w)238 bool ro_gui_print_apply(wimp_w w)
239 {
240 	int copies = atoi(ro_gui_get_icon_string(dialog_print,
241 						ICON_PRINT_COPIES));
242 	int sheets = atoi(ro_gui_get_icon_string(dialog_print,
243 						ICON_PRINT_SHEETS_VALUE));
244 
245 	print_in_background = ro_gui_get_icon_selected_state(dialog_print,
246 			ICON_PRINT_IN_BACKGROUND);
247 	print_text_black = ro_gui_get_icon_selected_state(dialog_print,
248 			ICON_PRINT_TEXT_BLACK);
249 	print_sideways = ro_gui_get_icon_selected_state(dialog_print,
250 			ICON_PRINT_SIDEWAYS);
251 	print_num_copies = copies;
252 	if (ro_gui_get_icon_selected_state(dialog_print, ICON_PRINT_SHEETS))
253 		print_max_sheets = sheets;
254 	else
255 		print_max_sheets = -1;
256 	print_bg_images = ro_gui_get_icon_selected_state(dialog_print,
257 			ICON_PRINT_BG_IMAGES);
258 
259 	print_send_printsave(browser_window_get_content(
260 			ro_print_current_window->bw));
261 
262 	return true;
263 }
264 
265 
266 /**
267  * Set shaded state of sheets
268  *
269  * \param on whether to turn shading on or off
270  */
271 
print_update_sheets_shaded_state(bool on)272 void print_update_sheets_shaded_state(bool on)
273 {
274 	ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_VALUE, on);
275 	ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_DOWN, on);
276 	ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_UP, on);
277 	ro_gui_set_icon_shaded_state(dialog_print, ICON_PRINT_SHEETS_TEXT, on);
278 	ro_gui_set_caret_first(dialog_print);
279 }
280 
281 
282 /**
283  * Send a message_PRINT_SAVE
284  *
285  * \param h handle to content to print.
286  */
287 
print_send_printsave(struct hlcache_handle * h)288 void print_send_printsave(struct hlcache_handle *h)
289 {
290 	wimp_full_message_data_xfer m;
291 	os_error *e;
292 	int len;
293 
294 	len = strlen(content_get_title(h)) + 1;
295 	if (212 < len)
296 		len = 212;
297 
298 	m.size = ((44+len+3) & ~3);
299 	m.your_ref = 0;
300 	m.action = message_PRINT_SAVE;
301 	m.w = (wimp_w)0;
302 	m.i = m.pos.x = m.pos.y = 0;
303 	m.est_size = 1024; /* arbitrary value - it really doesn't matter */
304 	m.file_type = ro_content_filetype(h);
305 	strncpy(m.file_name, content_get_title(h), 211);
306 	m.file_name[211] = 0;
307 	e = xwimp_send_message(wimp_USER_MESSAGE_RECORDED,
308 			(wimp_message *)&m, 0);
309 	if (e) {
310 		NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
311 		      e->errnum, e->errmess);
312 		ro_warn_user("WimpError", e->errmess);
313 		ro_print_cleanup();
314 	}
315 	print_prev_message = m.my_ref;
316 }
317 
318 
319 /**
320  * Send a message_PRINT_TYPE_KNOWN
321  *
322  * \param m message to reply to
323  * \return true on success, false otherwise
324  */
325 
print_send_printtypeknown(wimp_message * m)326 bool print_send_printtypeknown(wimp_message *m)
327 {
328 	os_error *e;
329 
330 	m->size = 20;
331 	m->your_ref = m->my_ref;
332 	m->action = message_PRINT_TYPE_KNOWN;
333 	e = xwimp_send_message(wimp_USER_MESSAGE, m, m->sender);
334 	if (e) {
335 		NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
336 		      e->errnum, e->errmess);
337 		ro_warn_user("WimpError", e->errmess);
338 		return false;
339 	}
340 
341 	return true;
342 }
343 
344 
345 /**
346  * Handle a bounced message_PRINT_SAVE
347  *
348  * \param m the bounced message
349  */
350 
ro_print_save_bounce(wimp_message * m)351 void ro_print_save_bounce(wimp_message *m)
352 {
353 	if (m->my_ref == 0 || m->my_ref != print_prev_message)
354 		return;
355 
356 	/* try to print anyway (we're graphics printing) */
357 	if (ro_print_current_window) {
358 		print_document(ro_print_current_window, "printer:");
359 	}
360 	ro_print_cleanup();
361 }
362 
363 
364 /**
365  * Handle message_PRINT_ERROR
366  *
367  * \param m the message containing the error
368  */
369 
ro_print_error(wimp_message * m)370 void ro_print_error(wimp_message *m)
371 {
372 	pdriver_message_print_error *p = (pdriver_message_print_error*)&m->data;
373 	if (m->your_ref == 0 || m->your_ref != print_prev_message)
374 		return;
375 
376 	if (m->size == 20)
377 		ro_warn_user("PrintErrorRO2", 0);
378 	else
379 		ro_warn_user("PrintError", p->errmess);
380 
381 	ro_print_cleanup();
382 }
383 
384 
385 /**
386  * Handle message_PRINT_TYPE_ODD
387  *
388  * \param m the message to handle
389  */
390 
ro_print_type_odd(wimp_message * m)391 void ro_print_type_odd(wimp_message *m)
392 {
393 	if ((m->your_ref == 0 || m->your_ref == print_prev_message) &&
394 						!print_in_background) {
395 		/* reply to a previous message (ie printsave) */
396 		if (ro_print_current_window && print_send_printtypeknown(m)) {
397 			print_document(ro_print_current_window, "printer:");
398 		}
399 		ro_print_cleanup();
400 	}
401 	else {
402 		/* broadcast message */
403 		/* no need to do anything */
404 	}
405 
406 }
407 
408 
409 /**
410  * Handle message_DATASAVE_ACK for the printing protocol.
411  *
412  * \param  m  the message to handle
413  * \return true if message successfully handled, false otherwise
414  *
415  * We cheat here and, instead of giving Printers what it asked for (a copy of
416  * the file so it can poke us later via a broadcast of PrintTypeOdd), we give
417  * it a file that it can print itself without having to bother us further. For
418  * PostScript printers (type 0) we give it a PostScript file. Otherwise, we give
419  * it a PrintOut file.
420  *
421  * This method has a couple of advantages:
422  * - we can reuse this code for background printing (we simply ignore the
423  *   PrintTypeOdd reply)
424  * - there's no need to ensure all components of a page queued to be printed
425  *   still exist when it reaches the top of the queue. (which reduces complexity
426  *   a fair bit)
427  */
428 
ro_print_ack(wimp_message * m)429 bool ro_print_ack(wimp_message *m)
430 {
431 	pdriver_info_type info_type;
432 	pdriver_type type;
433 	os_error *error;
434 
435 	if (m->your_ref == 0 || m->your_ref != print_prev_message ||
436 			!ro_print_current_window)
437 		return false;
438 
439 	/* read printer driver type */
440 	error = xpdriver_info(&info_type, 0, 0, 0, 0, 0, 0, 0);
441 	if (error) {
442 		NSLOG(netsurf, INFO, "xpdriver_info: 0x%x: %s",
443 		      error->errnum, error->errmess);
444 		ro_warn_user("PrintError", error->errmess);
445 		ro_print_cleanup();
446 		return true;
447 	}
448 	type = info_type >> 16;
449 
450 	/* print to file */
451 	if (!print_document(ro_print_current_window,
452 			m->data.data_xfer.file_name)) {
453 		ro_print_cleanup();
454 		return true;
455 	}
456 
457 	/* send dataload */
458 	m->your_ref = m->my_ref;
459 	m->action = message_DATA_LOAD;
460 
461 	if (type == pdriver_TYPE_PS)
462 		m->data.data_xfer.file_type = osfile_TYPE_POSTSCRIPT;
463 	else
464 		m->data.data_xfer.file_type = osfile_TYPE_PRINTOUT;
465 
466 	error = xwimp_send_message(wimp_USER_MESSAGE_RECORDED, m, m->sender);
467 	if (error) {
468 		NSLOG(netsurf, INFO, "xwimp_send_message: 0x%x: %s",
469 		      error->errnum, error->errmess);
470 		ro_warn_user("WimpError", error->errmess);
471 		/* and delete temporary file */
472 		xosfile_delete(m->data.data_xfer.file_name,
473 				0, 0, 0, 0, 0);
474 	}
475 	print_prev_message = m->my_ref;
476 
477 	ro_print_cleanup();
478 	return true;
479 }
480 
481 
482 /**
483  * Handle a bounced dataload message
484  *
485  * \param m the message to handle
486  */
487 
ro_print_dataload_bounce(wimp_message * m)488 void ro_print_dataload_bounce(wimp_message *m)
489 {
490 	if (m->your_ref == 0 || m->your_ref != print_prev_message)
491 		return;
492 
493 	xosfile_delete(m->data.data_xfer.file_name, 0, 0, 0, 0, 0);
494 	ro_print_cleanup();
495 }
496 
497 
498 /**
499  * Cleanup after printing
500  */
501 
ro_print_cleanup(void)502 void ro_print_cleanup(void)
503 {
504 	ro_print_current_window = NULL;
505 	print_text_black = false;
506 	print_prev_message = 0;
507 	print_max_sheets = -1;
508 	ro_gui_menu_destroy();
509 	ro_gui_dialog_close(dialog_print);
510 }
511 
512 
513 /**
514  * Print a document.
515  *
516  * \param  g         gui_window containing the document to print
517  * \param  filename  name of file to print to
518  * \return true on success, false on error and error reported
519  */
520 
print_document(struct gui_window * g,const char * filename)521 bool print_document(struct gui_window *g, const char *filename)
522 {
523 	int left, right, top, bottom, width, height;
524 	int saved_width, saved_height;
525 	int yscroll = 0, sheets = print_max_sheets;
526 	struct hlcache_handle *h = browser_window_get_content(g->bw);
527 	const char *error_message;
528 	pdriver_features features;
529 	os_fw fhandle, old_job = 0;
530 	os_error *error;
531 
532 	/* no point printing a blank page */
533 	if (!h) {
534 		ro_warn_user("PrintError", "nothing to print");
535 		return false;
536 	}
537 
538 	/* read printer driver features */
539 	error = xpdriver_info(0, 0, 0, &features, 0, 0, 0, 0);
540 	if (error) {
541 		NSLOG(netsurf, INFO, "xpdriver_info: 0x%x: %s",
542 		      error->errnum, error->errmess);
543 		ro_warn_user("PrintError", error->errmess);
544 		return false;
545 	}
546 
547 	/* read page size */
548 	error = xpdriver_page_size(0, 0, &left, &bottom, &right, &top);
549 	if (error) {
550 		NSLOG(netsurf, INFO, "xpdriver_page_size: 0x%x: %s",
551 		      error->errnum, error->errmess);
552 		ro_warn_user("PrintError", error->errmess);
553 		return false;
554 	}
555 
556 	if (print_sideways) {
557 		width = (top - bottom) / 800;
558 		height = (right - left) / 800;
559 	} else {
560 		width = (right - left) / 800;
561 		height = (top - bottom) / 800;
562 	}
563 
564 	/* layout the document to the correct width */
565 	saved_width = content_get_width(h);
566 	saved_height = content_get_height(h);
567 	if (content_get_type(h) == CONTENT_HTML)
568 		content_reformat(h, false, width, height);
569 
570 	/* open printer file */
571 	error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR |
572 			osfind_ERROR_IF_ABSENT, filename, 0, &fhandle);
573 	if (error) {
574 		NSLOG(netsurf, INFO, "xosfind_openoutw: 0x%x: %s",
575 		      error->errnum, error->errmess);
576 		ro_warn_user("PrintError", error->errmess);
577 		return false;
578 	}
579 
580 	/* select print job */
581 	error = xpdriver_select_jobw(fhandle, "NetSurf", &old_job);
582 	if (error) {
583 		NSLOG(netsurf, INFO, "xpdriver_select_jobw: 0x%x: %s",
584 		      error->errnum, error->errmess);
585 		ro_warn_user("PrintError", error->errmess);
586 		xosfind_closew(fhandle);
587 		return false;
588 	}
589 
590 	rufl_invalidate_cache();
591 
592 	/* declare fonts, if necessary */
593 	if (features & pdriver_FEATURE_DECLARE_FONT) {
594 		if ((error_message = print_declare_fonts(h)))
595 			goto error;
596 	}
597 
598 	ro_gui_current_redraw_gui = g;
599 
600 	/* print is now active */
601 	print_active = true;
602 
603 	do {
604 		struct rect clip;
605 		os_box b;
606 		os_hom_trfm t;
607 		os_coord p;
608 		osbool more;
609 
610 		if (print_sideways) {
611 			b.x0 = bottom / 400 -2;
612 			b.y0 = left / 400 - 2;
613 			b.x1 = top / 400 + 2;
614 			b.y1 = right / 400 + 2;
615 			t.entries[0][0] = 0;
616 			t.entries[0][1] = 65536;
617 			t.entries[1][0] = -65536;
618 			t.entries[1][1] = 0;
619 			p.x = right;
620 			p.y = bottom;
621 			ro_plot_origin_x = bottom / 400;
622 			ro_plot_origin_y = right / 400 + yscroll * 2;
623 		} else {
624 			b.x0 = left / 400 -2;
625 			b.y0 = bottom / 400 - 2;
626 			b.x1 = right / 400 + 2;
627 			b.y1 = top / 400 + 2;
628 			t.entries[0][0] = 65536;
629 			t.entries[0][1] = 0;
630 			t.entries[1][0] = 0;
631 			t.entries[1][1] = 65536;
632 			p.x = left;
633 			p.y = bottom;
634 			ro_plot_origin_x = left / 400;
635 			ro_plot_origin_y = top / 400 + yscroll * 2;
636 		}
637 
638 		xhourglass_percentage((int) (yscroll * 100 /
639 				content_get_height(h)));
640 
641 		/* give page rectangle */
642 		error = xpdriver_give_rectangle(0, &b, &t, &p, os_COLOUR_WHITE);
643 		if (error) {
644 			NSLOG(netsurf, INFO,
645 			      "xpdriver_give_rectangle: 0x%x: %s",
646 			      error->errnum,
647 			      error->errmess);
648 			error_message = error->errmess;
649 			goto error;
650 		}
651 
652 		NSLOG(netsurf, INFO, "given rectangle: [(%d, %d), (%d, %d)]",
653 		      b.x0, b.y0, b.x1, b.y1);
654 
655 		/* and redraw the document */
656 		error = xpdriver_draw_page(print_num_copies, &b, 0, 0,
657 				&more, 0);
658 		if (error) {
659 			NSLOG(netsurf, INFO, "xpdriver_draw_page: 0x%x: %s",
660 			      error->errnum, error->errmess);
661 			error_message = error->errmess;
662 			goto error;
663 		}
664 
665 		while (more) {
666 			struct content_redraw_data data;
667 			/* TODO: turn knockout off for print */
668 			struct redraw_context ctx = {
669 				.interactive = false,
670 				.background_images = print_bg_images,
671 				.plot = &ro_plotters
672 			};
673 
674 			NSLOG(netsurf, INFO,
675 			      "redrawing area: [(%d, %d), (%d, %d)]", b.x0,
676 			      b.y0, b.x1, b.y1);
677 			clip.x0 = (b.x0 - ro_plot_origin_x) / 2;
678 			clip.y0 = (ro_plot_origin_y - b.y1) / 2;
679 			clip.x1 = (b.x1 - ro_plot_origin_x) / 2;
680 			clip.y1 = (ro_plot_origin_y - b.y0) / 2;
681 
682 			data.x = 0;
683 			data.y = 0;
684 			data.width = content_get_width(h);
685 			data.height = content_get_height(h);
686 			data.background_colour = 0xFFFFFF;
687 			data.scale = print_scale;
688 			data.repeat_x = false;
689 			data.repeat_y = false;
690 
691 			if (!content_redraw(h, &data, &clip, &ctx)) {
692 				error_message = "redraw error";
693 				goto error;
694 			}
695 
696 			error = xpdriver_get_rectangle(&b, &more, 0);
697 			if (error) {
698 				NSLOG(netsurf, INFO,
699 				      "xpdriver_get_rectangle: 0x%x: %s",
700 				      error->errnum,
701 				      error->errmess);
702 				error_message = error->errmess;
703 				goto error;
704 			}
705 		}
706 
707 		yscroll += height;
708 	} while (yscroll <= content_get_height(h) && --sheets != 0);
709 
710 	/* make print inactive */
711 	print_active = false;
712 	ro_gui_current_redraw_gui = 0;
713 
714 	/* clean up
715 	 *
716 	 * Call PDriver_EndJob via _swix() so that r9 is preserved.  This
717 	 * prevents a crash if the SWI corrupts it on exit (as seems to
718 	 * happen on some versions of RISC OS 6).
719 	 */
720 
721 	error = (os_error *) _swix(PDriver_EndJob, _IN(0), (int) fhandle);
722 	if (error) {
723 		NSLOG(netsurf, INFO, "xpdriver_end_jobw: 0x%x: %s",
724 		      error->errnum, error->errmess);
725 		error_message = error->errmess;
726 		goto error;
727 	}
728 
729 	error = xosfind_closew(fhandle);
730 	if (error) {
731 		NSLOG(netsurf, INFO, "xosfind_closew: 0x%x: %s",
732 		      error->errnum, error->errmess);
733 		ro_warn_user("PrintError", error->errmess);
734 		return false;
735 	}
736 
737 	if (old_job) {
738 		error = xpdriver_select_jobw(old_job, 0, 0);
739 		if (error) {
740 			NSLOG(netsurf, INFO,
741 			      "xpdriver_select_jobw: 0x%x: %s",
742 			      error->errnum,
743 			      error->errmess);
744 			ro_warn_user("PrintError", error->errmess);
745 			/* the printing succeeded anyway */
746 			return true;
747 		}
748 	}
749 
750 	rufl_invalidate_cache();
751 
752 	/* restore document layout and redraw browser window */
753 	if (content_get_type(h) == CONTENT_HTML)
754 		content_reformat(h, false, saved_width, saved_height);
755 
756 	ro_gui_window_invalidate_area(g, NULL);
757 
758 	return true;
759 
760 error:
761 	xpdriver_abort_job(fhandle);
762 	xosfind_closew(fhandle);
763 	if (old_job)
764 		xpdriver_select_jobw(old_job, 0, 0);
765 	print_active = false;
766 	ro_gui_current_redraw_gui = 0;
767 
768 	ro_warn_user("PrintError", error_message);
769 
770 	rufl_invalidate_cache();
771 
772 	/* restore document layout */
773 	if (content_get_type(h)  == CONTENT_HTML)
774 		content_reformat(h, false, saved_width, saved_height);
775 
776 	return false;
777 }
778 
779 
780 
781 
782 static nserror
print_fonts_plot_clip(const struct redraw_context * ctx,const struct rect * clip)783 print_fonts_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
784 {
785 	return NSERROR_OK;
786 }
787 
788 static nserror
print_fonts_plot_arc(const struct redraw_context * ctx,const plot_style_t * style,int x,int y,int radius,int angle1,int angle2)789 print_fonts_plot_arc(const struct redraw_context *ctx,
790 	       const plot_style_t *style,
791 	       int x, int y, int radius, int angle1, int angle2)
792 {
793 	return NSERROR_OK;
794 }
795 
796 static nserror
print_fonts_plot_disc(const struct redraw_context * ctx,const plot_style_t * style,int x,int y,int radius)797 print_fonts_plot_disc(const struct redraw_context *ctx,
798 		      const plot_style_t *style,
799 		      int x, int y, int radius)
800 {
801 	return NSERROR_OK;
802 }
803 
804 static nserror
print_fonts_plot_line(const struct redraw_context * ctx,const plot_style_t * style,const struct rect * line)805 print_fonts_plot_line(const struct redraw_context *ctx,
806 		      const plot_style_t *style,
807 		      const struct rect *line)
808 {
809 	return NSERROR_OK;
810 }
811 
812 static nserror
print_fonts_plot_rectangle(const struct redraw_context * ctx,const plot_style_t * style,const struct rect * rect)813 print_fonts_plot_rectangle(const struct redraw_context *ctx,
814 		     const plot_style_t *style,
815 		     const struct rect *rect)
816 {
817 	return NSERROR_OK;
818 }
819 
820 static nserror
print_fonts_plot_polygon(const struct redraw_context * ctx,const plot_style_t * style,const int * p,unsigned int n)821 print_fonts_plot_polygon(const struct redraw_context *ctx,
822 		   const plot_style_t *style,
823 		   const int *p,
824 		   unsigned int n)
825 {
826 	return NSERROR_OK;
827 }
828 
829 static nserror
print_fonts_plot_path(const struct redraw_context * ctx,const plot_style_t * pstyle,const float * p,unsigned int n,const float transform[6])830 print_fonts_plot_path(const struct redraw_context *ctx,
831 		const plot_style_t *pstyle,
832 		const float *p,
833 		unsigned int n,
834 		const float transform[6])
835 {
836 	return NSERROR_OK;
837 }
838 
839 static nserror
print_fonts_plot_bitmap(const struct redraw_context * ctx,struct bitmap * bitmap,int x,int y,int width,int height,colour bg,bitmap_flags_t flags)840 print_fonts_plot_bitmap(const struct redraw_context *ctx,
841 	       struct bitmap *bitmap,
842 	       int x, int y,
843 	       int width,
844 	       int height,
845 	       colour bg,
846 	       bitmap_flags_t flags)
847 {
848 	return NSERROR_OK;
849 }
850 
851 /**
852  * text plotting during RO print font listing.
853  *
854  * \param ctx The current redraw context.
855  * \param fstyle plot style for this text
856  * \param x x coordinate
857  * \param y y coordinate
858  * \param text UTF-8 string to plot
859  * \param length length of string, in bytes
860  * \return NSERROR_OK on success else error code.
861  */
862 static nserror
print_fonts_plot_text(const struct redraw_context * ctx,const struct plot_font_style * fstyle,int x,int y,const char * text,size_t length)863 print_fonts_plot_text(const struct redraw_context *ctx,
864 		const struct plot_font_style *fstyle,
865 		int x,
866 		int y,
867 		const char *text,
868 		size_t length)
869 {
870 	const char *font_family;
871 	unsigned int font_size;
872 	rufl_style font_style;
873 	rufl_code code;
874 
875 	nsfont_read_style(fstyle, &font_family, &font_size, &font_style);
876 
877 	code = rufl_paint_callback(font_family, font_style, font_size,
878 			text, length, 0, 0, print_fonts_callback, 0);
879 	if (code != rufl_OK) {
880 		if (code == rufl_FONT_MANAGER_ERROR) {
881 			NSLOG(netsurf, INFO,
882 			      "rufl_paint_callback: rufl_FONT_MANAGER_ERROR: ""0x%x: %s",
883 			      rufl_fm_error->errnum,
884 			      rufl_fm_error->errmess);
885 			print_fonts_error = rufl_fm_error->errmess;
886 		} else {
887 			NSLOG(netsurf, INFO, "rufl_paint_callback: 0x%x",
888 			      code);
889 		}
890 		return NSERROR_INVALID;
891 	}
892 	if (print_fonts_error)
893 		return NSERROR_INVALID;
894 
895 	return NSERROR_OK;
896 }
897 
898 
899 /**
900  * Plotter table for print_declare_fonts().
901  *
902  * All the functions do nothing except for print_fonts_plot_text,
903  * which records the fonts used.
904 */
905 static const struct plotter_table print_fonts_plotters = {
906 	.rectangle = print_fonts_plot_rectangle,
907 	.line = print_fonts_plot_line,
908 	.polygon = print_fonts_plot_polygon,
909 	.clip = print_fonts_plot_clip,
910 	.text = print_fonts_plot_text,
911 	.disc = print_fonts_plot_disc,
912 	.arc = print_fonts_plot_arc,
913 	.bitmap = print_fonts_plot_bitmap,
914 	.path = print_fonts_plot_path,
915 	.option_knockout = false,
916 };
917 
918 
919 /**
920  * Declare fonts to the printer driver.
921  *
922  * \param h handle to content being printed
923  * \return 0 on success, error message on error
924  */
925 
print_declare_fonts(struct hlcache_handle * h)926 const char *print_declare_fonts(struct hlcache_handle *h)
927 {
928 	unsigned int i;
929 	struct rect clip;
930 	struct content_redraw_data data;
931 	const char *error_message = 0;
932 	os_error *error;
933 	struct redraw_context ctx = {
934 		.interactive = false,
935 		.background_images = false,
936 		.plot = &print_fonts_plotters
937 	};
938 
939 	free(print_fonts_list);
940 	print_fonts_list = 0;
941 	print_fonts_count = 0;
942 	print_fonts_error = 0;
943 
944 	clip.x0 = clip.y0 = INT_MIN;
945 	clip.x1 = clip.y1 = INT_MAX;
946 
947 	data.x = 0;
948 	data.y = 0;
949 	data.width = content_get_width(h);
950 	data.height = content_get_height(h);
951 	data.background_colour = 0xFFFFFF;
952 	data.scale = 1;
953 	data.repeat_x = false;
954 	data.repeat_y = false;
955 
956 	if (!content_redraw(h, &data, &clip, &ctx)) {
957 		if (print_fonts_error)
958 			return print_fonts_error;
959 		return "Declaring fonts failed.";
960 	}
961 
962 	for (i = 0; i != print_fonts_count; ++i) {
963 		NSLOG(netsurf, INFO, "%u %s", i, print_fonts_list[i]);
964 		error = xpdriver_declare_font(0, print_fonts_list[i],
965 				pdriver_KERNED);
966 		if (error) {
967 			NSLOG(netsurf, INFO,
968 			      "xpdriver_declare_font: 0x%x: %s",
969 			      error->errnum,
970 			      error->errmess);
971 			error_message = error->errmess;
972 			goto end;
973 		}
974 	}
975 	error = xpdriver_declare_font(0, 0, 0);
976 	if (error) {
977 		NSLOG(netsurf, INFO, "xpdriver_declare_font: 0x%x: %s",
978 		      error->errnum, error->errmess);
979 		error_message = error->errmess;
980 		goto end;
981 	}
982 
983 end:
984 	for (i = 0; i != print_fonts_count; i++)
985 		free(print_fonts_list[i]);
986 	free(print_fonts_list);
987 	print_fonts_list = 0;
988 
989 	return error_message;
990 }
991 
992 
993 /**
994  * Callback for print_fonts_plot_text().
995  *
996  * The font name is added to print_fonts_list.
997  */
998 
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)999 void print_fonts_callback(void *context,
1000 		const char *font_name, unsigned int font_size,
1001 		const char *s8, unsigned short *s16, unsigned int n,
1002 		int x, int y)
1003 {
1004 	unsigned int i;
1005 	char **fonts_list;
1006 
1007 	(void) context;  /* unused */
1008 	(void) font_size;  /* unused */
1009 	(void) x;  /* unused */
1010 	(void) y;  /* unused */
1011 
1012 	assert(s8 || s16);
1013 
1014 	/* check if the font name is new */
1015 	for (i = 0; i != print_fonts_count &&
1016 			strcmp(print_fonts_list[i], font_name) != 0; i++)
1017 		;
1018 	if (i != print_fonts_count)
1019 		return;
1020 
1021 	/* add to list of fonts */
1022 	fonts_list = realloc(print_fonts_list,
1023 			sizeof print_fonts_list[0] *
1024 			(print_fonts_count + 1));
1025 	if (!fonts_list) {
1026 		print_fonts_error = messages_get("NoMemory");
1027 		return;
1028 	}
1029 	fonts_list[print_fonts_count] = strdup(font_name);
1030 	if (!fonts_list[print_fonts_count]) {
1031 		print_fonts_error = messages_get("NoMemory");
1032 		return;
1033 	}
1034 	print_fonts_list = fonts_list;
1035 	print_fonts_count++;
1036 }
1037 
1038