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