From 35d3d6d0bb16abeeb6aad2fd0398c8e68a40d414 Mon Sep 17 00:00:00 2001 From: John Tytgat Date: Sat, 26 Jul 2008 16:01:59 +0000 Subject: First merge of Adam Blokus' GSoC work from his branch 'branches/adamblokus/netsurf'. Merged revisions 4212-4552,4554-4709,4711-4724 via svnmerge from svn://svn.netsurf-browser.org/branches/adamblokus/netsurf ........ r4212 | adamblokus | 2008-05-26 19:42:31 +0200 (Mon, 26 May 2008) | 4 lines Pdf plotting skeleton pinned on Print Preview in GTK. Just creates a file and draws lines. ........ r4213 | adamblokus | 2008-05-27 00:11:03 +0200 (Tue, 27 May 2008) | 4 lines Pdf plotter - added drawing some graphic primitives. Still with limited functionality, but a snapshot of the currently viewed page can be made and resembles the original. ........ r4214 | adamblokus | 2008-05-27 11:43:31 +0200 (Tue, 27 May 2008) | 2 lines Corrected encoding name ........ r4215 | adamblokus | 2008-05-27 12:47:26 +0200 (Tue, 27 May 2008) | 3 lines Colours and polygons added. ........ r4217 | adamblokus | 2008-05-27 21:39:35 +0200 (Tue, 27 May 2008) | 6 lines Added rectangles, filled boxes and clipping. Taken into consideration joty's comments. Added a todo list for this part. Added some debug stuff and checking boundaries. ........ r4218 | adamblokus | 2008-05-28 12:37:30 +0200 (Wed, 28 May 2008) | 2 lines Added path ploting (not sure if valid argument order for bezier) and dashed/dotted line styles ........ r4221 | adamblokus | 2008-05-28 22:11:05 +0200 (Wed, 28 May 2008) | 3 lines Some more options in graphic primitives and normalizing some parameters. ........ r4235 | adamblokus | 2008-05-31 22:54:56 +0200 (Sat, 31 May 2008) | 4 lines Plotting changed as jmb suggested (is the least invasive one from the possible) Added dummy bitmap plotting - way of plotting an image is determined by its type. ........ r4251 | adamblokus | 2008-06-03 17:12:15 +0200 (Tue, 03 Jun 2008) | 3 lines Added plotting jpg and png images - quite a lot to improve in this code, but it seems to work ;) ........ r4263 | adamblokus | 2008-06-05 14:20:32 +0200 (Thu, 05 Jun 2008) | 3 lines Added hadling images other than png and jpeg - with transparency. ........ r4267 | adamblokus | 2008-06-06 15:36:34 +0200 (Fri, 06 Jun 2008) | 5 lines Added handling NULL-returns from all mallocs. Added plot_bitmap_tile handling. Changed code style a little. ........ r4327 | adamblokus | 2008-06-12 17:46:34 +0200 (Thu, 12 Jun 2008) | 5 lines Added a first prototype of the paged-output organization. Still not sure about naming, file locations etc. Works with the same pdf plotting as before. ........ r4328 | adamblokus | 2008-06-13 13:52:15 +0200 (Fri, 13 Jun 2008) | 4 lines Added primitive width adjustment and outputing the whole website in multiple pages. ........ r4336 | joty | 2008-06-15 15:06:57 +0200 (Sun, 15 Jun 2008) | 1 line Fix RISC OS build failure (change r4235 wasn't complete). ........ r4337 | joty | 2008-06-15 18:15:32 +0200 (Sun, 15 Jun 2008) | 16 lines This enables "Export PDF" in RISC OS build: - Docs/Doxyfile(PREDEFINED): Added WITH_PDF_EXPORT - Makefile.sources(S_PDF): Add to RISC OS target as well. - utils/config.h: Define WITH_PDF_EXPORT which controls if we want to have PDF export functionality or not. - riscos/save_pdf.c,riscos/save_pdf.h(save_as_pdf): Use PDF print API made by Adam Blokus to write a PDF file under RISC OS. - riscos/save.c: Call save_as_pdf added. - riscos/menus.c: Add 'Export->PDF' menu entry. - riscos/menus.h(menu_action): Added BROWSER_EXPORT_PDF. - desktop/gui.h(gui_save_type): Added GUI_SAVE_PDF. - desktop/print.c(print_run): Added return value. - Makefile(CCACHE): Moved closed to the place where CC is set for the first time. (LDFLAGS): Centralised adding all non-pkgconfig libraries and added Haru + PNG libs. ........ r4343 | adamblokus | 2008-06-16 01:08:52 +0200 (Mon, 16 Jun 2008) | 3 lines Added margins and page size adjustment. ........ r4412 | adamblokus | 2008-06-21 20:22:07 +0200 (Sat, 21 Jun 2008) | 4 lines Added 'fuzzy' margins on page bottom. Disabled direct png embedding, because it is too unstable in Haru now. ........ r4421 | adamblokus | 2008-06-22 18:52:28 +0200 (Sun, 22 Jun 2008) | 2 lines Added "Save as.." dialog and Export->PDF menu entry. Print preview still works with default path. ........ r4437 | adamblokus | 2008-06-25 02:44:46 +0200 (Wed, 25 Jun 2008) | 4 lines Added skeleton of applying loose layout. Minor code cleaning-up. ........ r4492 | adamblokus | 2008-07-02 09:02:42 +0200 (Wed, 02 Jul 2008) | 5 lines Implemented the elementar ideas of the loose layout. Added scaling in the printing routine. Added some basic demonstrations. ........ r4493 | adamblokus | 2008-07-02 09:05:55 +0200 (Wed, 02 Jul 2008) | 3 lines Cleaned up the loosing code - commited to much of leftover rubbish code. ........ r4507 | adamblokus | 2008-07-04 14:25:48 +0200 (Fri, 04 Jul 2008) | 4 lines Added duplicating box tree and current content - window flickering during printing solved. Minor error checking after new HPDF_Image_AddSMask call. ........ r4515 | adamblokus | 2008-07-06 22:28:16 +0200 (Sun, 06 Jul 2008) | 2 lines Changes in loosen layout (image resizing). ........ r4517 | adamblokus | 2008-07-06 22:38:23 +0200 (Sun, 06 Jul 2008) | 2 lines Added pdf font handling and rendering functions with the use of Haru functions. ........ r4555 | adamblokus | 2008-07-10 00:59:05 +0200 (Thu, 10 Jul 2008) | 2 lines Added a very basic and still buggy GTK print implementation. ........ r4565 | adamblokus | 2008-07-10 14:50:16 +0200 (Thu, 10 Jul 2008) | 2 lines Added gtk printing one more time - I have forgotten to add the main file. ........ r4566 | adamblokus | 2008-07-10 14:57:02 +0200 (Thu, 10 Jul 2008) | 2 lines removed error with comment ........ r4569 | adamblokus | 2008-07-10 15:52:55 +0200 (Thu, 10 Jul 2008) | 5 lines Major style improvements - added a lot of doxygen comments, followed tlsa's style guide. Added some more error checking, too. ........ r4575 | adamblokus | 2008-07-10 18:48:26 +0200 (Thu, 10 Jul 2008) | 2 lines Cleaned up the code. ........ r4687 | adamblokus | 2008-07-17 14:17:19 +0200 (Thu, 17 Jul 2008) | 2 lines Changed everything according to jmb's review plus some minor bug fixes to gtk_print. ........ r4688 | adamblokus | 2008-07-17 17:16:34 +0200 (Thu, 17 Jul 2008) | 2 lines Solved the netsurf.glade clash from r4421. ........ r4693 | adamblokus | 2008-07-18 18:11:51 +0200 (Fri, 18 Jul 2008) | 2 lines Fixed bug with wrong number of pages in gtk printing. ........ r4695 | adamblokus | 2008-07-18 19:59:24 +0200 (Fri, 18 Jul 2008) | 3 lines - fixed uncommented line from the previous commit - fixed bug with scale bigger than 1.0 (incorretly clipped page) ........ r4696 | adamblokus | 2008-07-18 23:28:00 +0200 (Fri, 18 Jul 2008) | 2 lines Fixed bug in gtk_print_font_paint (and nsfont_paint). ........ r4697 | adamblokus | 2008-07-18 23:35:38 +0200 (Fri, 18 Jul 2008) | 2 lines Bug fix in nsfont_paint. ........ r4711 | adamblokus | 2008-07-19 22:44:15 +0200 (Sat, 19 Jul 2008) | 2 lines Added gtk_selection files. ........ r4712 | adamblokus | 2008-07-20 11:15:06 +0200 (Sun, 20 Jul 2008) | 2 lines Addam missing glade files. ........ r4713 | joty | 2008-07-20 17:13:10 +0200 (Sun, 20 Jul 2008) | 1 line Follow change r4517 for RISC OS and BeOS platforms : Added pdf font handling and rendering functions with the use of Haru functions. ........ r4714 | joty | 2008-07-20 18:19:50 +0200 (Sun, 20 Jul 2008) | 1 line Declare haru_nsfont iso define an instance for each C source including the font_haru.h header. This fixes breakage of PDF export on RISC OS. ........ r4724 | adamblokus | 2008-07-23 03:30:08 +0200 (Wed, 23 Jul 2008) | 6 lines Applied changes according to joty's review. Added checking the dimensions of a plotted image to pdf plotter. Commented out jpg embedding (it seems to cause some problems I'll bring it back when I figure out what's wrong) . Added back some files removed by mistake. ........ svn path=/trunk/netsurf/; revision=4741 --- pdf/TODO | 19 ++ pdf/font_haru.c | 373 ++++++++++++++++++++++++++ pdf/font_haru.h | 36 +++ pdf/pdf_plotters.c | 774 +++++++++++++++++++++++++++++++++++++++++++++++++++++ pdf/pdf_plotters.h | 40 +++ pdf/pdf_printer.h | 36 +++ 6 files changed, 1278 insertions(+) create mode 100644 pdf/TODO create mode 100644 pdf/font_haru.c create mode 100644 pdf/font_haru.h create mode 100644 pdf/pdf_plotters.c create mode 100644 pdf/pdf_plotters.h create mode 100644 pdf/pdf_printer.h (limited to 'pdf') diff --git a/pdf/TODO b/pdf/TODO new file mode 100644 index 000000000..1b3a896b9 --- /dev/null +++ b/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/pdf/font_haru.c b/pdf/font_haru.c new file mode 100644 index 000000000..045d481a2 --- /dev/null +++ b/pdf/font_haru.c @@ -0,0 +1,373 @@ +/* + * 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 + * 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. + */ + +#define FONT_HARU_DEBUG + +#include +#include +#include +#include + +#include "css/css.h" +#include "hpdf.h" +#include "render/font.h" +#include "pdf/font_haru.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; + + if (length == 0) { + *width = 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; + HPDF_REAL width; + + + if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length)) + return false; + + if (!HPDF_Page_SetWidth(page, x) + || !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) + || !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 + + if (font != NULL) { + pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding"); + if (pdf_font == NULL) + return false; + *font = pdf_font; + } + 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); + + /*with 0.7 the pages look the best, this should be kept the same + as the scale in print settings*/ + size = size / 0.7; + + pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding"); + if (pdf_font == NULL) + return false; + HPDF_Page_SetFontAndSize(page, pdf_font, size); + } + + return true; +} diff --git a/pdf/font_haru.h b/pdf/font_haru.h new file mode 100644 index 000000000..326f6497b --- /dev/null +++ b/pdf/font_haru.h @@ -0,0 +1,36 @@ +/* + * 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 + * 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; + + +#endif diff --git a/pdf/pdf_plotters.c b/pdf/pdf_plotters.c new file mode 100644 index 000000000..50d7067eb --- /dev/null +++ b/pdf/pdf_plotters.c @@ -0,0 +1,774 @@ +/* + * 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 + * Target independent PDF plotting using Haru Free PDF Library. + * Contains also the current solution for some text being cropped over page + * boundaries a 'fuzzy' bottom margin. + */ + +#include +#include +#include "hpdf.h" + +#include "desktop/plotters.h" +#include "desktop/print.h" +#include "desktop/printer.h" +#include "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_flush(void); +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 void pdf_page_apply_notext_clip(void); + +static HPDF_Image pdf_extract_image(struct bitmap *bitmap, struct content *content); + +static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, + void*user_data); + +static void pdf_plot_grid(int x_dist,int y_dist,unsigned int colour); + +/*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; + +static struct print_settings* settings; +/*this is added to the bottom margin as a place where text can be plotted + when it overflows just a little bit*/ +static float text_margin; + +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, + pdf_plot_flush, + pdf_plot_path +}; + +struct printer pdf_printer= { + &pdf_plotters, + pdf_begin, + pdf_next_page, + pdf_end +}; + +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 + 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 + 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; + + 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 ; ifont_size.value.length.unit == CSS_UNIT_PX) + size = style->font_size.value.length.value; + else + size = css_len2pt(&style->font_size.value.length, style); + + 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; + + if ( (size > y) && (y - descent <= text_margin) ) + return true; + + if (text_bottom_position < settings->margins[MARGINBOTTOM] + text_margin ) { + if ((text_bottom_position >= settings->margins[MARGINBOTTOM]) && + (page_height - (y - size) > + settings->margins[MARGINBOTTOM] + text_margin)) { + fuzzy = true; + HPDF_Page_GRestore(pdf_page); + } + } + + 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_BeginText(pdf_page); + HPDF_Page_SetFontAndSize (pdf_page, pdf_font, size); + HPDF_Page_TextOut (pdf_page, x, page_height - y, word); + HPDF_Page_EndText(pdf_page); + + if (fuzzy) + pdf_page_apply_notext_clip(); + + free(word); + + return true; +} + +bool pdf_plot_disc(int x, int y, int radius, colour c, bool filled){ +#ifdef PDF_DEBUG + LOG((".")); +#endif + 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; + + 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; + + 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; + + 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, + page_height-current_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*/ + /*TODO:something seems to be wrong with HPDF_LoadJpegImageFromMem + no embedding at all till I'll figure it out + */ +// case CONTENT_JPEG: +// image = HPDF_LoadJpegImageFromMem(pdf_doc, +// content->source_data, +// content->total_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;*/ + } + } + + 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; ipage_width - settings->margins[MARGINLEFT] - + settings->margins[MARGINRIGHT]; + + page_height = settings->page_height - settings->margins[MARGINTOP]; + + text_margin = settings->margins[MARGINTEXT]; + +// 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() +{ +#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); + + pdf_page_apply_notext_clip(); + + page_clipped = false; + +#ifdef PDF_DEBUG + LOG(("%f %f", page_width, page_height)); +#endif + + return true; +} + + +void pdf_end() +{ +#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 + + /*TODO: if false notify user*/ + if (settings->output) + HPDF_SaveToFile(pdf_doc, settings->output); + + + HPDF_Free(pdf_doc); + +#ifdef PDF_DEBUG + LOG(("pdf_end finishes")); +#endif +} + + +/** + * 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 + +/** + * A solution for fuzzy margins - saves the current clipping and puts the main + * clip frame (page without margins) over it. +*/ +void pdf_page_apply_notext_clip() +{ + /*Save state underneath*/ + HPDF_Page_GSave(pdf_page); + + /*Apply no-text clipping (stadard page)*/ + HPDF_Page_Rectangle(pdf_page, + 0, + text_margin + settings->margins[MARGINBOTTOM], + page_width, + page_height - settings->margins[MARGINTOP] - text_margin); + + HPDF_Page_Clip(pdf_page); + +#ifdef PDF_DEBUG + HPDF_Page_Stroke(pdf_page); +#else + HPDF_Page_EndPath(pdf_page); +#endif +} + + diff --git a/pdf/pdf_plotters.h b/pdf/pdf_plotters.h new file mode 100644 index 000000000..874518980 --- /dev/null +++ b/pdf/pdf_plotters.h @@ -0,0 +1,40 @@ +/* + * 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" +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); + +#endif /*NETSURF_PDF_PLOTTERS_H*/ diff --git a/pdf/pdf_printer.h b/pdf/pdf_printer.h new file mode 100644 index 000000000..a8d7d7466 --- /dev/null +++ b/pdf/pdf_printer.h @@ -0,0 +1,36 @@ +/* + * 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 Plotter and flow manipulating functions combined as a printer +*/ + +#ifndef NETSURF_PDF_PRINTER_H +#define NETSURF_PDF_PRINTER_H + +#include "desktop/printer.h" +#include "pdf/pdf_plotters.h" + +struct printer pdf_printer= { + &pdf_plotters, + pdf_begin, + pdf_next_page, + pdf_end +}; + +#endif -- cgit v1.2.3