From d204d6d555ac8e79da330a93e96fb070c8ee8f8c Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 26 Oct 2014 23:49:18 +0000 Subject: Clean up saving as PDF This removes the global PDF_Password interface that had completely bitrotted and moves it into the standard misc operation table with a sensible defualt implementation. This also cleans up and fixes the gtk frontend implementation of the pdf password callback so it compiles. Finally this moves the implementation to a sensible place alongside the other exporters reducing target makefile complexity futher. --- Makefile | 3 - amiga/Makefile.target | 2 +- amiga/save_pdf.c | 5 - cocoa/utils.m | 9 - desktop/Makefile | 4 +- desktop/font_haru.c | 375 +++++++++++++++ desktop/font_haru.h | 40 ++ desktop/gui_factory.c | 22 +- desktop/gui_misc.h | 10 + desktop/save_pdf.c | 990 ++++++++++++++++++++++++++++++++++++++++ desktop/save_pdf.h | 41 ++ desktop/save_pdf/Makefile | 6 - desktop/save_pdf/TODO | 19 - desktop/save_pdf/font_haru.c | 376 --------------- desktop/save_pdf/font_haru.h | 40 -- desktop/save_pdf/pdf_plotters.c | 963 -------------------------------------- desktop/save_pdf/pdf_plotters.h | 41 -- gtk/Makefile.target | 2 +- gtk/gui.c | 119 ++--- riscos/Makefile.target | 2 +- riscos/gui.c | 7 - utils/utils.h | 1 - 22 files changed, 1545 insertions(+), 1532 deletions(-) create mode 100644 desktop/font_haru.c create mode 100644 desktop/font_haru.h create mode 100644 desktop/save_pdf.c create mode 100644 desktop/save_pdf.h delete mode 100644 desktop/save_pdf/Makefile delete mode 100644 desktop/save_pdf/TODO delete mode 100644 desktop/save_pdf/font_haru.c delete mode 100644 desktop/save_pdf/font_haru.h delete mode 100644 desktop/save_pdf/pdf_plotters.c delete mode 100644 desktop/save_pdf/pdf_plotters.h diff --git a/Makefile b/Makefile index 4fe22e2a3..08766089f 100644 --- a/Makefile +++ b/Makefile @@ -571,9 +571,6 @@ include javascript/Makefile # Image content handler sources include image/Makefile -# PDF saving sources -include desktop/save_pdf/Makefile - # S_COMMON are sources common to all builds S_COMMON := $(S_CONTENT) $(S_FETCHERS) $(S_CSS) $(S_RENDER) $(S_UTILS) \ $(S_HTTP) $(S_DESKTOP) $(S_JAVASCRIPT) diff --git a/amiga/Makefile.target b/amiga/Makefile.target index ea765af36..8939dbc83 100644 --- a/amiga/Makefile.target +++ b/amiga/Makefile.target @@ -78,7 +78,7 @@ S_AMIGA := $(addprefix amiga/,$(S_AMIGA)) # This is the final source build list # Note this is deliberately *not* expanded here as common and image # are not yet available -SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_AMIGA) $(S_PDF) +SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_AMIGA) # ---------------------------------------------------------------------------- # Install target diff --git a/amiga/save_pdf.c b/amiga/save_pdf.c index 16592215b..b70fc5716 100644 --- a/amiga/save_pdf.c +++ b/amiga/save_pdf.c @@ -56,9 +56,4 @@ bool save_as_pdf(struct hlcache_handle *c, const char *path) return true; } -void PDF_Password(char **owner_pass, char **user_pass, char *path) -{ - /*TODO:this waits to be written, until then no PDF encryption*/ - *owner_pass = NULL; -} #endif diff --git a/cocoa/utils.m b/cocoa/utils.m index b49e503d0..2c73e9b49 100644 --- a/cocoa/utils.m +++ b/cocoa/utils.m @@ -20,9 +20,6 @@ #import "utils/utils.h" -#define UNIMPL() NSLog( @"Function '%s' unimplemented", __func__ ) - - void warn_user(const char *warning, const char *detail) { NSRunAlertPanel( NSLocalizedString( @"Warning", @"Warning title" ), @@ -31,9 +28,3 @@ void warn_user(const char *warning, const char *detail) warning, detail != NULL ? ": " : "", detail != NULL ? detail : "" ); } - -void PDF_Password(char **owner_pass, char **user_pass, char *path) -{ - UNIMPL(); -} - diff --git a/desktop/Makefile b/desktop/Makefile index 218f60e67..894b51861 100644 --- a/desktop/Makefile +++ b/desktop/Makefile @@ -13,7 +13,7 @@ desktop/version.c: testament $(OBJROOT)/testament.h # S_BROWSER are sources related to full browsers but are common # between RISC OS, GTK, BeOS and AmigaOS builds S_BROWSER := browser.c browser_history.c download.c frames.c netsurf.c \ - save_complete.c save_text.c selection.c textinput.c gui_factory.c + save_complete.c save_text.c selection.c textinput.c gui_factory.c \ + save_pdf.c font_haru.c S_BROWSER := $(addprefix desktop/,$(S_BROWSER)) - diff --git a/desktop/font_haru.c b/desktop/font_haru.c new file mode 100644 index 000000000..aaee84c35 --- /dev/null +++ b/desktop/font_haru.c @@ -0,0 +1,375 @@ +/* + * Copyright 2008 Adam Blokus + * Copyright 2009 John Tytgat + * + * 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 . + */ + + /** \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 +#include +#include +#include + +#include + +#include "css/css.h" +#include "css/utils.h" + +#include "utils/nsoption.h" +#include "desktop/save_pdf/font_haru.h" +#include "desktop/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 plot_font_style_t *fstyle, + const char *string, size_t length, + int *width); + +static bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle, + const char *string, size_t length, + int x, size_t *char_offset, int *actual_x); + +static bool haru_nsfont_split(const plot_font_style_t *fstyle, + const char *string, size_t length, + int x, size_t *char_offset, int *actual_x); + +static float pdf_text_scale = DEFAULT_EXPORT_SCALE; + +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 fstyle style for this text + * \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 plot_font_style_t *fstyle, + 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(fstyle, pdf, page, NULL, 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 fstyle style for this text + * \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 plot_font_style_t *fstyle, + 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(fstyle, pdf, page, NULL, 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 fstyle style for this text + * \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 plot_font_style_t *fstyle, + 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(fstyle, pdf, page, NULL, 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 font style to a Haru HPDF_Page + * + * \param fstyle plot style for this page + * \param doc document owning the page + * \param page the page to apply the style to + * \param font if this is non NULL it is updated to the font based + * on given style + * \param font_size if this is non NULL it is updated to the font size + * based on given style + * \return true on success, false on error and error reported + * + * When both font and font_size are NULL, the HPDF_Page is updated for given + * style, otherwise it is left to the called to do this. + */ +bool haru_nsfont_apply_style(const plot_font_style_t *fstyle, + HPDF_Doc doc, HPDF_Page page, + HPDF_Font *font, HPDF_REAL *font_size) +{ + HPDF_Font pdf_font; + HPDF_REAL size; + char font_name[50]; + bool roman = false; + bool bold = false; + bool styled = false; + + /*TODO: style handling, we are mapping the + styles on the basic 14 fonts only + */ + switch (fstyle->family) { + case PLOT_FONT_FAMILY_SERIF: + strcpy(font_name, "Times"); + roman = true; + break; + case PLOT_FONT_FAMILY_MONOSPACE: + strcpy(font_name, "Courier"); + break; + case PLOT_FONT_FAMILY_SANS_SERIF: + strcpy(font_name, "Helvetica"); + break; + case PLOT_FONT_FAMILY_CURSIVE: + case PLOT_FONT_FAMILY_FANTASY: + default: + strcpy(font_name, "Times"); + roman=true; + break; + } + + if (fstyle->weight == 700) { + strcat(font_name, "-Bold"); + bold = true; + } + + if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE)) { + if (!bold) + strcat(font_name,"-"); + if (roman) + strcat(font_name,"Italic"); + else + strcat(font_name,"Oblique"); + + styled = true; + } + + if (roman && !styled && !bold) + strcat(font_name, "-Roman"); + +#ifdef FONT_HARU_DEBUG + LOG(("Setting font: %s", font_name)); +#endif + + size = fstyle->size; + + if (font != NULL) + size *= pdf_text_scale; + + if (size <= 0) + return true; + + size /= FONT_SIZE_SCALE; + + if (size > HPDF_MAX_FONTSIZE) + size = HPDF_MAX_FONTSIZE; + + if (font_size) + *font_size = size; + + pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding"); + if (pdf_font == NULL) + return false; + if (font != NULL) + *font = pdf_font; + + if (font == NULL || font_size == NULL) + HPDF_Page_SetFontAndSize(page, pdf_font, size); + + return true; +} + +/** + * Sync the text scale with the scale for the whole content + */ +void haru_nsfont_set_scale(float s) +{ + pdf_text_scale = s; +} + +#endif /* WITH_PDF_EXPORT */ diff --git a/desktop/font_haru.h b/desktop/font_haru.h new file mode 100644 index 000000000..479f7deb0 --- /dev/null +++ b/desktop/font_haru.h @@ -0,0 +1,40 @@ +/* + * Copyright 2008 Adam Blokus + * Copyright 2009 John Tytgat + * + * 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 . + */ + + /** \file + * Font handling in Haru pdf documents (interface). + */ + +#ifndef _NETSURF_DESKTOP_FONT_HARU_H_ +#define _NETSURF_DESKTOP_FONT_HARU_H_ + +#include + +#include "desktop/plot_style.h" +#include "desktop/font.h" + +bool haru_nsfont_apply_style(const plot_font_style_t *fstyle, + HPDF_Doc doc, HPDF_Page page, + HPDF_Font *font, HPDF_REAL *font_size); + +void haru_nsfont_set_scale(float s); + +extern const struct font_functions haru_nsfont; + +#endif diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c index e7770e770..b69700fca 100644 --- a/desktop/gui_factory.c +++ b/desktop/gui_factory.c @@ -20,6 +20,7 @@ #include "content/backing_store.h" #include "utils/file.h" +#include "desktop/save_pdf.h" #include "desktop/download.h" #include "desktop/searchweb.h" #include "desktop/gui_download.h" @@ -259,6 +260,12 @@ static void gui_default_download_done(struct gui_download_window *dw) { } +static struct gui_download_table default_download_table = { + .create = gui_default_download_create, + .data = gui_default_download_data, + .error = gui_default_download_error, + .done = gui_default_download_done, +}; /** verify download window table is valid */ static nserror verify_download_register(struct gui_download_table *gdt) @@ -566,12 +573,12 @@ static void gui_default_401login_open(nsurl *url, const char *realm, cb(false, cbpw); } -static struct gui_download_table default_download_table = { - .create = gui_default_download_create, - .data = gui_default_download_data, - .error = gui_default_download_error, - .done = gui_default_download_done, -}; +static void +gui_default_pdf_password(char **owner_pass, char **user_pass, char *path) +{ + *owner_pass = NULL; + save_pdf(path); +} /** verify browser table is valid */ static nserror verify_browser_register(struct gui_browser_table *gbt) @@ -599,6 +606,9 @@ static nserror verify_browser_register(struct gui_browser_table *gbt) if (gbt->login == NULL) { gbt->login = gui_default_401login_open; } + if (gbt->pdf_password == NULL) { + gbt->pdf_password = gui_default_pdf_password; + } return NSERROR_OK; } diff --git a/desktop/gui_misc.h b/desktop/gui_misc.h index daad6ba2e..8005006c7 100644 --- a/desktop/gui_misc.h +++ b/desktop/gui_misc.h @@ -80,6 +80,16 @@ struct gui_browser_table { void (*login)(struct nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw); + /** + * Warn the user of an event. + */ + void (*warning)(const char *warning, const char *detail); + + /** + * Prompt the user for a password for a PDF. + */ + void (*pdf_password)(char **owner_pass, char **user_pass, char *path); + }; #endif diff --git a/desktop/save_pdf.c b/desktop/save_pdf.c new file mode 100644 index 000000000..e3f9cbc34 --- /dev/null +++ b/desktop/save_pdf.c @@ -0,0 +1,990 @@ +/* + * Copyright 2008 Adam Blokus + * Copyright 2009 John Tytgat + * + * 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 . + */ + + /** \file + * Target independent PDF plotting using Haru Free PDF Library. + */ + +/* TODO + * - 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. + */ + +#include "utils/config.h" + +#include "desktop/save_pdf.h" + +#ifdef WITH_PDF_EXPORT + +#include +#include +#include + +#include + +#include "content/hlcache.h" +#include "utils/nsoption.h" +#include "desktop/plotters.h" +#include "desktop/print.h" +#include "desktop/printer.h" +#include "image/bitmap.h" +#include "utils/log.h" +#include "utils/utils.h" +#include "utils/useragent.h" + +#include "font_haru.h" + +/* #define PDF_DEBUG */ +/* #define PDF_DEBUG_DUMPGRID */ + +static bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style); +static bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle); +static bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style); +static bool pdf_plot_clip(const struct rect *clip); +static bool pdf_plot_text(int x, int y, const char *text, size_t length, + const plot_font_style_t *fstyle); +static bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style); +static bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, + const plot_style_t *style); +static bool pdf_plot_bitmap_tile(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bitmap_flags_t flags); +static bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width, + colour c, const float transform[6]); + +static HPDF_Image pdf_extract_image(struct bitmap *bitmap); + +static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, + void *user_data); + +#ifdef PDF_DEBUG_DUMPGRID +static void pdf_plot_grid(int x_dist,int y_dist,unsigned int colour); +#endif + +typedef enum { + DashPattern_eNone, + DashPattern_eDash, + DashPattern_eDotted +} DashPattern_e; + +/* Wrapper routines to minimize gstate updates in the produced PDF file. */ +static void pdfw_gs_init(void); +static void pdfw_gs_save(HPDF_Page page); +static void pdfw_gs_restore(HPDF_Page page); +static void pdfw_gs_fillcolour(HPDF_Page page, colour col); +static void pdfw_gs_strokecolour(HPDF_Page page, colour col); +static void pdfw_gs_linewidth(HPDF_Page page, float lineWidth); +static void pdfw_gs_font(HPDF_Page page, HPDF_Font font, HPDF_REAL font_size); +static void pdfw_gs_dash(HPDF_Page page, DashPattern_e dash); + +/** + * Our PDF gstate mirror which we use to minimize gstate updates + * in the PDF file. + */ +typedef struct { + colour fillColour; /**< Current fill colour. */ + colour strokeColour; /**< Current stroke colour. */ + float lineWidth; /**< Current line width. */ + HPDF_Font font; /**< Current font. */ + HPDF_REAL font_size; /**< Current font size. */ + DashPattern_e dash; /**< Current dash state. */ +} PDFW_GState; + +static void apply_clip_and_mode(bool selectTextMode, colour fillCol, + colour strokeCol, float lineWidth, DashPattern_e dash); + +#define PDFW_MAX_GSTATES 4 +static PDFW_GState pdfw_gs[PDFW_MAX_GSTATES]; +static unsigned int pdfw_gs_level; + +static HPDF_Doc pdf_doc; /**< Current PDF document. */ +static HPDF_Page pdf_page; /**< Current page. */ + +/*PDF Page size*/ +static HPDF_REAL page_height, page_width; + +static bool in_text_mode; /**< true if we're currently in text mode or not. */ +static bool clip_update_needed; /**< true if pdf_plot_clip was invoked for + current page and not yet synced with PDF output. */ +static int last_clip_x0, last_clip_y0, last_clip_x1, last_clip_y1; + +static const struct print_settings *settings; + +static const struct plotter_table pdf_plotters = { + .rectangle = pdf_plot_rectangle, + .line = pdf_plot_line, + .polygon = pdf_plot_polygon, + .clip = pdf_plot_clip, + .text = pdf_plot_text, + .disc = pdf_plot_disc, + .arc = pdf_plot_arc, + .bitmap = pdf_plot_bitmap_tile, + .path = pdf_plot_path, + .option_knockout = false, +}; + +const struct printer pdf_printer = { + &pdf_plotters, + pdf_begin, + pdf_next_page, + pdf_end +}; + +static char *owner_pass; +static char *user_pass; + +bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle) +{ + DashPattern_e dash; +#ifdef PDF_DEBUG + LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, pstyle->fill_colour)); +#endif + + if (pstyle->fill_type != PLOT_OP_TYPE_NONE) { + + apply_clip_and_mode(false, pstyle->fill_colour, NS_TRANSPARENT, 0., DashPattern_eNone); + + /* 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); + + HPDF_Page_Rectangle(pdf_page, x0, page_height - y1, x1 - x0, y1 - y0); + HPDF_Page_Fill(pdf_page); + + } + + if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) { + + switch (pstyle->stroke_type) { + case PLOT_OP_TYPE_DOT: + dash = DashPattern_eDotted; + break; + + case PLOT_OP_TYPE_DASH: + dash = DashPattern_eDash; + break; + + default: + dash = DashPattern_eNone; + break; + + } + + apply_clip_and_mode(false, + NS_TRANSPARENT, + pstyle->stroke_colour, + pstyle->stroke_width, + dash); + + HPDF_Page_Rectangle(pdf_page, x0, page_height - y0, x1 - x0, -(y1 - y0)); + HPDF_Page_Stroke(pdf_page); + } + + return true; +} + +bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle) +{ + DashPattern_e dash; + + switch (pstyle->stroke_type) { + case PLOT_OP_TYPE_DOT: + dash = DashPattern_eDotted; + break; + + case PLOT_OP_TYPE_DASH: + dash = DashPattern_eDash; + break; + + default: + dash = DashPattern_eNone; + break; + + } + + apply_clip_and_mode(false, + NS_TRANSPARENT, + pstyle->stroke_colour, + pstyle->stroke_width, + dash); + + HPDF_Page_MoveTo(pdf_page, x0, page_height - y0); + HPDF_Page_LineTo(pdf_page, x1, page_height - y1); + HPDF_Page_Stroke(pdf_page); + + return true; +} + +bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) +{ + unsigned 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(false, style->fill_colour, NS_TRANSPARENT, 0., DashPattern_eNone); + + HPDF_Page_MoveTo(pdf_page, p[0], page_height - p[1]); + for (i = 1 ; ix0, 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); + + clip_update_needed = true; + + return true; +} + +bool pdf_plot_text(int x, int y, const char *text, size_t length, + const plot_font_style_t *fstyle) +{ +#ifdef PDF_DEBUG + LOG((". %d %d %.*s", x, y, (int)length, text)); +#endif + char *word; + HPDF_Font pdf_font; + HPDF_REAL size; + + if (length == 0) + return true; + + apply_clip_and_mode(true, fstyle->foreground, NS_TRANSPARENT, 0., + DashPattern_eNone); + + haru_nsfont_apply_style(fstyle, pdf_doc, pdf_page, &pdf_font, &size); + pdfw_gs_font(pdf_page, pdf_font, size); + + /* FIXME: UTF-8 to current font encoding needs to done. Or the font + * encoding needs to be UTF-8 or other Unicode encoding. */ + word = (char *)malloc( sizeof(char) * (length+1) ); + if (word == NULL) + return false; + memcpy(word, text, length); + word[length] = '\0'; + + HPDF_Page_TextOut (pdf_page, x, page_height - y, word); + + free(word); + + return true; +} + +bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style) +{ +#ifdef PDF_DEBUG + LOG((".")); +#endif + if (style->fill_type != PLOT_OP_TYPE_NONE) { + apply_clip_and_mode(false, + style->fill_colour, + NS_TRANSPARENT, + 1., DashPattern_eNone); + + HPDF_Page_Circle(pdf_page, x, page_height - y, radius); + + HPDF_Page_Fill(pdf_page); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + /* FIXME: line width 1 is ok ? */ + apply_clip_and_mode(false, + NS_TRANSPARENT, + style->stroke_colour, + 1., DashPattern_eNone); + + HPDF_Page_Circle(pdf_page, x, page_height - y, radius); + + HPDF_Page_Stroke(pdf_page); + } + + return true; +} + +bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) +{ +#ifdef PDF_DEBUG + LOG(("%d %d %d %d %d %X", x, y, radius, angle1, angle2, style->stroke_colour)); +#endif + + /* FIXME: line width 1 is ok ? */ + apply_clip_and_mode(false, NS_TRANSPARENT, style->fill_colour, 1., DashPattern_eNone); + + /* Normalize angles */ + angle1 %= 360; + angle2 %= 360; + if (angle1 > angle2) + angle1 -= 360; + + HPDF_Page_Arc(pdf_page, x, page_height - y, radius, angle1, angle2); + + HPDF_Page_Stroke(pdf_page); + return true; +} + + +bool pdf_plot_bitmap_tile(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bitmap_flags_t flags) +{ + HPDF_Image image; + HPDF_REAL current_x, current_y ; + HPDF_REAL max_width, max_height; + +#ifdef PDF_DEBUG + LOG(("%d %d %d %d %p 0x%x", x, y, width, height, + bitmap, bg)); +#endif + if (width == 0 || height == 0) + return true; + + apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., DashPattern_eNone); + + image = pdf_extract_image(bitmap); + if (!image) + return false; + + /*The position of the next tile*/ + max_width = (flags & BITMAPF_REPEAT_X) ? page_width : width; + max_height = (flags & BITMAPF_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; +} + +HPDF_Image pdf_extract_image(struct bitmap *bitmap) +{ + HPDF_Image image = NULL; + hlcache_handle *content = NULL; + + /* TODO - get content from bitmap pointer */ + + if (content) { + const char *source_data; + unsigned long source_size; + + /*Not sure if I don't have to check if downloading has been + finished. + Other way - lock pdf plotting while fetching a website + */ + source_data = content_get_source_data(content, &source_size); + + switch(content_get_type(content)){ + /*Handle "embeddable" types of images*/ + case CONTENT_JPEG: + image = HPDF_LoadJpegImageFromMem(pdf_doc, + (const HPDF_BYTE *) source_data, + source_size); + break; + + /*Disabled until HARU PNG support will be more stable. + + case CONTENT_PNG: + image = HPDF_LoadPngImageFromMem(pdf_doc, + (const HPDF_BYTE *)content->source_data, + content->total_size); + break;*/ + default: + break; + } + } + + if (!image) { + HPDF_Image smask; + unsigned char *img_buffer, *rgb_buffer, *alpha_buffer; + int img_width, img_height, img_rowstride; + int i, j; + + /*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 = (unsigned char *)malloc(3 * img_width * img_height); + alpha_buffer = (unsigned char *)malloc(img_width * img_height); + if (rgb_buffer == NULL || alpha_buffer == NULL) { + LOG(("Not enough memory to create RGB buffer")); + free(rgb_buffer); + free(alpha_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(image, smask) != HPDF_OK) + image = NULL; + + free(rgb_buffer); + free(alpha_buffer); + } + + return image; +} + +/** + * Enter/leave text mode and update PDF gstate for its clip, fill & stroke + * colour, line width and dash pattern parameters. + * \param selectTextMode true if text mode needs to be entered if required; + * false otherwise. + * \param fillCol Desired fill colour, use NS_TRANSPARENT if no update is + * required. + * \param strokeCol Desired stroke colour, use NS_TRANSPARENT if no update is + * required. + * \param lineWidth Desired line width. Only taken into account when strokeCol + * is different from NS_TRANSPARENT. + * \param dash Desired dash pattern. Only taken into account when strokeCol + * is different from NS_TRANSPARENT. + */ +static void apply_clip_and_mode(bool selectTextMode, colour fillCol, + colour strokeCol, float lineWidth, DashPattern_e dash) +{ + /* Leave text mode when + * 1) we're not setting text anymore + * 2) or we need to update the current clippath + * 3) or we need to update any fill/stroke colour, linewidth or dash. + * Note: the test on stroke parameters (stroke colour, line width and + * dash) is commented out as if these need updating we want to be + * outside the text mode anyway (i.e. selectTextMode is false). + */ + if (in_text_mode && (!selectTextMode || clip_update_needed + || (fillCol != NS_TRANSPARENT + && fillCol != pdfw_gs[pdfw_gs_level].fillColour) + /* || (strokeCol != NS_TRANSPARENT + && (strokeCol != pdfw_gs[pdfw_gs_level].strokeColour + || lineWidth != pdfw_gs[pdfw_gs_level].lineWidth + || dash != pdfw_gs[pdfw_gs_level].dash)) */)) { + HPDF_Page_EndText(pdf_page); + in_text_mode = false; + } + + if (clip_update_needed) + pdfw_gs_restore(pdf_page); + + /* Update fill/stroke colour, linewidth and dash when needed. */ + if (fillCol != NS_TRANSPARENT) + pdfw_gs_fillcolour(pdf_page, fillCol); + if (strokeCol != NS_TRANSPARENT) { + pdfw_gs_strokecolour(pdf_page, strokeCol); + pdfw_gs_linewidth(pdf_page, lineWidth); + pdfw_gs_dash(pdf_page, dash); + } + + if (clip_update_needed) { + pdfw_gs_save(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); + + clip_update_needed = false; + } + + if (selectTextMode && !in_text_mode) { + HPDF_Page_BeginText(pdf_page); + in_text_mode = true; + } +} + +static inline float transform_x(const float transform[6], float x, float y) +{ + return transform[0] * x + transform[2] * y + transform[4]; +} + +static inline float transform_y(const float transform[6], float x, float y) +{ + return page_height + - (transform[1] * x + transform[3] * y + transform[5]); +} + +bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width, + colour c, const float transform[6]) +{ + unsigned int i; + bool empty_path; + +#ifdef PDF_DEBUG + LOG((".")); +#endif + + if (n == 0) + return true; + + if (c == NS_TRANSPARENT && fill == NS_TRANSPARENT) + return true; + + if (p[0] != PLOTTER_PATH_MOVE) + return false; + + apply_clip_and_mode(false, fill, c, width, DashPattern_eNone); + + empty_path = true; + 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 != NS_TRANSPARENT) { + if (c != NS_TRANSPARENT) + HPDF_Page_FillStroke(pdf_page); + else + HPDF_Page_Fill(pdf_page); + } + else + HPDF_Page_Stroke(pdf_page); + + return true; +} + +/** + * 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) +{ + pdfw_gs_init(); + + if (pdf_doc != NULL) + HPDF_Free(pdf_doc); + 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 - + FIXTOFLT(FSUB(settings->margins[MARGINLEFT], + settings->margins[MARGINRIGHT])); + + page_height = settings->page_height - + FIXTOFLT(settings->margins[MARGINTOP]); + + +#ifndef PDF_DEBUG + if (option_enable_PDF_compression) + HPDF_SetCompressionMode(pdf_doc, HPDF_COMP_ALL); /*Compression on*/ +#endif + HPDF_SetInfoAttr(pdf_doc, HPDF_INFO_CREATOR, user_agent_string()); + + pdf_page = NULL; + +#ifdef PDF_DEBUG + LOG(("pdf_begin finishes")); +#endif + return true; +} + + +bool pdf_next_page(void) +{ +#ifdef PDF_DEBUG + LOG(("pdf_next_page begins")); +#endif + clip_update_needed = false; + if (pdf_page != NULL) { + apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., + DashPattern_eNone); + pdfw_gs_restore(pdf_page); + } + +#ifdef PDF_DEBUG_DUMPGRID + if (pdf_page != NULL) { + 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, + FIXTOFLT(settings->margins[MARGINLEFT]), 0); + + pdfw_gs_save(pdf_page); + +#ifdef PDF_DEBUG + LOG(("%f %f", page_width, page_height)); +#endif + + return true; +} + + +void pdf_end(void) +{ +#ifdef PDF_DEBUG + LOG(("pdf_end begins")); +#endif + clip_update_needed = false; + if (pdf_page != NULL) { + apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., + DashPattern_eNone); + pdfw_gs_restore(pdf_page); + } + +#ifdef PDF_DEBUG_DUMPGRID + if (pdf_page != NULL) { + pdf_plot_grid(10, 10, 0xCCCCCC); + pdf_plot_grid(100, 100, 0xCCCCFF); + } +#endif + + assert(settings->output != NULL); + + /*Encryption on*/ + if (option_enable_PDF_password) + guit->browser->pdf_password(&owner_pass, &user_pass, + (void *)settings->output); + else + save_pdf(settings->output); +#ifdef PDF_DEBUG + LOG(("pdf_end finishes")); +#endif +} + +/** saves the pdf with optional encryption */ +void save_pdf(const 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; + } + + if (!success) + warn_user("Unable to save PDF file.", 0); + + HPDF_Free(pdf_doc); + pdf_doc = NULL; +} + + +/** + * 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_DUMPGRID +void pdf_plot_grid(int x_dist, int y_dist, unsigned int colour) +{ + 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 + +/** + * Initialize the gstate wrapper code. + */ +void pdfw_gs_init() +{ + pdfw_gs_level = 0; + pdfw_gs[0].fillColour = 0x00000000; /* Default PDF fill colour is black. */ + pdfw_gs[0].strokeColour = 0x00000000; /* Default PDF stroke colour is black. */ + pdfw_gs[0].lineWidth = 1.0; /* Default PDF line width is 1. */ + pdfw_gs[0].font = NULL; + pdfw_gs[0].font_size = 0.; + pdfw_gs[0].dash = DashPattern_eNone; /* Default dash state is a solid line. */ +} + +/** + * Increase gstate level. + * \param page PDF page where the update needs to happen. + */ +void pdfw_gs_save(HPDF_Page page) +{ + if (pdfw_gs_level == PDFW_MAX_GSTATES) + abort(); + pdfw_gs[pdfw_gs_level + 1] = pdfw_gs[pdfw_gs_level]; + ++pdfw_gs_level; + HPDF_Page_GSave(page); +} + +/** + * Decrease gstate level and restore the gstate to its value at last save + * operation. + * \param page PDF page where the update needs to happen. + */ +void pdfw_gs_restore(HPDF_Page page) +{ + if (pdfw_gs_level == 0) + abort(); + --pdfw_gs_level; + HPDF_Page_GRestore(page); +} + +#define RBYTE(x) (((x) & 0x0000FF) >> 0) +#define GBYTE(x) (((x) & 0x00FF00) >> 8) +#define BBYTE(x) (((x) & 0xFF0000) >> 16) +#define R(x) (RBYTE(x) / 255.) +#define G(x) (GBYTE(x) / 255.) +#define B(x) (BBYTE(x) / 255.) + +/** + * Checks if given fill colour is already set in PDF gstate and if not, + * update the gstate accordingly. + * \param page PDF page where the update needs to happen. + * \param col Wanted fill colour. + */ +void pdfw_gs_fillcolour(HPDF_Page page, colour col) +{ + if (col == pdfw_gs[pdfw_gs_level].fillColour) + return; + pdfw_gs[pdfw_gs_level].fillColour = col; + if (RBYTE(col) == GBYTE(col) && GBYTE(col) == BBYTE(col)) + HPDF_Page_SetGrayFill(pdf_page, R(col)); + else + HPDF_Page_SetRGBFill(pdf_page, R(col), G(col), B(col)); +} + +/** + * Checks if given stroke colour is already set in PDF gstate and if not, + * update the gstate accordingly. + * \param page PDF page where the update needs to happen. + * \param col Wanted stroke colour. + */ +void pdfw_gs_strokecolour(HPDF_Page page, colour col) +{ + if (col == pdfw_gs[pdfw_gs_level].strokeColour) + return; + pdfw_gs[pdfw_gs_level].strokeColour = col; + if (RBYTE(col) == GBYTE(col) && GBYTE(col) == BBYTE(col)) + HPDF_Page_SetGrayStroke(pdf_page, R(col)); + else + HPDF_Page_SetRGBStroke(pdf_page, R(col), G(col), B(col)); +} + +/** + * Checks if given line width is already set in PDF gstate and if not, update + * the gstate accordingly. + * \param page PDF page where the update needs to happen. + * \param lineWidth Wanted line width. + */ +void pdfw_gs_linewidth(HPDF_Page page, float lineWidth) +{ + if (lineWidth == pdfw_gs[pdfw_gs_level].lineWidth) + return; + pdfw_gs[pdfw_gs_level].lineWidth = lineWidth; + HPDF_Page_SetLineWidth(page, lineWidth); +} + +/** + * Checks if given font and font size is already set in PDF gstate and if not, + * update the gstate accordingly. + * \param page PDF page where the update needs to happen. + * \param font Wanted PDF font. + * \param font_size Wanted PDF font size. + */ +void pdfw_gs_font(HPDF_Page page, HPDF_Font font, HPDF_REAL font_size) +{ + if (font == pdfw_gs[pdfw_gs_level].font + && font_size == pdfw_gs[pdfw_gs_level].font_size) + return; + pdfw_gs[pdfw_gs_level].font = font; + pdfw_gs[pdfw_gs_level].font_size = font_size; + HPDF_Page_SetFontAndSize(page, font, font_size); +} + +/** + * Checks if given dash pattern is already set in PDF gstate and if not, + * update the gstate accordingly. + * \param page PDF page where the update needs to happen. + * \param dash Wanted dash pattern. + */ +void pdfw_gs_dash(HPDF_Page page, DashPattern_e dash) +{ + if (dash == pdfw_gs[pdfw_gs_level].dash) + return; + pdfw_gs[pdfw_gs_level].dash = dash; + switch (dash) { + case DashPattern_eNone: { + HPDF_Page_SetDash(page, NULL, 0, 0); + break; + } + case DashPattern_eDash: { + const HPDF_UINT16 dash_ptn[] = {3}; + HPDF_Page_SetDash(page, dash_ptn, 1, 1); + break; + } + case DashPattern_eDotted: { + const HPDF_UINT16 dash_ptn[] = {1}; + HPDF_Page_SetDash(page, dash_ptn, 1, 1); + break; + } + } +} + +#else +void save_pdf(const char *path) +{ +} +#endif /* WITH_PDF_EXPORT */ diff --git a/desktop/save_pdf.h b/desktop/save_pdf.h new file mode 100644 index 000000000..d02c356e8 --- /dev/null +++ b/desktop/save_pdf.h @@ -0,0 +1,41 @@ +/* + * Copyright 2008 Adam Blokus + * + * 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 . + */ + +/** \file + PDF Plotting +*/ + +#ifndef NETSURF_PDF_PLOTTERS_H +#define NETSURF_PDF_PLOTTERS_H + +#include "desktop/print.h" + +extern const 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 save_pdf(const char *path); + +#endif /*NETSURF_PDF_PLOTTERS_H*/ diff --git a/desktop/save_pdf/Makefile b/desktop/save_pdf/Makefile deleted file mode 100644 index cf1f978e6..000000000 --- a/desktop/save_pdf/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# PDF saving sources - -# S_PDF are sources of the pdf plotter + the ones for paged-printing -S_PDF := pdf_plotters.c font_haru.c - -S_PDF := $(addprefix desktop/save_pdf/,$(S_PDF)) diff --git a/desktop/save_pdf/TODO b/desktop/save_pdf/TODO deleted file mode 100644 index 1b3a896b9..000000000 --- a/desktop/save_pdf/TODO +++ /dev/null @@ -1,19 +0,0 @@ -- 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 deleted file mode 100644 index e8643f701..000000000 --- a/desktop/save_pdf/font_haru.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright 2008 Adam Blokus - * Copyright 2009 John Tytgat - * - * 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 . - */ - - /** \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 -#include -#include -#include - -#include - -#include "css/css.h" -#include "css/utils.h" - -#include "utils/nsoption.h" -#include "desktop/save_pdf/font_haru.h" -#include "desktop/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 plot_font_style_t *fstyle, - const char *string, size_t length, - int *width); - -static bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle, - const char *string, size_t length, - int x, size_t *char_offset, int *actual_x); - -static bool haru_nsfont_split(const plot_font_style_t *fstyle, - const char *string, size_t length, - int x, size_t *char_offset, int *actual_x); - -static float pdf_text_scale = DEFAULT_EXPORT_SCALE; - -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 fstyle style for this text - * \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 plot_font_style_t *fstyle, - 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(fstyle, pdf, page, NULL, 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 fstyle style for this text - * \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 plot_font_style_t *fstyle, - 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(fstyle, pdf, page, NULL, 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 fstyle style for this text - * \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 plot_font_style_t *fstyle, - 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(fstyle, pdf, page, NULL, 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 font style to a Haru HPDF_Page - * - * \param fstyle plot style for this page - * \param doc document owning the page - * \param page the page to apply the style to - * \param font if this is non NULL it is updated to the font based - * on given style - * \param font_size if this is non NULL it is updated to the font size - * based on given style - * \return true on success, false on error and error reported - * - * When both font and font_size are NULL, the HPDF_Page is updated for given - * style, otherwise it is left to the called to do this. - */ -bool haru_nsfont_apply_style(const plot_font_style_t *fstyle, - HPDF_Doc doc, HPDF_Page page, - HPDF_Font *font, HPDF_REAL *font_size) -{ - HPDF_Font pdf_font; - HPDF_REAL size; - char font_name[50]; - bool roman = false; - bool bold = false; - bool styled = false; - - /*TODO: style handling, we are mapping the - styles on the basic 14 fonts only - */ - switch (fstyle->family) { - case PLOT_FONT_FAMILY_SERIF: - strcpy(font_name, "Times"); - roman = true; - break; - case PLOT_FONT_FAMILY_MONOSPACE: - strcpy(font_name, "Courier"); - break; - case PLOT_FONT_FAMILY_SANS_SERIF: - strcpy(font_name, "Helvetica"); - break; - case PLOT_FONT_FAMILY_CURSIVE: - case PLOT_FONT_FAMILY_FANTASY: - default: - strcpy(font_name, "Times"); - roman=true; - break; - } - - if (fstyle->weight == 700) { - strcat(font_name, "-Bold"); - bold = true; - } - - if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE)) { - if (!bold) - strcat(font_name,"-"); - if (roman) - strcat(font_name,"Italic"); - else - strcat(font_name,"Oblique"); - - styled = true; - } - - if (roman && !styled && !bold) - strcat(font_name, "-Roman"); - -#ifdef FONT_HARU_DEBUG - LOG(("Setting font: %s", font_name)); -#endif - - size = fstyle->size; - - if (font != NULL) - size *= pdf_text_scale; - - if (size <= 0) - return true; - - size /= FONT_SIZE_SCALE; - - if (size > HPDF_MAX_FONTSIZE) - size = HPDF_MAX_FONTSIZE; - - if (font_size) - *font_size = size; - - pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding"); - if (pdf_font == NULL) - return false; - if (font != NULL) - *font = pdf_font; - - if (font == NULL || font_size == NULL) - HPDF_Page_SetFontAndSize(page, pdf_font, size); - - return true; -} - -/** - * Sync the text scale with the scale for the whole content - */ -void haru_nsfont_set_scale(float s) -{ - pdf_text_scale = s; -} - -#endif /* WITH_PDF_EXPORT */ - diff --git a/desktop/save_pdf/font_haru.h b/desktop/save_pdf/font_haru.h deleted file mode 100644 index c6578b09f..000000000 --- a/desktop/save_pdf/font_haru.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2008 Adam Blokus - * Copyright 2009 John Tytgat - * - * 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 . - */ - - /** \file - * Font handling in Haru pdf documents (interface). - */ - -#ifndef _NETSURF_RENDER_FONT_HARU_H_ -#define _NETSURF_RENDER_FONT_HARU_H_ - -#include - -#include "desktop/plot_style.h" -#include "desktop/font.h" - -bool haru_nsfont_apply_style(const plot_font_style_t *fstyle, - HPDF_Doc doc, HPDF_Page page, - HPDF_Font *font, HPDF_REAL *font_size); - -void haru_nsfont_set_scale(float s); - -extern const struct font_functions haru_nsfont; - -#endif diff --git a/desktop/save_pdf/pdf_plotters.c b/desktop/save_pdf/pdf_plotters.c deleted file mode 100644 index 123408dd3..000000000 --- a/desktop/save_pdf/pdf_plotters.c +++ /dev/null @@ -1,963 +0,0 @@ -/* - * Copyright 2008 Adam Blokus - * Copyright 2009 John Tytgat - * - * 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 . - */ - - /** \file - * Target independent PDF plotting using Haru Free PDF Library. - */ - -#include "utils/config.h" -#ifdef WITH_PDF_EXPORT - -#include -#include -#include - -#include - -#include "content/hlcache.h" -#include "utils/nsoption.h" -#include "desktop/plotters.h" -#include "desktop/print.h" -#include "desktop/printer.h" -#include "desktop/save_pdf/pdf_plotters.h" -#include "image/bitmap.h" -#include "utils/log.h" -#include "utils/utils.h" -#include "utils/useragent.h" - -#include "font_haru.h" - -/* #define PDF_DEBUG */ -/* #define PDF_DEBUG_DUMPGRID */ - -static bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle); -static bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style); -static bool pdf_plot_clip(const struct rect *clip); -static bool pdf_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); -static bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style); -static bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style); -static bool pdf_plot_bitmap_tile(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags); -static bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]); - -static HPDF_Image pdf_extract_image(struct bitmap *bitmap); - -static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, - void *user_data); - -#ifdef PDF_DEBUG_DUMPGRID -static void pdf_plot_grid(int x_dist,int y_dist,unsigned int colour); -#endif - -typedef enum { - DashPattern_eNone, - DashPattern_eDash, - DashPattern_eDotted -} DashPattern_e; - -/* Wrapper routines to minimize gstate updates in the produced PDF file. */ -static void pdfw_gs_init(void); -static void pdfw_gs_save(HPDF_Page page); -static void pdfw_gs_restore(HPDF_Page page); -static void pdfw_gs_fillcolour(HPDF_Page page, colour col); -static void pdfw_gs_strokecolour(HPDF_Page page, colour col); -static void pdfw_gs_linewidth(HPDF_Page page, float lineWidth); -static void pdfw_gs_font(HPDF_Page page, HPDF_Font font, HPDF_REAL font_size); -static void pdfw_gs_dash(HPDF_Page page, DashPattern_e dash); - -/** - * Our PDF gstate mirror which we use to minimize gstate updates - * in the PDF file. - */ -typedef struct { - colour fillColour; /**< Current fill colour. */ - colour strokeColour; /**< Current stroke colour. */ - float lineWidth; /**< Current line width. */ - HPDF_Font font; /**< Current font. */ - HPDF_REAL font_size; /**< Current font size. */ - DashPattern_e dash; /**< Current dash state. */ -} PDFW_GState; - -static void apply_clip_and_mode(bool selectTextMode, colour fillCol, - colour strokeCol, float lineWidth, DashPattern_e dash); - -#define PDFW_MAX_GSTATES 4 -static PDFW_GState pdfw_gs[PDFW_MAX_GSTATES]; -static unsigned int pdfw_gs_level; - -static HPDF_Doc pdf_doc; /**< Current PDF document. */ -static HPDF_Page pdf_page; /**< Current page. */ - -/*PDF Page size*/ -static HPDF_REAL page_height, page_width; - -static bool in_text_mode; /**< true if we're currently in text mode or not. */ -static bool clip_update_needed; /**< true if pdf_plot_clip was invoked for - current page and not yet synced with PDF output. */ -static int last_clip_x0, last_clip_y0, last_clip_x1, last_clip_y1; - -static const struct print_settings *settings; - -static const struct plotter_table pdf_plotters = { - .rectangle = pdf_plot_rectangle, - .line = pdf_plot_line, - .polygon = pdf_plot_polygon, - .clip = pdf_plot_clip, - .text = pdf_plot_text, - .disc = pdf_plot_disc, - .arc = pdf_plot_arc, - .bitmap = pdf_plot_bitmap_tile, - .path = pdf_plot_path, - .option_knockout = false, -}; - -const struct printer pdf_printer = { - &pdf_plotters, - pdf_begin, - pdf_next_page, - pdf_end -}; - -static char *owner_pass; -static char *user_pass; - -bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle) -{ - DashPattern_e dash; -#ifdef PDF_DEBUG - LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, pstyle->fill_colour)); -#endif - - if (pstyle->fill_type != PLOT_OP_TYPE_NONE) { - - apply_clip_and_mode(false, pstyle->fill_colour, NS_TRANSPARENT, 0., DashPattern_eNone); - - /* 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); - - HPDF_Page_Rectangle(pdf_page, x0, page_height - y1, x1 - x0, y1 - y0); - HPDF_Page_Fill(pdf_page); - - } - - if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) { - - switch (pstyle->stroke_type) { - case PLOT_OP_TYPE_DOT: - dash = DashPattern_eDotted; - break; - - case PLOT_OP_TYPE_DASH: - dash = DashPattern_eDash; - break; - - default: - dash = DashPattern_eNone; - break; - - } - - apply_clip_and_mode(false, - NS_TRANSPARENT, - pstyle->stroke_colour, - pstyle->stroke_width, - dash); - - HPDF_Page_Rectangle(pdf_page, x0, page_height - y0, x1 - x0, -(y1 - y0)); - HPDF_Page_Stroke(pdf_page); - } - - return true; -} - -bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle) -{ - DashPattern_e dash; - - switch (pstyle->stroke_type) { - case PLOT_OP_TYPE_DOT: - dash = DashPattern_eDotted; - break; - - case PLOT_OP_TYPE_DASH: - dash = DashPattern_eDash; - break; - - default: - dash = DashPattern_eNone; - break; - - } - - apply_clip_and_mode(false, - NS_TRANSPARENT, - pstyle->stroke_colour, - pstyle->stroke_width, - dash); - - HPDF_Page_MoveTo(pdf_page, x0, page_height - y0); - HPDF_Page_LineTo(pdf_page, x1, page_height - y1); - HPDF_Page_Stroke(pdf_page); - - return true; -} - -bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) -{ - unsigned 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(false, style->fill_colour, NS_TRANSPARENT, 0., DashPattern_eNone); - - HPDF_Page_MoveTo(pdf_page, p[0], page_height - p[1]); - for (i = 1 ; ix0, 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); - - clip_update_needed = true; - - return true; -} - -bool pdf_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) -{ -#ifdef PDF_DEBUG - LOG((". %d %d %.*s", x, y, (int)length, text)); -#endif - char *word; - HPDF_Font pdf_font; - HPDF_REAL size; - - if (length == 0) - return true; - - apply_clip_and_mode(true, fstyle->foreground, NS_TRANSPARENT, 0., - DashPattern_eNone); - - haru_nsfont_apply_style(fstyle, pdf_doc, pdf_page, &pdf_font, &size); - pdfw_gs_font(pdf_page, pdf_font, size); - - /* FIXME: UTF-8 to current font encoding needs to done. Or the font - * encoding needs to be UTF-8 or other Unicode encoding. */ - word = (char *)malloc( sizeof(char) * (length+1) ); - if (word == NULL) - return false; - memcpy(word, text, length); - word[length] = '\0'; - - HPDF_Page_TextOut (pdf_page, x, page_height - y, word); - - free(word); - - return true; -} - -bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style) -{ -#ifdef PDF_DEBUG - LOG((".")); -#endif - if (style->fill_type != PLOT_OP_TYPE_NONE) { - apply_clip_and_mode(false, - style->fill_colour, - NS_TRANSPARENT, - 1., DashPattern_eNone); - - HPDF_Page_Circle(pdf_page, x, page_height - y, radius); - - HPDF_Page_Fill(pdf_page); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - /* FIXME: line width 1 is ok ? */ - apply_clip_and_mode(false, - NS_TRANSPARENT, - style->stroke_colour, - 1., DashPattern_eNone); - - HPDF_Page_Circle(pdf_page, x, page_height - y, radius); - - HPDF_Page_Stroke(pdf_page); - } - - return true; -} - -bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) -{ -#ifdef PDF_DEBUG - LOG(("%d %d %d %d %d %X", x, y, radius, angle1, angle2, style->stroke_colour)); -#endif - - /* FIXME: line width 1 is ok ? */ - apply_clip_and_mode(false, NS_TRANSPARENT, style->fill_colour, 1., DashPattern_eNone); - - /* Normalize angles */ - angle1 %= 360; - angle2 %= 360; - if (angle1 > angle2) - angle1 -= 360; - - HPDF_Page_Arc(pdf_page, x, page_height - y, radius, angle1, angle2); - - HPDF_Page_Stroke(pdf_page); - return true; -} - - -bool pdf_plot_bitmap_tile(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) -{ - HPDF_Image image; - HPDF_REAL current_x, current_y ; - HPDF_REAL max_width, max_height; - -#ifdef PDF_DEBUG - LOG(("%d %d %d %d %p 0x%x", x, y, width, height, - bitmap, bg)); -#endif - if (width == 0 || height == 0) - return true; - - apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., DashPattern_eNone); - - image = pdf_extract_image(bitmap); - if (!image) - return false; - - /*The position of the next tile*/ - max_width = (flags & BITMAPF_REPEAT_X) ? page_width : width; - max_height = (flags & BITMAPF_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; -} - -HPDF_Image pdf_extract_image(struct bitmap *bitmap) -{ - HPDF_Image image = NULL; - hlcache_handle *content = NULL; - - /* TODO - get content from bitmap pointer */ - - if (content) { - const char *source_data; - unsigned long source_size; - - /*Not sure if I don't have to check if downloading has been - finished. - Other way - lock pdf plotting while fetching a website - */ - source_data = content_get_source_data(content, &source_size); - - switch(content_get_type(content)){ - /*Handle "embeddable" types of images*/ - case CONTENT_JPEG: - image = HPDF_LoadJpegImageFromMem(pdf_doc, - (const HPDF_BYTE *) source_data, - source_size); - break; - - /*Disabled until HARU PNG support will be more stable. - - case CONTENT_PNG: - image = HPDF_LoadPngImageFromMem(pdf_doc, - (const HPDF_BYTE *)content->source_data, - content->total_size); - break;*/ - default: - break; - } - } - - if (!image) { - HPDF_Image smask; - unsigned char *img_buffer, *rgb_buffer, *alpha_buffer; - int img_width, img_height, img_rowstride; - int i, j; - - /*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 = (unsigned char *)malloc(3 * img_width * img_height); - alpha_buffer = (unsigned char *)malloc(img_width * img_height); - if (rgb_buffer == NULL || alpha_buffer == NULL) { - LOG(("Not enough memory to create RGB buffer")); - free(rgb_buffer); - free(alpha_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(image, smask) != HPDF_OK) - image = NULL; - - free(rgb_buffer); - free(alpha_buffer); - } - - return image; -} - -/** - * Enter/leave text mode and update PDF gstate for its clip, fill & stroke - * colour, line width and dash pattern parameters. - * \param selectTextMode true if text mode needs to be entered if required; - * false otherwise. - * \param fillCol Desired fill colour, use NS_TRANSPARENT if no update is - * required. - * \param strokeCol Desired stroke colour, use NS_TRANSPARENT if no update is - * required. - * \param lineWidth Desired line width. Only taken into account when strokeCol - * is different from NS_TRANSPARENT. - * \param dash Desired dash pattern. Only taken into account when strokeCol - * is different from NS_TRANSPARENT. - */ -static void apply_clip_and_mode(bool selectTextMode, colour fillCol, - colour strokeCol, float lineWidth, DashPattern_e dash) -{ - /* Leave text mode when - * 1) we're not setting text anymore - * 2) or we need to update the current clippath - * 3) or we need to update any fill/stroke colour, linewidth or dash. - * Note: the test on stroke parameters (stroke colour, line width and - * dash) is commented out as if these need updating we want to be - * outside the text mode anyway (i.e. selectTextMode is false). - */ - if (in_text_mode && (!selectTextMode || clip_update_needed - || (fillCol != NS_TRANSPARENT - && fillCol != pdfw_gs[pdfw_gs_level].fillColour) - /* || (strokeCol != NS_TRANSPARENT - && (strokeCol != pdfw_gs[pdfw_gs_level].strokeColour - || lineWidth != pdfw_gs[pdfw_gs_level].lineWidth - || dash != pdfw_gs[pdfw_gs_level].dash)) */)) { - HPDF_Page_EndText(pdf_page); - in_text_mode = false; - } - - if (clip_update_needed) - pdfw_gs_restore(pdf_page); - - /* Update fill/stroke colour, linewidth and dash when needed. */ - if (fillCol != NS_TRANSPARENT) - pdfw_gs_fillcolour(pdf_page, fillCol); - if (strokeCol != NS_TRANSPARENT) { - pdfw_gs_strokecolour(pdf_page, strokeCol); - pdfw_gs_linewidth(pdf_page, lineWidth); - pdfw_gs_dash(pdf_page, dash); - } - - if (clip_update_needed) { - pdfw_gs_save(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); - - clip_update_needed = false; - } - - if (selectTextMode && !in_text_mode) { - HPDF_Page_BeginText(pdf_page); - in_text_mode = true; - } -} - -static inline float transform_x(const float transform[6], float x, float y) -{ - return transform[0] * x + transform[2] * y + transform[4]; -} - -static inline float transform_y(const float transform[6], float x, float y) -{ - return page_height - - (transform[1] * x + transform[3] * y + transform[5]); -} - -bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - unsigned int i; - bool empty_path; - -#ifdef PDF_DEBUG - LOG((".")); -#endif - - if (n == 0) - return true; - - if (c == NS_TRANSPARENT && fill == NS_TRANSPARENT) - return true; - - if (p[0] != PLOTTER_PATH_MOVE) - return false; - - apply_clip_and_mode(false, fill, c, width, DashPattern_eNone); - - empty_path = true; - 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 != NS_TRANSPARENT) { - if (c != NS_TRANSPARENT) - HPDF_Page_FillStroke(pdf_page); - else - HPDF_Page_Fill(pdf_page); - } - else - HPDF_Page_Stroke(pdf_page); - - return true; -} - -/** - * 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) -{ - pdfw_gs_init(); - - if (pdf_doc != NULL) - HPDF_Free(pdf_doc); - 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 - - FIXTOFLT(FSUB(settings->margins[MARGINLEFT], - settings->margins[MARGINRIGHT])); - - page_height = settings->page_height - - FIXTOFLT(settings->margins[MARGINTOP]); - - -#ifndef PDF_DEBUG - if (option_enable_PDF_compression) - HPDF_SetCompressionMode(pdf_doc, HPDF_COMP_ALL); /*Compression on*/ -#endif - HPDF_SetInfoAttr(pdf_doc, HPDF_INFO_CREATOR, user_agent_string()); - - pdf_page = NULL; - -#ifdef PDF_DEBUG - LOG(("pdf_begin finishes")); -#endif - return true; -} - - -bool pdf_next_page(void) -{ -#ifdef PDF_DEBUG - LOG(("pdf_next_page begins")); -#endif - clip_update_needed = false; - if (pdf_page != NULL) { - apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., - DashPattern_eNone); - pdfw_gs_restore(pdf_page); - } - -#ifdef PDF_DEBUG_DUMPGRID - if (pdf_page != NULL) { - 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, - FIXTOFLT(settings->margins[MARGINLEFT]), 0); - - pdfw_gs_save(pdf_page); - -#ifdef PDF_DEBUG - LOG(("%f %f", page_width, page_height)); -#endif - - return true; -} - - -void pdf_end(void) -{ -#ifdef PDF_DEBUG - LOG(("pdf_end begins")); -#endif - clip_update_needed = false; - if (pdf_page != NULL) { - apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., - DashPattern_eNone); - pdfw_gs_restore(pdf_page); - } - -#ifdef PDF_DEBUG_DUMPGRID - if (pdf_page != NULL) { - pdf_plot_grid(10, 10, 0xCCCCCC); - pdf_plot_grid(100, 100, 0xCCCCFF); - } -#endif - - assert(settings->output != NULL); - - /*Encryption on*/ - if (option_enable_PDF_password) - PDF_Password(&owner_pass, &user_pass, - (void *)settings->output); - else - save_pdf(settings->output); -#ifdef PDF_DEBUG - LOG(("pdf_end finishes")); -#endif -} - -/** saves the pdf optionally encrypting it before*/ -void save_pdf(const 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; - } - - if (!success) - warn_user("Unable to save PDF file.", 0); - - HPDF_Free(pdf_doc); - pdf_doc = NULL; -} - - -/** - * 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_DUMPGRID -void pdf_plot_grid(int x_dist, int y_dist, unsigned int colour) -{ - 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 - -/** - * Initialize the gstate wrapper code. - */ -void pdfw_gs_init() -{ - pdfw_gs_level = 0; - pdfw_gs[0].fillColour = 0x00000000; /* Default PDF fill colour is black. */ - pdfw_gs[0].strokeColour = 0x00000000; /* Default PDF stroke colour is black. */ - pdfw_gs[0].lineWidth = 1.0; /* Default PDF line width is 1. */ - pdfw_gs[0].font = NULL; - pdfw_gs[0].font_size = 0.; - pdfw_gs[0].dash = DashPattern_eNone; /* Default dash state is a solid line. */ -} - -/** - * Increase gstate level. - * \param page PDF page where the update needs to happen. - */ -void pdfw_gs_save(HPDF_Page page) -{ - if (pdfw_gs_level == PDFW_MAX_GSTATES) - abort(); - pdfw_gs[pdfw_gs_level + 1] = pdfw_gs[pdfw_gs_level]; - ++pdfw_gs_level; - HPDF_Page_GSave(page); -} - -/** - * Decrease gstate level and restore the gstate to its value at last save - * operation. - * \param page PDF page where the update needs to happen. - */ -void pdfw_gs_restore(HPDF_Page page) -{ - if (pdfw_gs_level == 0) - abort(); - --pdfw_gs_level; - HPDF_Page_GRestore(page); -} - -#define RBYTE(x) (((x) & 0x0000FF) >> 0) -#define GBYTE(x) (((x) & 0x00FF00) >> 8) -#define BBYTE(x) (((x) & 0xFF0000) >> 16) -#define R(x) (RBYTE(x) / 255.) -#define G(x) (GBYTE(x) / 255.) -#define B(x) (BBYTE(x) / 255.) - -/** - * Checks if given fill colour is already set in PDF gstate and if not, - * update the gstate accordingly. - * \param page PDF page where the update needs to happen. - * \param col Wanted fill colour. - */ -void pdfw_gs_fillcolour(HPDF_Page page, colour col) -{ - if (col == pdfw_gs[pdfw_gs_level].fillColour) - return; - pdfw_gs[pdfw_gs_level].fillColour = col; - if (RBYTE(col) == GBYTE(col) && GBYTE(col) == BBYTE(col)) - HPDF_Page_SetGrayFill(pdf_page, R(col)); - else - HPDF_Page_SetRGBFill(pdf_page, R(col), G(col), B(col)); -} - -/** - * Checks if given stroke colour is already set in PDF gstate and if not, - * update the gstate accordingly. - * \param page PDF page where the update needs to happen. - * \param col Wanted stroke colour. - */ -void pdfw_gs_strokecolour(HPDF_Page page, colour col) -{ - if (col == pdfw_gs[pdfw_gs_level].strokeColour) - return; - pdfw_gs[pdfw_gs_level].strokeColour = col; - if (RBYTE(col) == GBYTE(col) && GBYTE(col) == BBYTE(col)) - HPDF_Page_SetGrayStroke(pdf_page, R(col)); - else - HPDF_Page_SetRGBStroke(pdf_page, R(col), G(col), B(col)); -} - -/** - * Checks if given line width is already set in PDF gstate and if not, update - * the gstate accordingly. - * \param page PDF page where the update needs to happen. - * \param lineWidth Wanted line width. - */ -void pdfw_gs_linewidth(HPDF_Page page, float lineWidth) -{ - if (lineWidth == pdfw_gs[pdfw_gs_level].lineWidth) - return; - pdfw_gs[pdfw_gs_level].lineWidth = lineWidth; - HPDF_Page_SetLineWidth(page, lineWidth); -} - -/** - * Checks if given font and font size is already set in PDF gstate and if not, - * update the gstate accordingly. - * \param page PDF page where the update needs to happen. - * \param font Wanted PDF font. - * \param font_size Wanted PDF font size. - */ -void pdfw_gs_font(HPDF_Page page, HPDF_Font font, HPDF_REAL font_size) -{ - if (font == pdfw_gs[pdfw_gs_level].font - && font_size == pdfw_gs[pdfw_gs_level].font_size) - return; - pdfw_gs[pdfw_gs_level].font = font; - pdfw_gs[pdfw_gs_level].font_size = font_size; - HPDF_Page_SetFontAndSize(page, font, font_size); -} - -/** - * Checks if given dash pattern is already set in PDF gstate and if not, - * update the gstate accordingly. - * \param page PDF page where the update needs to happen. - * \param dash Wanted dash pattern. - */ -void pdfw_gs_dash(HPDF_Page page, DashPattern_e dash) -{ - if (dash == pdfw_gs[pdfw_gs_level].dash) - return; - pdfw_gs[pdfw_gs_level].dash = dash; - switch (dash) { - case DashPattern_eNone: { - HPDF_Page_SetDash(page, NULL, 0, 0); - break; - } - case DashPattern_eDash: { - const HPDF_UINT16 dash_ptn[] = {3}; - HPDF_Page_SetDash(page, dash_ptn, 1, 1); - break; - } - case DashPattern_eDotted: { - const HPDF_UINT16 dash_ptn[] = {1}; - HPDF_Page_SetDash(page, dash_ptn, 1, 1); - break; - } - } -} - -#endif /* WITH_PDF_EXPORT */ - diff --git a/desktop/save_pdf/pdf_plotters.h b/desktop/save_pdf/pdf_plotters.h deleted file mode 100644 index 7ecb54964..000000000 --- a/desktop/save_pdf/pdf_plotters.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2008 Adam Blokus - * - * 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 . - */ - -/** \file - PDF Plotting -*/ - -#ifndef NETSURF_PDF_PLOTTERS_H -#define NETSURF_PDF_PLOTTERS_H - -#include "desktop/print.h" - -extern const 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 save_pdf(const char *path); - -#endif /*NETSURF_PDF_PLOTTERS_H*/ diff --git a/gtk/Makefile.target b/gtk/Makefile.target index be0dad2ae..b1a6f61f8 100644 --- a/gtk/Makefile.target +++ b/gtk/Makefile.target @@ -117,7 +117,7 @@ S_GTK := $(addprefix gtk/,$(S_GTK)) $(addprefix utils/,container.c) # This is the final source build list # Note this is deliberately *not* expanded here as common and image # are not yet available -SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_PDF) $(S_PIXBUF) $(S_GTK) +SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_PIXBUF) $(S_GTK) EXETARGET := nsgtk # ---------------------------------------------------------------------------- diff --git a/gtk/gui.c b/gtk/gui.c index eeba46619..c4dc0e171 100644 --- a/gtk/gui.c +++ b/gtk/gui.c @@ -54,7 +54,7 @@ #include "content/backing_store.h" #include "desktop/browser.h" #include "desktop/save_complete.h" -#include "desktop/save_pdf/pdf_plotters.h" +#include "desktop/save_pdf.h" #include "desktop/searchweb.h" #include "desktop/sslcert_viewer.h" #include "desktop/textinput.h" @@ -696,71 +696,45 @@ gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event, gpointer data) return FALSE; } -#ifdef WITH_PDF_EXPORT - -void PDF_Password(char **owner_pass, char **user_pass, char *path) -{ - GladeXML *x = glade_xml_new(glade_password_file_location, NULL, NULL); - GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndPDFPassword")); - GtkButton *ok, *no; - void **data = malloc(5 * sizeof(void *)); - - *owner_pass = NULL; - *user_pass = NULL; - - data[0] = owner_pass; - data[1] = user_pass; - data[2] = wnd; - data[3] = x; - data[4] = path; - - ok = GTK_BUTTON(glade_xml_get_widget(x, "buttonPDFSetPassword")); - no = GTK_BUTTON(glade_xml_get_widget(x, "buttonPDFNoPassword")); - - g_signal_connect(G_OBJECT(ok), "clicked", - G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data); - g_signal_connect(G_OBJECT(no), "clicked", - G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data); - - gtk_widget_show(GTK_WIDGET(wnd)); -} static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data) { char **owner_pass = ((void **)data)[0]; char **user_pass = ((void **)data)[1]; GtkWindow *wnd = ((void **)data)[2]; - GladeXML *x = ((void **)data)[3]; + GtkBuilder *gladeFile = ((void **)data)[3]; char *path = ((void **)data)[4]; char *op, *op1; char *up, *up1; - op = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFOwnerPassword")))); - op1 = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFOwnerPassword1")))); - up = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFUserPassword")))); - up1 = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFUserPassword1")))); + op = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(gladeFile, + "entryPDFOwnerPassword")))); + op1 = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(gladeFile, + "entryPDFOwnerPassword1")))); + up = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(gladeFile, + "entryPDFUserPassword")))); + up1 = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(gladeFile, + "entryPDFUserPassword1")))); if (op[0] == '\0') { - gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, + gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(gladeFile, "labelInfo")), "Owner password must be at least 1 character long:"); free(op); free(up); - } - else if (!strcmp(op, up)) { - gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, + } else if (!strcmp(op, up)) { + gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(gladeFile, "labelInfo")), "User and owner passwords must be different:"); free(op); free(up); - } - else if (!strcmp(op, op1) && !strcmp(up, up1)) { + } else if (!strcmp(op, op1) && !strcmp(up, up1)) { *owner_pass = op; if (up[0] == '\0') @@ -770,13 +744,13 @@ static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data) free(data); gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(x)); + g_object_unref(G_OBJECT(gladeFile)); save_pdf(path); + free(path); - } - else { - gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, + } else { + gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(gladeFile, "labelInfo")), "Passwords not confirmed:"); free(op); free(up); @@ -789,18 +763,60 @@ static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data) static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data) { GtkWindow *wnd = ((void **)data)[2]; - GladeXML *x = ((void **)data)[3]; + GtkBuilder *gladeFile = ((void **)data)[3]; char *path = ((void **)data)[4]; free(data); gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(x)); + g_object_unref(G_OBJECT(gladeFile)); save_pdf(path); + free(path); } -#endif + +static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path) +{ + GtkButton *ok, *no; + GtkWindow *wnd; + void **data; + GtkBuilder *gladeFile; + GError* error = NULL; + + gladeFile = gtk_builder_new(); + if (!gtk_builder_add_from_file(gladeFile, + glade_file_location->password, + &error)) { + g_warning ("Couldn't load builder file: %s", error->message); + g_error_free (error); + return; + } + + wnd = GTK_WINDOW(gtk_builder_get_object(gladeFile, "wndPDFPassword")); + + data = malloc(5 * sizeof(void *)); + + *owner_pass = NULL; + *user_pass = NULL; + + data[0] = owner_pass; + data[1] = user_pass; + data[2] = wnd; + data[3] = gladeFile; + data[4] = path; + + ok = GTK_BUTTON(gtk_builder_get_object(gladeFile, "buttonPDFSetPassword")); + no = GTK_BUTTON(gtk_builder_get_object(gladeFile, "buttonPDFNoPassword")); + + g_signal_connect(G_OBJECT(ok), "clicked", + G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data); + g_signal_connect(G_OBJECT(no), "clicked", + G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data); + + gtk_widget_show(GTK_WIDGET(wnd)); +} + uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) { @@ -1194,6 +1210,7 @@ static struct gui_browser_table nsgtk_browser_table = { .launch_url = gui_launch_url, .cert_verify = gui_cert_verify, .login = gui_401login_open, + .pdf_password = nsgtk_pdf_password, }; /** diff --git a/riscos/Makefile.target b/riscos/Makefile.target index 46ca34116..a52c03f5a 100644 --- a/riscos/Makefile.target +++ b/riscos/Makefile.target @@ -92,7 +92,7 @@ TPL_RISCOS := $(addprefix riscos/templates/,$(TPL_RISCOS)) # This is the final source build list # Note this is deliberately *not* expanded here as common and image # are not yet available -SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_PDF) $(S_RISCOS) +SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_RISCOS) EXETARGET := !NetSurf/!RunImage$(EXEEXT) !NetSurf/!Run$(RUNEXT): riscos/scripts/Run $(EXETARGET) diff --git a/riscos/gui.c b/riscos/gui.c index ade22cb48..198fd2391 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -2152,13 +2152,6 @@ bool ro_gui_prequit(void) } -void PDF_Password(char **owner_pass, char **user_pass, char *path) -{ - /** @todo this waits to be written, until then no PDF encryption */ - *owner_pass = NULL; -} - - /** * Generate a riscos path from one or more component elemnts. * diff --git a/utils/utils.h b/utils/utils.h index b90843271..00d150126 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -258,6 +258,5 @@ int dir_sort_alpha(const struct dirent **d1, const struct dirent **d2); /* Platform specific functions */ void warn_user(const char *warning, const char *detail); -void PDF_Password(char **owner_pass, char **user_pass, char *path); #endif -- cgit v1.2.3