summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
authorJohn Tytgat <joty@netsurf-browser.org>2008-08-14 20:32:10 +0000
committerJohn Tytgat <joty@netsurf-browser.org>2008-08-14 20:32:10 +0000
commite063a2a59d698dd96123b68a44b09f0623f80cab (patch)
tree1bd06130de988cb0f6da239800229387f189d21c /desktop
parent44856d86d4efb12e08c8ef7560f39233107dfa8a (diff)
downloadnetsurf-e063a2a59d698dd96123b68a44b09f0623f80cab.tar.gz
netsurf-e063a2a59d698dd96123b68a44b09f0623f80cab.tar.bz2
Second merge of Adam Blokus' GSoC work from his branch 'branches/adamblokus/netsurf'.
Merged revisions 4195-4211,4216,4219-4220,4222-4234,4236-4250,4252-4262,4264-4266,4268-4326,4329-4335,4338-4342,4344-4411,4413-4420,4422-4436,4438-4491,4494-4506,4508-4514,4516,4518-4552,4554,4556-4564,4567-4568,4570-4574,4576-4686,4689-4692,4694,4698-4709,4715-4723,4725-4755,4757-4769,4771-4919,4921-4996,4998-5110,5112-5117 via svnmerge from svn://svn.netsurf-browser.org/branches/adamblokus/netsurf ........ r4736 | adamblokus | 2008-07-26 13:46:54 +0200 (Sat, 26 Jul 2008) | 2 lines Sorting out some problems with svn. ........ r4737 | adamblokus | 2008-07-26 13:54:36 +0200 (Sat, 26 Jul 2008) | 4 lines Added export tab to the options dialog. Added the possibility of changing some print options. ........ r4897 | adamblokus | 2008-08-04 17:59:05 +0200 (Mon, 04 Aug 2008) | 5 lines Added checking of horizontal clipping. Added better table loosening. Changed some minor bugs. Applied changes in the Export options tab according to the review from tlsa. ........ r4905 | adamblokus | 2008-08-05 01:53:34 +0200 (Tue, 05 Aug 2008) | 2 lines Fixed bug which made it impossible to export pdf's. ........ r4919 | adamblokus | 2008-08-05 16:39:33 +0200 (Tue, 05 Aug 2008) | 2 lines Fixed some memory leaks which caused Netsurf to break. ........ r4927 | adamblokus | 2008-08-06 02:26:30 +0200 (Wed, 06 Aug 2008) | 4 lines Fixed bug with filenames which crashed Netsurf. Turned anti aliasing off for printing. Fixed some scaling issues. ........ r4928 | adamblokus | 2008-08-06 17:52:44 +0200 (Wed, 06 Aug 2008) | 5 lines Added new export/print options: - suppressing images - turning off backgrounds - toggled loosening ........ r4950 | adamblokus | 2008-08-07 21:15:21 +0200 (Thu, 07 Aug 2008) | 5 lines Added new options to PDF export: - document compression - document encryption Added PDF password dialog ........ r4954 | adamblokus | 2008-08-07 22:11:31 +0200 (Thu, 07 Aug 2008) | 2 lines Added saving print settings. ........ r4956 | adamblokus | 2008-08-07 22:44:48 +0200 (Thu, 07 Aug 2008) | 2 lines Fixes to PDF encryption ........ r4970 | adamblokus | 2008-08-09 15:26:24 +0200 (Sat, 09 Aug 2008) | 3 lines Fixed bug in plotting tiled bitmaps. Fixed bug with too long text decorations. ........ r4977 | adamblokus | 2008-08-09 19:18:56 +0200 (Sat, 09 Aug 2008) | 2 lines Fixed JPG embedding bug. ........ r4988 | adamblokus | 2008-08-10 16:59:51 +0200 (Sun, 10 Aug 2008) | 3 lines Added clip checking to pdf plotters. No more "blank" clips. Made PDF compression a default setting. ........ r4995 | adamblokus | 2008-08-10 20:03:00 +0200 (Sun, 10 Aug 2008) | 2 lines Fixed Haru crash on font-size==0. ........ r4996 | adamblokus | 2008-08-10 21:04:43 +0200 (Sun, 10 Aug 2008) | 2 lines Added changing text mode only if necessary. ........ r5045 | adamblokus | 2008-08-11 21:26:26 +0200 (Mon, 11 Aug 2008) | 3 lines Removing gtk stuff from core code. Little fix in options. ........ r5048 | adamblokus | 2008-08-11 21:57:45 +0200 (Mon, 11 Aug 2008) | 2 lines Better font size checking in PDF export. ........ r5050 | adamblokus | 2008-08-11 22:19:56 +0200 (Mon, 11 Aug 2008) | 2 lines Fixed riscos text scale bug. ........ r5073 | adamblokus | 2008-08-12 17:40:57 +0200 (Tue, 12 Aug 2008) | 2 lines Added missing tooltips ........ r5092 | adamblokus | 2008-08-13 17:09:25 +0200 (Wed, 13 Aug 2008) | 2 lines Moved /pdf folder to desktop/save_pdf ........ r5110 | adamblokus | 2008-08-13 22:44:50 +0200 (Wed, 13 Aug 2008) | 2 lines Added comments. ........ r5113 | adamblokus | 2008-08-13 23:07:35 +0200 (Wed, 13 Aug 2008) | 2 lines Cosmetic changes ........ r5116 | adamblokus | 2008-08-14 16:10:18 +0200 (Thu, 14 Aug 2008) | 2 lines Fixed bug with BOX_INLINE_END in tree duplication. ........ r5117 | joty | 2008-08-14 21:47:46 +0200 (Thu, 14 Aug 2008) | 1 line Improvement for r5116: use local vars when possible; rename global last to box_duplicate_last; check on box_duplicate_main_tree failure. ........ svn path=/trunk/netsurf/; revision=5118
Diffstat (limited to 'desktop')
-rw-r--r--desktop/options.c30
-rw-r--r--desktop/options.h19
-rw-r--r--desktop/print.c141
-rw-r--r--desktop/print.h23
-rw-r--r--desktop/save_pdf/TODO19
-rw-r--r--desktop/save_pdf/font_haru.c372
-rw-r--r--desktop/save_pdf/font_haru.h36
-rw-r--r--desktop/save_pdf/pdf_plotters.c831
-rw-r--r--desktop/save_pdf/pdf_plotters.h44
9 files changed, 1468 insertions, 47 deletions
diff --git a/desktop/options.c b/desktop/options.c
index c289cb0b6..197399aa1 100644
--- a/desktop/options.c
+++ b/desktop/options.c
@@ -139,6 +139,26 @@ unsigned int option_min_reflow_period = 100; /* time in cs */
#else
unsigned int option_min_reflow_period = 25; /* time in cs */
#endif
+/** top margin of exported page*/
+int option_margin_top = DEFAULT_MARGIN_TOP_MM;
+/** bottom margin of exported page*/
+int option_margin_bottom = DEFAULT_MARGIN_BOTTOM_MM;
+/** left margin of exported page*/
+int option_margin_left = DEFAULT_MARGIN_LEFT_MM;
+/** right margin of exported page*/
+int option_margin_right = DEFAULT_MARGIN_RIGHT_MM;
+/** scale of exported content*/
+int option_export_scale = DEFAULT_EXPORT_SCALE * 100;
+/**suppressing images in printed content*/
+bool option_suppress_images = false;
+/**turning off all backgrounds for printed content*/
+bool option_remove_backgrounds = false;
+/**turning on content loosening for printed content*/
+bool option_enable_loosening = true;
+/**compression of PDF documents*/
+bool option_enable_PDF_compression = true;
+/**setting a password and encoding PDF documents*/
+bool option_enable_PDF_password = false;
/* Fetcher configuration */
/** Maximum simultaneous active fetchers */
@@ -218,6 +238,16 @@ struct {
{ "suppress_curl_debug", OPTION_BOOL, &option_suppress_curl_debug },
{ "target_blank",
OPTION_BOOL, &option_target_blank },
+ { "margin_top", OPTION_INTEGER, &option_margin_top},
+ { "margin_bottom", OPTION_INTEGER, &option_margin_bottom},
+ { "margin_left", OPTION_INTEGER, &option_margin_left},
+ { "margin_right", OPTION_INTEGER, &option_margin_right},
+ { "export_scale", OPTION_INTEGER, &option_export_scale},
+ { "suppress_images", OPTION_BOOL, &option_suppress_images},
+ { "remove_backgrounds", OPTION_BOOL, &option_remove_backgrounds},
+ { "enable_loosening", OPTION_BOOL, &option_enable_loosening},
+ { "enable_PDF_compression", OPTION_BOOL, &option_enable_PDF_compression},
+ { "enable_PDF_password", OPTION_BOOL, &option_enable_PDF_password},
EXTRA_OPTION_TABLE
};
diff --git a/desktop/options.h b/desktop/options.h
index 89e99969b..cb238b93a 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -83,6 +83,25 @@ extern int option_scale;
extern bool option_incremental_reflow;
extern unsigned int option_min_reflow_period;
+extern int option_margin_top;
+extern int option_margin_bottom;
+extern int option_margin_left;
+extern int option_margin_right;
+extern int option_export_scale;
+extern bool option_suppress_images;
+extern bool option_remove_backgrounds;
+extern bool option_enable_loosening;
+extern bool option_enable_PDF_compression;
+extern bool option_enable_PDF_password;
+#define DEFAULT_PAGE_WIDTH 595
+#define DEFAULT_PAGE_HEIGHT 840
+#define DEFAULT_MARGIN_TOP_MM 10
+#define DEFAULT_MARGIN_BOTTOM_MM 10
+#define DEFAULT_MARGIN_LEFT_MM 10
+#define DEFAULT_MARGIN_RIGHT_MM 10
+#define DEFAULT_EXPORT_SCALE 0.7
+#define DEFAULT_COPIES 1
+
/* Fetcher configuration. */
extern int option_max_fetchers;
extern int option_max_fetchers_per_host;
diff --git a/desktop/print.c b/desktop/print.c
index 931dbe087..433a0bd89 100644
--- a/desktop/print.c
+++ b/desktop/print.c
@@ -23,31 +23,34 @@
#include "utils/config.h"
#ifdef WITH_PDF_EXPORT
+#include <string.h>
+
+#include "desktop/options.h"
#include "desktop/print.h"
#include "desktop/printer.h"
+#include "desktop/save_pdf/font_haru.h"
#include "content/content.h"
+#include "gtk/options.h"
+
#include "utils/log.h"
#include "utils/talloc.h"
#include "render/loosen.h"
#include "render/box.h"
-#include "pdf/font_haru.h"
-
static struct content *print_init(struct content *, struct print_settings *);
static bool print_apply_settings(struct content *, struct print_settings *);
-
-/*TODO: should these be passed as parameters in order to allow simultaneous
- printings?
-*/
static float page_content_width, page_content_height;
-static float text_margin_height;
static struct content *printed_content;
static float done_height;
+bool html_redraw_printing = false;
+int html_redraw_printing_border = 0;
+int html_redraw_printing_top_cropped = 0;
+
/**
* This function calls print setup, prints page after page until the whole
* content is printed calls cleaning up afterwise.
@@ -61,9 +64,9 @@ bool print_basic_run(struct content *content,
struct print_settings *settings)
{
bool ret = true;
-
+
if (settings == NULL)
- settings = print_make_settings(DEFAULT);
+ settings = print_make_settings(DEFAULT, NULL);
if (!print_set_up(content, printer, settings, NULL))
ret = false;
@@ -71,7 +74,7 @@ bool print_basic_run(struct content *content,
while (ret && (done_height < printed_content->height) )
ret = print_draw_next_page(printer, settings);
- print_cleanup(content, printer);
+ print_cleanup(content, printer, settings);
return ret;
}
@@ -115,11 +118,17 @@ bool print_set_up(struct content *content,
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings)
{
- /*TODO:Plotter will have to be duplicated and passed
- as an argument - to allow simultaneous screen and
- page plotting*/
+ int clip_x1, clip_y1;
+
plot = *(printer->plotter);
-
+ html_redraw_printing_top_cropped = INT_MAX;
+
+ clip_x1 = page_content_width * settings->scale;
+ clip_y1 = page_content_height * settings->scale;
+
+ html_redraw_printing = true;
+ html_redraw_printing_border = clip_y1;
+
printer->print_next_page();
if( !content_redraw(printed_content,
0,
@@ -127,11 +136,13 @@ bool print_draw_next_page(const struct printer *printer,
0,0,
0,
0,
- page_content_width * settings->scale,
- page_content_height * settings->scale,
+ clip_x1,
+ clip_y1,
settings->scale, 0xffffff))
return false;
- done_height += page_content_height - text_margin_height;
+ done_height += page_content_height -
+ (html_redraw_printing_top_cropped != INT_MAX ?
+ clip_y1 - html_redraw_printing_top_cropped : 0) / settings->scale;
return true;
}
@@ -194,9 +205,7 @@ bool print_apply_settings(struct content *content,
return false;
/*Apply settings - adjust page size etc*/
-
- text_margin_height = settings->margins[MARGINTEXT];
-
+
page_content_width = (settings->page_width - settings->margins[MARGINLEFT] -
settings->margins[MARGINRIGHT]) / settings->scale;
@@ -207,9 +216,10 @@ bool print_apply_settings(struct content *content,
LOG(("New layout applied.New height = %d ; New width = %d ",
content->height, content->width));
- if (content->width > page_content_width)
- return loosen_document_layout(content, content->data.html.layout,
- page_content_width, page_content_height);
+ /*check if loosening is necessary and requested*/
+ if (option_enable_loosening && content->width > page_content_width)
+ return loosen_document_layout(content, content->data.html.layout,
+ page_content_width, page_content_height);
return true;
}
@@ -221,10 +231,13 @@ bool print_apply_settings(struct content *content,
* \return true if successful, false otherwise
*/
bool print_cleanup(struct content *content,
- const struct printer *printer)
+ const struct printer *printer,
+ struct print_settings *settings)
{
printer->print_end();
+ html_redraw_printing = false;
+
if (printed_content) {
content_remove_user(printed_content, NULL, (intptr_t)print_init, 0);
talloc_free(printed_content);
@@ -232,50 +245,98 @@ bool print_cleanup(struct content *content,
content_remove_user(content, NULL, (intptr_t)print_init, 0);
+ free((void *)settings->output);
+ free(settings);
+
return true;
}
/**
* Generates one of the predefined print settings sets.
+ * \param configuration the requested configuration
+ * \param filename the filename or NULL
* \return print_settings in case if successful, NULL if unknown configuration \
* or lack of memory.
*/
-struct print_settings *print_make_settings(print_configuration configuration)
+struct print_settings *print_make_settings(print_configuration configuration,
+ const char *filename)
{
struct print_settings *settings;
+ char *path;
+ struct css_length length;
+
+ path = malloc(PATH_MAX * sizeof(char));
+ if (path == NULL)
+ return NULL;
+
+ length.unit = CSS_UNIT_MM;
switch (configuration){
case DEFAULT:
settings = (struct print_settings*)
- malloc(sizeof (struct print_settings) );
+ malloc(sizeof(struct print_settings) );
if (settings == NULL)
return NULL;
- settings->page_width = 595;
- settings->page_height = 840;
- settings->copies = 1;
- /*with 0.7 the pages look the best, the value in
- haru_nsfont_apply_style should be kept the same as this
- */
- settings->scale = 0.7;
+ settings->page_width = DEFAULT_PAGE_WIDTH;
+ settings->page_height = DEFAULT_PAGE_HEIGHT;
+ settings->copies = DEFAULT_COPIES;
+
+ settings->scale = DEFAULT_EXPORT_SCALE;
+
+ length.value = DEFAULT_MARGIN_LEFT_MM;
+ settings->margins[MARGINLEFT] = css_len2px(&length, 0);
+ length.value = DEFAULT_MARGIN_RIGHT_MM;
+ settings->margins[MARGINRIGHT] = css_len2px(&length, 0);
+ length.value = DEFAULT_MARGIN_TOP_MM;
+ settings->margins[MARGINTOP] = css_len2px(&length, 0);
+ length.value = DEFAULT_MARGIN_BOTTOM_MM;
+ settings->margins[MARGINBOTTOM] = css_len2px(&length, 0);
- settings->margins[MARGINLEFT] = 30;
- settings->margins[MARGINRIGHT] = 30;
- settings->margins[MARGINTOP] = 30;
- settings->margins[MARGINBOTTOM] = 30;
+ settings->font_func = &haru_nsfont;
- settings->margins[MARGINTEXT] = 10;
+ break;
+ /*use settings from the Export options tab*/
+ case OPTIONS:
+ settings = (struct print_settings*)
+ malloc(sizeof(struct print_settings) );
+
+ if (settings == NULL)
+ return NULL;
+
+ settings->page_width = DEFAULT_PAGE_WIDTH;
+ settings->page_height = DEFAULT_PAGE_HEIGHT;
+ settings->copies = DEFAULT_COPIES;
+
+ settings->scale = (float)option_export_scale / 100;
+
+ length.value = option_margin_left;
+ settings->margins[MARGINLEFT] = css_len2px(&length, 0);
+ length.value = option_margin_right;
+ settings->margins[MARGINRIGHT] = css_len2px(&length, 0);
+ length.value = option_margin_top;
+ settings->margins[MARGINTOP] = css_len2px(&length, 0);
+ length.value = option_margin_bottom;
+ settings->margins[MARGINBOTTOM] = css_len2px(&length, 0);
- settings->output = "out.pdf";
settings->font_func = &haru_nsfont;
break;
-
default:
return NULL;
}
+ /*if no filename is specified use one without an extension*/
+ if (filename == NULL) {
+ /*TODO: the "/" is not platform independent*/
+ strcpy(path, "/out");
+ }
+ else
+ strcpy(path, filename);
+
+ settings->output = path;
+
return settings;
}
diff --git a/desktop/print.h b/desktop/print.h
index dc4cde642..98f382eca 100644
--- a/desktop/print.h
+++ b/desktop/print.h
@@ -37,11 +37,10 @@
struct content;
struct printer;
-enum { MARGINLEFT = 0, MARGINRIGHT = 1, MARGINTOP = 2, MARGINBOTTOM = 3,
- MARGINTEXT = 4};
+enum { MARGINLEFT = 0, MARGINRIGHT = 1, MARGINTOP = 2, MARGINBOTTOM = 3};
/** Predefined printing configuration names*/
-typedef enum {DEFAULT} print_configuration;
+typedef enum {DEFAULT, OPTIONS} print_configuration;
/** Settings for a print - filled in by print_make_settings or
* 'manually' by the caller
@@ -49,7 +48,7 @@ typedef enum {DEFAULT} print_configuration;
struct print_settings{
/*Standard parameters*/
float page_width, page_height;
- float margins[5];
+ int margins[4];
float scale;
@@ -58,18 +57,28 @@ struct print_settings{
/*Output destinations - file/printer name*/
const char *output;
- /*TODO: more options?*/
+ /*the functions used to measure fonts*/
const struct font_functions *font_func;
};
+
bool print_basic_run(struct content *, const struct printer *, struct print_settings *);
bool print_set_up(struct content *content,
const struct printer *printer, struct print_settings *settings,
double *height);
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings);
-bool print_cleanup(struct content *, const struct printer *);
+bool print_cleanup(struct content *, const struct printer *,
+ struct print_settings *settings);
+
+struct print_settings *print_make_settings(print_configuration configuration,
+ const char *url);
-struct print_settings *print_make_settings(print_configuration configuration);
+/*is the content currently redrawn fo printing?*/
+extern bool html_redraw_printing;
+/*if something is partially under this Y coordinate it won't be drawn...*/
+extern int html_redraw_printing_border;
+/*...and the highest of the tops of all cropped elements will be remembered*/
+extern int html_redraw_printing_top_cropped;
#endif
diff --git a/desktop/save_pdf/TODO b/desktop/save_pdf/TODO
new file mode 100644
index 000000000..1b3a896b9
--- /dev/null
+++ b/desktop/save_pdf/TODO
@@ -0,0 +1,19 @@
+- finish all graphic primitives
+- allow adding raw bitmaps
+- make image-aware (embed the image in its native/original type if possible)
+
+- adjust content width to page width
+- divide output into multiple pages (not just the first one)
+- rearrange file structure
+
+- separate print-plotting as much as possible from window redrawing
+- add text-scaling (if not yet using the original font - make the default one
+ have the same width)
+- add a save file.. dialogue
+- add utf support to Haru ( doable? )
+- wait for browser to end fetching?
+- analyze and deal with performance issues(huge file hangs some pdf viewers,
+ for example kpdf when viewing plotted http://www.onet.pl)
+- deal with to wide pages - when window layouting adds a horizontal scrollbar,
+ we should treat it otherwise - either print horizontal or scale or,
+ better, find a new layout. \ No newline at end of file
diff --git a/desktop/save_pdf/font_haru.c b/desktop/save_pdf/font_haru.c
new file mode 100644
index 000000000..2e5f90adb
--- /dev/null
+++ b/desktop/save_pdf/font_haru.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * 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/>.
+ */
+
+ /** \file
+ * Font handling in Haru pdf documents (implementation).
+ *
+ * The functions were written to implement the same interface as the Pango ones
+ * so that the usage of the latter wouldn't have to be modified.
+ */
+
+#include "utils/config.h"
+#ifdef WITH_PDF_EXPORT
+
+/*#define FONT_HARU_DEBUG */
+
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <string.h>
+#include "hpdf.h"
+#include "css/css.h"
+#include "desktop/save_pdf/font_haru.h"
+#include "render/font.h"
+#include "utils/log.h"
+
+
+static bool haru_nsfont_init(HPDF_Doc *pdf, HPDF_Page *page,
+ const char *string, char **string_nt, int length);
+
+static bool haru_nsfont_width(const struct css_style *style,
+ const char *string, size_t length,
+ int *width);
+
+static bool haru_nsfont_position_in_string(const struct css_style *style,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x);
+
+static bool haru_nsfont_split(const struct css_style *style,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x);
+
+
+const struct font_functions haru_nsfont = {
+ haru_nsfont_width,
+ haru_nsfont_position_in_string,
+ haru_nsfont_split
+};
+
+/**
+ * Haru error handler
+ * for debugging purposes - it immediately exits the program on the first error,
+ * as it would otherwise flood the user with all resulting complications,
+ * covering the most important error source.
+ */
+static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
+ void *user_data)
+{
+ LOG(("ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n",
+ (HPDF_UINT)error_no, (HPDF_UINT)detail_no));
+#ifdef FONT_HARU_DEBUG
+ exit(1);
+#endif
+}
+
+static bool haru_nsfont_init(HPDF_Doc *pdf, HPDF_Page *page,
+ const char *string, char **string_nt, int length)
+{
+
+ *pdf = HPDF_New(error_handler, NULL);
+
+ if (*pdf == NULL)
+ return false;
+
+ *page = HPDF_AddPage(*pdf);
+
+ if (*page == NULL) {
+ HPDF_Free(*pdf);
+ return false;
+ }
+
+ *string_nt = malloc((length + 1) * sizeof(char));
+ if (*string_nt == NULL) {
+ HPDF_Free(*pdf);
+ return false;
+ }
+
+ memcpy(*string_nt, string, length);
+ (*string_nt)[length] = '\0';
+ return true;
+}
+
+/**
+ * Measure the width of a string.
+ *
+ * \param style css_style for this text, with style->font_size.size ==
+ * CSS_FONT_SIZE_LENGTH
+ * \param string string to measure (no UTF-8 currently)
+ * \param length length of string
+ * \param width updated to width of string[0..length]
+ * \return true on success, false on error and error reported
+ */
+bool haru_nsfont_width(const struct css_style *style,
+ const char *string, size_t length,
+ int *width)
+{
+ HPDF_Doc pdf;
+ HPDF_Page page;
+ char *string_nt;
+ HPDF_REAL width_real;
+
+ *width = 0;
+
+ if (length == 0) {
+ return true;
+ }
+
+ if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
+ return false;
+
+ if (!haru_nsfont_apply_style(style, pdf, page, NULL)) {
+ free(string_nt);
+ HPDF_Free(pdf);
+ return false;
+ }
+
+ width_real = HPDF_Page_TextWidth(page, string_nt);
+ *width = width_real;
+
+#ifdef FONT_HARU_DEBUG
+ LOG(("Measuring string: %s ; Calculated width: %f %i",string_nt, width_real, *width));
+#endif
+ free(string_nt);
+ HPDF_Free(pdf);
+
+
+ return true;
+}
+
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param style css_style for this text, with style->font_size.size ==
+ * CSS_FONT_SIZE_LENGTH
+ * \param string string to measure (no UTF-8 currently)
+ * \param length length of string
+ * \param x x coordinate to search for
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ */
+
+bool haru_nsfont_position_in_string(const struct css_style *style,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ HPDF_Doc pdf;
+ HPDF_Page page;
+ char *string_nt;
+ HPDF_UINT offset;
+ HPDF_REAL real_width;
+
+ if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
+ return false;
+
+ if (HPDF_Page_SetWidth(page, x) != HPDF_OK
+ || !haru_nsfont_apply_style(style, pdf, page, NULL)) {
+ free(string_nt);
+ HPDF_Free(pdf);
+ return false;
+ }
+
+
+ offset = HPDF_Page_MeasureText(page, string_nt, x,
+ HPDF_FALSE, &real_width);
+
+
+ if (real_width < x)
+ *char_offset = offset;
+ else {
+ assert(fabs(real_width - x) < FLT_EPSILON);
+ assert(offset > 0);
+ *char_offset = offset - 1;
+ }
+
+ /*TODO: this is only the right edge of the character*/
+ *actual_x = real_width;
+
+#ifdef FONT_HARU_DEBUG
+ LOG(("Position in string: %s at x: %i; Calculated position: %i",
+ string_nt, x, *char_offset));
+#endif
+ free(string_nt);
+ HPDF_Free(pdf);
+
+ return true;
+}
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param style css_style for this text, with style->font_size.size ==
+ * CSS_FONT_SIZE_LENGTH
+ * \param string string to measure (no UTF-8 currently)
+ * \param length length of string
+ * \param x width available
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ */
+
+bool haru_nsfont_split(const struct css_style *style,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ HPDF_Doc pdf;
+ HPDF_Page page;
+ char *string_nt;
+ HPDF_REAL real_width;
+ HPDF_UINT offset;
+
+
+ if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
+ return false;
+
+ if (HPDF_Page_SetWidth(page, x) != HPDF_OK
+ || !haru_nsfont_apply_style(style, pdf, page, NULL)) {
+ free(string_nt);
+ HPDF_Free(pdf);
+ return false;
+ }
+
+ offset = HPDF_Page_MeasureText(page, string_nt, x,
+ HPDF_TRUE, &real_width);
+
+#ifdef FONT_HARU_DEBUG
+ LOG(("Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f",
+ string_nt, x, *char_offset, real_width));
+#endif
+ *char_offset = offset - 1;
+
+ /*TODO: this is only the right edge of the character*/
+ *actual_x = real_width;
+
+ free(string_nt);
+ HPDF_Free(pdf);
+
+ return true;
+}
+
+/**
+ * Apply css_style to a Haru HPDF_Page
+ *
+ * \param style css_style for this page, with style->font_size.size ==
+ * CSS_FONT_SIZE_LENGTH
+ * \param doc document owning the page
+ * \param page the page to apply the style to
+ * \param font if this is not NULL it is updated to the font from the
+ * style and nothing with the page is done
+ * \return true on success, false on error and error reported
+ */
+bool haru_nsfont_apply_style(const struct css_style *style,
+ HPDF_Doc doc, HPDF_Page page, HPDF_Font *font)
+{
+ HPDF_Font pdf_font;
+ HPDF_REAL size;
+ char font_name[50];
+ bool roman;
+ bool bold;
+ bool styled;
+
+ roman = false;
+ bold = false;
+ styled = false;
+
+
+ /*TODO: style handling, we are mapping the
+ styles on the basic 14 fonts only
+ */
+ switch (style->font_family) {
+ case CSS_FONT_FAMILY_SERIF:
+ strcpy(font_name, "Times");
+ roman = true;
+ break;
+ case CSS_FONT_FAMILY_MONOSPACE:
+ strcpy(font_name, "Courier");
+ break;
+ case CSS_FONT_FAMILY_SANS_SERIF:
+ strcpy(font_name, "Helvetica");
+ break;
+ case CSS_FONT_FAMILY_CURSIVE:
+ case CSS_FONT_FAMILY_FANTASY:
+ default:
+ strcpy(font_name, "Times");
+ roman=true;
+ break;
+ }
+
+ if (style->font_weight == CSS_FONT_WEIGHT_BOLD){
+ strcat(font_name, "-Bold");
+ bold = true;
+ }
+
+ switch (style->font_style) {
+ case CSS_FONT_STYLE_ITALIC:
+ case CSS_FONT_STYLE_OBLIQUE:
+ if (!bold)
+ strcat(font_name,"-");
+ if (roman)
+ strcat(font_name,"Italic");
+ else
+ strcat(font_name,"Oblique");
+
+ styled = true;
+ break;
+ default:
+ break;
+ }
+
+ if (roman && !styled && !bold)
+ strcat(font_name, "-Roman");
+
+#ifdef FONT_HARU_DEBUG
+ LOG(("Setting font: %s", font_name));
+#endif
+
+ /*the functions was invoked only to get the proper font*/
+ if (font != NULL) {
+ pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding");
+ if (pdf_font == NULL)
+ return false;
+ *font = pdf_font;
+ }
+ /*the function was invoked to set the page parameters*/
+ else {
+ if (style->font_size.value.length.unit == CSS_UNIT_PX)
+ size = style->font_size.value.length.value;
+ else
+ size = css_len2pt(&style->font_size.value.length, style);
+
+ if (size <= 0)
+ return false;
+
+ if (size > HPDF_MAX_FONTSIZE)
+ size = HPDF_MAX_FONTSIZE;
+
+ pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding");
+ if (pdf_font == NULL)
+ return false;
+ HPDF_Page_SetFontAndSize(page, pdf_font, size);
+ }
+
+ return true;
+}
+
+#endif /* WITH_PDF_EXPORT */
+
diff --git a/desktop/save_pdf/font_haru.h b/desktop/save_pdf/font_haru.h
new file mode 100644
index 000000000..eca9855e6
--- /dev/null
+++ b/desktop/save_pdf/font_haru.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * 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/>.
+ */
+
+ /** \file
+ * Font handling in Haru pdf documents (interface).
+ */
+
+#ifndef _NETSURF_RENDER_FONT_HARU_H_
+#define _NETSURF_RENDER_FONT_HARU_H_
+
+#include "render/font.h"
+#include "hpdf.h"
+
+bool haru_nsfont_apply_style(const struct css_style *style,
+ HPDF_Doc doc, HPDF_Page page,
+ HPDF_Font *font);
+
+extern const struct font_functions haru_nsfont;
+extern float pdf_scale;
+
+#endif
diff --git a/desktop/save_pdf/pdf_plotters.c b/desktop/save_pdf/pdf_plotters.c
new file mode 100644
index 000000000..10ddc10bf
--- /dev/null
+++ b/desktop/save_pdf/pdf_plotters.c
@@ -0,0 +1,831 @@
+/*
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * 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/>.
+ */
+
+ /** \file
+ * Target independent PDF plotting using Haru Free PDF Library.
+ */
+
+#include "utils/config.h"
+#ifdef WITH_PDF_EXPORT
+
+#include <stdlib.h>
+#include <string.h>
+#include "hpdf.h"
+
+#include "desktop/options.h"
+#include "desktop/plotters.h"
+#include "desktop/print.h"
+#include "desktop/printer.h"
+#include "desktop/save_pdf/pdf_plotters.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "image/bitmap.h"
+
+#include "font_haru.h"
+
+#define R(x) (( (x) & 0x0000ff )/256.0)
+#define G(x) ((( (x) & 0x00ff00)>>8 )/256.0)
+#define B(x) ((( (x) & 0xff0000)>>16)/256.0)
+
+/*#define PDF_DEBUG*/
+
+static bool pdf_plot_clg(colour c);
+static bool pdf_plot_rectangle(int x0, int y0, int width, int height,
+ int line_width, colour c, bool dotted, bool dashed);
+static bool pdf_plot_line(int x0, int y0, int x1, int y1, int width,
+ colour c, bool dotted, bool dashed);
+static bool pdf_plot_polygon(int *p, unsigned int n, colour fill);
+static bool pdf_plot_fill(int x0, int y0, int x1, int y1, colour c);
+static bool pdf_plot_clip(int clip_x0, int clip_y0,
+ int clip_x1, int clip_y1);
+static bool pdf_plot_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c);
+static bool pdf_plot_disc(int x, int y, int radius, colour c, bool filled);
+static bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2,
+ colour c);
+static bool pdf_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg, struct content *content);
+static bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bool repeat_x, bool repeat_y, struct content *content);
+static bool pdf_plot_path(float *p, unsigned int n, colour fill, float width,
+ colour c, float *transform);
+
+static void pdf_set_solid(void);
+static void pdf_set_dashed(void);
+static void pdf_set_dotted(void);
+
+static HPDF_Image pdf_extract_image(struct bitmap *bitmap, struct content *content);
+static void apply_clip_and_mode(void);
+
+
+static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
+ void *user_data);
+
+#ifdef PDF_DEBUG
+static void pdf_plot_grid(int x_dist,int y_dist,unsigned int colour);
+#endif
+
+/*PDF Plotter - current doc,page and font*/
+static HPDF_Doc pdf_doc;
+static HPDF_Page pdf_page;
+static HPDF_Font pdf_font;
+
+/*PDF Page size*/
+static HPDF_REAL page_height, page_width;
+
+/*Remeber if pdf_plot_clip was invoked for current page*/
+static bool page_clipped;
+int last_clip_x0, last_clip_y0, last_clip_x1, last_clip_y1;
+
+bool in_text_mode, text_mode_request;
+
+static struct print_settings* settings;
+
+static const struct plotter_table pdf_plotters = {
+ pdf_plot_clg,
+ pdf_plot_rectangle,
+ pdf_plot_line,
+ pdf_plot_polygon,
+ pdf_plot_fill,
+ pdf_plot_clip,
+ pdf_plot_text,
+ pdf_plot_disc,
+ pdf_plot_arc,
+ pdf_plot_bitmap,
+ pdf_plot_bitmap_tile,
+ NULL,
+ NULL,
+ NULL,
+ pdf_plot_path,
+ false
+};
+
+struct printer pdf_printer= {
+ &pdf_plotters,
+ pdf_begin,
+ pdf_next_page,
+ pdf_end
+};
+
+float pdf_scale;
+static char *owner_pass;
+static char *user_pass;
+
+bool pdf_plot_clg(colour c)
+{
+ return true;
+}
+
+bool pdf_plot_rectangle(int x0, int y0, int width, int height,
+ int line_width, colour c, bool dotted, bool dashed)
+{
+#ifdef PDF_DEBUG
+ LOG(("."));
+#endif
+ apply_clip_and_mode();
+
+ HPDF_Page_SetLineWidth(pdf_page, line_width);
+
+ if (dotted)
+ pdf_set_dotted();
+ else if (dashed)
+ pdf_set_dashed();
+
+ HPDF_Page_SetRGBStroke(pdf_page, R(c), G(c), B(c));
+ HPDF_Page_Rectangle(pdf_page, x0, page_height - y0 + height, width, height);
+ HPDF_Page_Stroke(pdf_page);
+
+ if (dotted||dashed)
+ pdf_set_solid();
+
+ return true;
+}
+
+bool pdf_plot_line(int x0, int y0, int x1, int y1, int width,
+ colour c, bool dotted, bool dashed)
+{
+#ifdef PDF_DEBUG
+ LOG(("."));
+#endif
+
+ apply_clip_and_mode();
+
+ HPDF_Page_SetLineWidth(pdf_page, width);
+
+ if (dotted)
+ pdf_set_dotted();
+ else if (dashed)
+ pdf_set_dashed();
+
+ HPDF_Page_SetRGBStroke(pdf_page, R(c), G(c), B(c));
+ HPDF_Page_SetLineWidth(pdf_page, width);
+ HPDF_Page_MoveTo(pdf_page, x0, page_height - y0);
+ HPDF_Page_LineTo(pdf_page, x1, page_height - y1);
+ HPDF_Page_Stroke(pdf_page);
+
+ if (dotted||dashed)
+ pdf_set_solid();
+
+ return true;
+}
+
+bool pdf_plot_polygon(int *p, unsigned int n, colour fill)
+{
+ int i;
+#ifdef PDF_DEBUG
+ int pmaxx = p[0], pmaxy = p[1];
+ int pminx = p[0], pminy = p[1];
+ LOG(("."));
+#endif
+ if (n == 0)
+ return true;
+
+ apply_clip_and_mode();
+
+ HPDF_Page_SetRGBFill(pdf_page, R(fill), G(fill), B(fill));
+ HPDF_Page_MoveTo(pdf_page, p[0], page_height - p[1]);
+
+ for (i = 1 ; i<n ; i++) {
+ HPDF_Page_LineTo(pdf_page, p[i*2], page_height - p[i*2+1]);
+#ifdef PDF_DEBUG
+ pmaxx = max(pmaxx, p[i*2]);
+ pmaxy = max(pmaxy, p[i*2+1]);
+ pminx = min(pminx, p[i*2]);
+ pminy = min(pminy, p[i*2+1]);
+#endif
+ }
+
+#ifdef PDF_DEBUG
+ LOG(("%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy, page_height-pminy));
+#endif
+
+ HPDF_Page_LineTo(pdf_page, p[0], page_height - p[1]);
+ HPDF_Page_Fill(pdf_page);
+
+ return true;
+}
+
+bool pdf_plot_fill(int x0, int y0, int x1, int y1, colour c)
+{
+#ifdef PDF_DEBUG
+ LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height-y0, c));
+#endif
+
+ /*Normalize boundaries of the area - to prevent overflows.
+ It is needed only in a few functions, where integers are subtracted.
+ When the whole browser window is meant min and max int values are used
+ what must be handled in paged output.
+ */
+ x0 = min(max(x0, 0), page_width);
+ y0 = min(max(y0, 0), page_height);
+ x1 = min(max(x1, 0), page_width);
+ y1 = min(max(y1, 0), page_height);
+
+ apply_clip_and_mode();
+
+ HPDF_Page_SetRGBFill(pdf_page, R(c), G(c), B(c));
+ HPDF_Page_Rectangle(pdf_page, x0, page_height - y1, x1-x0, y1-y0);
+ HPDF_Page_Fill(pdf_page);
+
+ return true;
+}
+
+/**here the clip is only queried */
+bool pdf_plot_clip(int clip_x0, int clip_y0, int clip_x1, int clip_y1)
+{
+#ifdef PDF_DEBUG
+ LOG(("%d %d %d %d", clip_x0, clip_y0, clip_x1, clip_y1));
+#endif
+
+ /*Normalize cllipping area - to prevent overflows.
+ See comment in pdf_plot_fill.
+ */
+ last_clip_x0 = min(max(clip_x0, 0), page_width);
+ last_clip_y0 = min(max(clip_y0, 0), page_height);
+ last_clip_x1 = min(max(clip_x1, 0), page_width);
+ last_clip_y1 = min(max(clip_y1, 0), page_height);
+
+ page_clipped = true;
+
+ return true;
+}
+
+bool pdf_plot_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+#ifdef PDF_DEBUG
+ LOG((". %d %d %s", x, y, text));
+#endif
+ char *word;
+ HPDF_REAL size;
+ float text_bottom_position, descent;
+
+ if (length == 0)
+ return true;
+
+ text_mode_request = true;
+ apply_clip_and_mode();
+
+ if (style->font_size.value.length.unit == CSS_UNIT_PX)
+ size = style->font_size.value.length.value;
+ else
+ size = css_len2pt(&style->font_size.value.length, style);
+
+ /*this can be removed when export options get added for riscos*/
+#ifdef riscos
+ size *= DEFAULT_EXPORT_SCALE;
+#else
+ size *= pdf_scale;
+#endif
+
+ if (size <= 0)
+ return true;
+
+ if (size > HPDF_MAX_FONTSIZE)
+ size = HPDF_MAX_FONTSIZE;
+
+ haru_nsfont_apply_style(style, pdf_doc, pdf_page, &pdf_font);
+
+ descent = size * (HPDF_Font_GetDescent(pdf_font) / 1000.0);
+ text_bottom_position = page_height - y + descent;
+
+ word = (char*) malloc( sizeof(char) * (length+1) );
+ if (word == NULL)
+ return false;
+
+ memcpy(word, text, length);
+ word[length] = '\0';
+
+ HPDF_Page_SetRGBFill(pdf_page, R(c), G(c), B(c));
+
+ HPDF_Page_SetFontAndSize (pdf_page, pdf_font, size);
+ HPDF_Page_TextOut (pdf_page, x, page_height - y, word);
+
+ free(word);
+
+ return true;
+}
+
+bool pdf_plot_disc(int x, int y, int radius, colour c, bool filled)
+{
+#ifdef PDF_DEBUG
+ LOG(("."));
+#endif
+ apply_clip_and_mode();
+
+ if (filled)
+ HPDF_Page_SetRGBFill(pdf_page, R(c), G(c), B(c));
+ else
+ HPDF_Page_SetRGBStroke(pdf_page, R(c), G(c), B(c));
+
+ HPDF_Page_Circle(pdf_page, x, page_height-y, radius);
+
+ if (filled)
+ HPDF_Page_Fill(pdf_page);
+ else
+ HPDF_Page_Stroke(pdf_page);
+
+ return true;
+}
+
+bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, colour c)
+{
+#ifdef PDF_DEBUG
+ LOG(("%d %d %d %d %d %X", x, y, radius, angle1, angle2, c));
+#endif
+
+ /*Normalize angles*/
+ angle1 %= 360;
+ angle2 %= 360;
+ if (angle1 > angle2)
+ angle1 -= 360;
+
+ apply_clip_and_mode();
+
+ HPDF_Page_SetRGBStroke(pdf_page, R(c), G(c), B(c));
+
+ HPDF_Page_Arc(pdf_page, x, page_height-y, radius, angle1, angle2);
+
+ HPDF_Page_Stroke(pdf_page);
+ return true;
+}
+
+bool pdf_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg, struct content *content)
+{
+ HPDF_Image image;
+
+#ifdef PDF_DEBUG
+ LOG(("%d %d %d %d %X %X %X", x, y, width, height,
+ bitmap, bg, content));
+#endif
+ if (width == 0 || height == 0)
+ return true;
+
+ apply_clip_and_mode();
+
+ image = pdf_extract_image(bitmap, content);
+
+ if (!image)
+ return false;
+
+ HPDF_Page_DrawImage(pdf_page, image,
+ x, page_height-y-height,
+ width, height);
+ return true;
+
+
+}
+
+bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bool repeat_x, bool repeat_y, struct content *content)
+{
+ HPDF_Image image;
+
+#ifdef PDF_DEBUG
+ LOG(("%d %d %d %d %X %X %X", x, y, width, height,
+ bitmap, bg, content));
+#endif
+ if (width == 0 || height == 0)
+ return true;
+
+ apply_clip_and_mode();
+
+ image = pdf_extract_image(bitmap, content);
+
+ if (image) {
+ /*The position of the next tile*/
+ HPDF_REAL current_x, current_y ;
+ HPDF_REAL max_width, max_height;
+
+ max_width = (repeat_x ? page_width : width);
+ max_height = (repeat_y ? page_height: height);
+
+
+ for (current_y=0; current_y < max_height; current_y += height)
+ for (current_x=0; current_x < max_width; current_x += width)
+ HPDF_Page_DrawImage(pdf_page, image,
+ current_x + x,
+ page_height-current_y - y - height,
+ width, height);
+
+ return true;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+HPDF_Image pdf_extract_image(struct bitmap *bitmap, struct content *content)
+{
+ HPDF_Image image = NULL,smask;
+ char *img_buffer, *rgb_buffer, *alpha_buffer;
+ int img_width, img_height, img_rowstride;
+ int i, j;
+
+ if (content) {
+ /*Not sure if I don't have to check if downloading has been
+ finished.
+ Other way - lock pdf plotting while fetching a website
+ */
+ switch(content->type){
+ /*Handle "embeddable" types of images*/
+ case CONTENT_JPEG:
+ image = HPDF_LoadJpegImageFromMem(pdf_doc,
+ content->source_data,
+ content->source_size);
+ break;
+
+ /*Disabled until HARU PNG support will be more stable.
+
+ case CONTENT_PNG:
+ image = HPDF_LoadPngImageFromMem(pdf_doc,
+ content->source_data,
+ content->total_size);
+ break;*/
+ default:
+ break;
+ }
+ }
+
+ if (!image) {
+ /*Handle pixmaps*/
+ img_buffer = bitmap_get_buffer(bitmap);
+ img_width = bitmap_get_width(bitmap);
+ img_height = bitmap_get_height(bitmap);
+ img_rowstride = bitmap_get_rowstride(bitmap);
+
+ rgb_buffer = (char*)malloc(3 * img_width * img_height);
+ if (rgb_buffer == NULL) {
+ LOG(("Not enough memory to create RGB buffer"));
+ return NULL;
+ }
+
+ alpha_buffer = (char*)malloc(img_width * img_height);
+ if (alpha_buffer == NULL) {
+ LOG(("Not enough memory to create alpha buffer"));
+ free(rgb_buffer);
+ return NULL;
+ }
+
+
+ for (i = 0; i<img_height; i++)
+ for (j = 0 ; j<img_width ; j++) {
+ rgb_buffer[((i * img_width) + j) * 3] =
+ img_buffer[(i * img_rowstride) + (j * 4)];
+
+ rgb_buffer[(((i * img_width) + j) * 3) + 1] =
+ img_buffer[(i * img_rowstride) + (j * 4) + 1];
+
+ rgb_buffer[(((i * img_width) + j) * 3) + 2] =
+ img_buffer[(i * img_rowstride) + (j * 4) + 2];
+
+ alpha_buffer[(i * img_width)+j] =
+ img_buffer[(i * img_rowstride) + (j * 4) + 3];
+ }
+
+ smask = HPDF_LoadRawImageFromMem(pdf_doc, alpha_buffer,
+ img_width, img_height,
+ HPDF_CS_DEVICE_GRAY, 8);
+
+ image = HPDF_LoadRawImageFromMem(pdf_doc, rgb_buffer,
+ img_width, img_height,
+ HPDF_CS_DEVICE_RGB, 8);
+
+ if (HPDF_Image_AddSMask(pdf_doc, image,smask) != HPDF_OK)
+ image = NULL;
+
+ free(rgb_buffer);
+ free(alpha_buffer);
+ }
+
+ return image;
+}
+/**change the mode and clip only if it's necessary*/
+static void apply_clip_and_mode()
+{
+
+ if (in_text_mode && (!text_mode_request || page_clipped)) {
+ HPDF_Page_EndText(pdf_page);
+ in_text_mode = false;
+ }
+
+ if (page_clipped) {
+
+ HPDF_Page_GRestore(pdf_page);
+ HPDF_Page_GSave(pdf_page);
+
+ HPDF_Page_Rectangle(pdf_page, last_clip_x0,
+ page_height - last_clip_y1,
+ last_clip_x1 - last_clip_x0,
+ last_clip_y1 - last_clip_y0);
+ HPDF_Page_Clip(pdf_page);
+ HPDF_Page_EndPath(pdf_page);
+
+ page_clipped = false;
+ }
+
+ if (text_mode_request) {
+ if (!in_text_mode) {
+ HPDF_Page_BeginText(pdf_page);
+ in_text_mode = true;
+ }
+
+ text_mode_request = false;
+ }
+}
+
+static inline float transform_x(float *transform, float x, float y)
+{
+ return ((transform[0] * x) + (transform[2] * (-y) ) + transform[4]) * 2;
+}
+
+static inline float transform_y(float *transform, float x, float y)
+{
+ return page_height - (((transform[1] * x) +
+ (transform[3] * (-y)) - transform[5]) * 2);
+}
+
+bool pdf_plot_path(float *p, unsigned int n, colour fill, float width,
+ colour c, float *transform)
+{
+#ifdef PDF_DEBUG
+ LOG(("."));
+#endif
+ unsigned int i;
+ bool empty_path = true;
+
+ if (n == 0)
+ return true;
+
+ if ((c == TRANSPARENT) && (fill == TRANSPARENT))
+ return true;
+
+ if (p[0] != PLOTTER_PATH_MOVE) {
+ return false;
+ }
+
+ HPDF_Page_SetRGBFill(pdf_page, R(fill), G(fill), B(fill));
+ HPDF_Page_SetRGBStroke(pdf_page, R(c), G(c), B(c));
+
+ transform[0] = 0.1;
+ transform[1] = 0;
+ transform[2] = 0;
+ transform[3] = -0.1;
+ transform[4] = 0;
+ transform[5] = 0;
+
+ for (i = 0 ; i<n ; ) {
+ if (p[i] == PLOTTER_PATH_MOVE) {
+ HPDF_Page_MoveTo(pdf_page,
+ transform_x(transform, p[i+1], p[i+2]),
+ transform_y(transform, p[i+1], p[i+2]));
+ i+= 3;
+ } else if (p[i] == PLOTTER_PATH_CLOSE) {
+ if (!empty_path)
+ HPDF_Page_ClosePath(pdf_page);
+ i++;
+ } else if (p[i] == PLOTTER_PATH_LINE) {
+ HPDF_Page_LineTo(pdf_page,
+ transform_x(transform, p[i+1], p[i+2]),
+ transform_y(transform, p[i+1], p[i+2]));
+ i+=3;
+ empty_path = false;
+ } else if (p[i] == PLOTTER_PATH_BEZIER) {
+ HPDF_Page_CurveTo(pdf_page,
+ transform_x(transform, p[i+1], p[i+2]),
+ transform_y(transform, p[i+1], p[i+2]),
+ transform_x(transform, p[i+3], p[i+4]),
+ transform_y(transform, p[i+3], p[i+4]),
+ transform_x(transform, p[i+5], p[i+6]),
+ transform_y(transform, p[i+5], p[i+6]));
+ i += 7;
+ empty_path = false;
+ } else {
+ LOG(("bad path command %f", p[i]));
+ return false;
+ }
+ }
+
+ if (empty_path) {
+ HPDF_Page_EndPath(pdf_page);
+ return true;
+ }
+
+ if (fill!=TRANSPARENT) {
+ if (c != TRANSPARENT)
+ HPDF_Page_FillStroke(pdf_page);
+ else
+ HPDF_Page_Fill(pdf_page);
+ }
+ else
+ HPDF_Page_Stroke(pdf_page);
+
+ return true;
+}
+
+void pdf_set_solid()
+{
+ HPDF_Page_SetDash(pdf_page, NULL, 0, 0);
+}
+
+void pdf_set_dashed()
+{
+ HPDF_UINT16 dash_ptn[] = {3};
+ HPDF_Page_SetDash(pdf_page, dash_ptn, 1, 1);
+}
+
+void pdf_set_dotted()
+{
+ HPDF_UINT16 dash_ptn[] = {1};
+ HPDF_Page_SetDash(pdf_page, dash_ptn, 1, 1);
+}
+
+/**
+ * Begin pdf plotting - initialize a new document
+ * \param path Output file path
+ * \param pg_width page width
+ * \param pg_height page height
+ */
+bool pdf_begin(struct print_settings *print_settings)
+{
+ pdf_doc = NULL;
+
+ pdf_doc = HPDF_New(error_handler, NULL);
+ if (!pdf_doc) {
+ LOG(("Error creating pdf_doc"));
+ return false;
+ }
+
+ settings = print_settings;
+
+ page_width = settings->page_width - settings->margins[MARGINLEFT] -
+ settings->margins[MARGINRIGHT];
+
+ page_height = settings->page_height - settings->margins[MARGINTOP];
+
+
+ if (option_enable_PDF_compression)
+ HPDF_SetCompressionMode(pdf_doc, HPDF_COMP_ALL); /*Compression on*/
+
+ pdf_font = HPDF_GetFont (pdf_doc, "Times-Roman", "StandardEncoding");
+
+ pdf_page = NULL;
+
+#ifdef PDF_DEBUG
+ LOG(("pdf_begin finishes"));
+#endif
+ return true;
+}
+
+
+bool pdf_next_page(void)
+{
+#ifdef PDF_DEBUG
+ if (pdf_page != NULL) {
+ HPDF_Page_GRestore(pdf_page);
+ if (page_clipped)
+ HPDF_Page_GRestore(pdf_page);
+ pdf_plot_grid(10, 10, 0xCCCCCC);
+ pdf_plot_grid(100, 100, 0xCCCCFF);
+ }
+#endif
+ pdf_page = HPDF_AddPage(pdf_doc);
+ if (pdf_page == NULL)
+ return false;
+
+ HPDF_Page_SetWidth (pdf_page, settings->page_width);
+ HPDF_Page_SetHeight(pdf_page, settings->page_height);
+
+ HPDF_Page_Concat(pdf_page,1,0,0,1,settings->margins[MARGINLEFT],0);
+
+ page_clipped = false;
+ HPDF_Page_GSave(pdf_page);
+
+ text_mode_request = false;
+ in_text_mode = false;
+
+#ifdef PDF_DEBUG
+ LOG(("%f %f", page_width, page_height));
+#endif
+
+ return true;
+}
+
+
+void pdf_end(void)
+{
+ char *path;
+#ifdef PDF_DEBUG
+ LOG(("pdf_end begins"));
+ if (pdf_page != NULL) {
+ HPDF_Page_GRestore(pdf_page);
+ if (page_clipped)
+ HPDF_Page_GRestore(pdf_page);
+ pdf_plot_grid(10, 10, 0xCCCCCC);
+ pdf_plot_grid(100, 100, 0xCCCCFF);
+ }
+#endif
+
+ if (settings->output != NULL)
+ path = strdup(settings->output);
+ else
+ path = NULL;
+
+ /*Encryption on*/
+ if (option_enable_PDF_password)
+ PDF_Password(&owner_pass, &user_pass, path);
+ else
+ save_pdf(path);
+#ifdef PDF_DEBUG
+ LOG(("pdf_end finishes"));
+#endif
+}
+/** saves the pdf optionally encrypting it before*/
+void save_pdf(char *path)
+{
+ bool success = false;
+
+ if (option_enable_PDF_password && owner_pass != NULL ) {
+ HPDF_SetPassword(pdf_doc, owner_pass, user_pass);
+ HPDF_SetEncryptionMode(pdf_doc, HPDF_ENCRYPT_R3, 16);
+ free(owner_pass);
+ free(user_pass);
+ }
+
+ if (path != NULL) {
+ if (HPDF_SaveToFile(pdf_doc, path) != HPDF_OK)
+ remove(path);
+ else
+ success = true;
+
+ free(path);
+ }
+
+ if (!success)
+ warn_user("Unable to save PDF file.", 0);
+
+ HPDF_Free(pdf_doc);
+}
+
+
+/**
+ * Haru error handler
+ * for debugging purposes - it immediately exits the program on the first error,
+ * as it would otherwise flood the user with all resulting complications,
+ * covering the most important error source.
+*/
+static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
+ void *user_data)
+{
+ LOG(("ERROR:\n\terror_no=%x\n\tdetail_no=%d\n", (HPDF_UINT)error_no,
+ (HPDF_UINT)detail_no));
+#ifdef PDF_DEBUG
+ exit(1);
+#endif
+}
+
+/**
+ * This function plots a grid - used for debug purposes to check if all
+ * elements' final coordinates are correct.
+*/
+#ifdef PDF_DEBUG
+void pdf_plot_grid(int x_dist, int y_dist, unsigned int colour)
+{
+ int i;
+
+ for (int i = x_dist ; i < page_width ; i += x_dist)
+ pdf_plot_line(i, 0, i, page_height, 1, colour, false, false);
+
+ for (int i = y_dist ; i < page_height ; i += x_dist)
+ pdf_plot_line(0, i, page_width, i, 1, colour, false, false);
+
+}
+#endif
+
+/**used to synch the text scale with the scale for the whole content*/
+void pdf_set_scale(float s)
+{
+ pdf_scale = s;
+}
+
+#endif /* WITH_PDF_EXPORT */
+
diff --git a/desktop/save_pdf/pdf_plotters.h b/desktop/save_pdf/pdf_plotters.h
new file mode 100644
index 000000000..ba815c552
--- /dev/null
+++ b/desktop/save_pdf/pdf_plotters.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * 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/>.
+ */
+
+/** \file
+ PDF Plotting
+*/
+
+#ifndef NETSURF_PDF_PLOTTERS_H
+#define NETSURF_PDF_PLOTTERS_H
+
+#include "desktop/print.h"
+struct plotter_table;
+
+extern struct printer pdf_printer;
+
+/**Start plotting a pdf file*/
+bool pdf_begin(struct print_settings* settings);
+
+/**Finish the current page and start a new one*/
+bool pdf_next_page(void);
+
+/**Close pdf document and save changes to file*/
+void pdf_end(void);
+
+void pdf_set_scale(float s);
+
+void save_pdf(char *path);
+
+#endif /*NETSURF_PDF_PLOTTERS_H*/