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
This commit is contained in:
John Tytgat 2008-07-26 16:01:59 +00:00
parent 9fb65c7096
commit 35d3d6d0bb
59 changed files with 3529 additions and 158 deletions

View File

@ -894,7 +894,7 @@ INCLUDE_FILE_PATTERNS =
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed.
PREDEFINED = riscos CSS_INTERNALS WITH_ARTWORKS WITH_AUTH WITH_BMP WITH_DRAW WITH_DRAW_EXPORT WITH_GIF WITH_JPEG WITH_MMAP WITH_MNG WITH_NSSPRITE WITH_NS_SVG WITH_PLUGIN WITH_PRINT WITH_RSVG WITH_SAVE_COMPLETE WITH_SEARCH WITH_SPRITE WITH_SSL WITH_THEME_INSTALL WITH_URI WITH_URL
PREDEFINED = riscos CSS_INTERNALS WITH_ARTWORKS WITH_AUTH WITH_BMP WITH_DRAW WITH_DRAW_EXPORT WITH_GIF WITH_JPEG WITH_MMAP WITH_MNG WITH_NSSPRITE WITH_NS_SVG WITH_PLUGIN WITH_PRINT WITH_RSVG WITH_SAVE_COMPLETE WITH_SEARCH WITH_SPRITE WITH_SSL WITH_THEME_INSTALL WITH_URI WITH_URL WITH_PDF_EXPORT
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.

View File

@ -114,6 +114,10 @@ SUBTARGET := -aof
EXEEXT := ,ff8
endif
PKG_CONFIG := $(GCCSDK_INSTALL_ENV)/ro-pkg-config
CCACHE := $(shell which ccache)
ifneq ($(CCACHE),)
CC := $(CCACHE) $(CC)
endif
endif
else
ifeq ($(TARGET),beos)
@ -145,15 +149,9 @@ LDFLAGS += -lxml2 -lz -lcurl -lssl -lcrypto -ljpeg -liconv
LDFLAGS += -lmng -ljpeg
else
LDFLAGS := $(shell $(PKG_CONFIG) --libs libxml-2.0 libcurl openssl)
LDFLAGS += -lz -lm -lmng -ljpeg
CCACHE := $(shell which ccache)
ifneq ($(CCACHE),)
CC := $(CCACHE) $(CC)
endif
endif
# Common libraries without pkgconfig support:
LDFLAGS += -lz -lm -lmng -ljpeg -lhpdf -lpng
endif
ifeq ($(TARGET),gtk)
@ -170,7 +168,10 @@ GTKCFLAGS := -std=c99 -Dgtk -Dnsgtk \
$(shell $(PKG_CONFIG) --cflags librosprite) \
$(shell xml2-config --cflags)
#GTKLDFLAGS := $(shell $(PKG_CONFIG) --cflags --libs libglade-2.0 gtk+-2.0 gthread-2.0 gmodule-2.0 librosprite)
GTKLDFLAGS := $(shell $(PKG_CONFIG) --cflags --libs libglade-2.0 gtk+-2.0 gthread-2.0 gmodule-2.0 librsvg-2.0 librosprite)
#CFLAGS += $(GTKCFLAGS) -g
#LDFLAGS += $(GTKLDFLAGS) $(shell $(PKG_CONFIG) --libs lcms) -lsvgtiny
CFLAGS += $(GTKCFLAGS)
LDFLAGS += $(GTKLDFLAGS) $(shell $(PKG_CONFIG) --libs lcms)

View File

@ -39,7 +39,7 @@ S_RISCOS := 401login.c artworks.c assert.c awrender.s bitmap.c buffer.c \
cookies.c configure.c debugwin.c dialog.c download.c draw.c filetype.c \
font.c global_history.c gui.c help.c history.c hotlist.c image.c \
menus.c message.c palettes.c plotters.c plugin.c print.c query.c \
save.c save_complete.c save_draw.c schedule.c search.c sprite.c \
save.c save_complete.c save_draw.c save_pdf.c schedule.c search.c sprite.c \
sslcert.c textarea.c textselection.c theme.c theme_install.c \
thumbnail.c \
treeview.c ucstables.c uri.c url_complete.c url_protocol.c wimp.c wimp_event.c \
@ -58,9 +58,16 @@ S_DIALOGS := $(addprefix gtk/dialogs/,$(S_DIALOGS))
S_GTK := font_pango.c gtk_bitmap.c gtk_gui.c gtk_schedule.c \
gtk_thumbnail.c gtk_plotters.c gtk_treeview.c gtk_scaffolding.c \
gtk_completion.c gtk_login.c gtk_throbber.c gtk_selection.c \
gtk_history.c gtk_window.c gtk_filetype.c gtk_download.c
gtk_history.c gtk_window.c gtk_filetype.c gtk_download.c gtk_print.c
S_GTK := $(addprefix gtk/,$(S_GTK))
# S_PDF are sources of the pdf plotter + the ones for paged-printing
S_PDF := pdf_plotters.c font_haru.c
S_PRINT := print.c
S_LOOSE := loosen.c
S_PDF := $(addprefix pdf/,$(S_PDF)) $(addprefix desktop/,$(S_PRINT)) \
$(addprefix render/,$(S_LOOSE))
# S_BEOS are sources purely for the BeOS build
S_BEOS := beos_bitmap.cpp beos_fetch_rsrc.cpp beos_filetype.cpp beos_font.cpp \
beos_gui.cpp beos_history.cpp beos_login.cpp beos_options.cpp \
@ -122,12 +129,12 @@ CLEANS += clean-intermediates
# Finally select the correct set of sources for this build...
ifeq ($(TARGET),riscos)
SOURCES := $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_RISCOS)
SOURCES := $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_PDF) $(S_RISCOS)
EXETARGET := !NetSurf/!RunImage$(EXEEXT)
endif
ifeq ($(TARGET),gtk)
SOURCES := $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_GTK) $(S_DIALOGS)
SOURCES := $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_PDF) $(S_GTK) $(S_DIALOGS)
EXETARGET := nsgtk
endif

View File

@ -44,6 +44,21 @@ extern "C" {
static void nsfont_style_to_font(BFont &font,
const struct css_style *style);
static bool nsfont_width(const struct css_style *style,
const char *string, size_t length,
int *width);
static bool 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 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 nsfont = {
nsfont_width,
nsfont_position_in_string,
nsfont_split
};
/**
* Measure the width of a string.

View File

@ -1442,7 +1442,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
int pixel_offset;
size_t idx;
nsfont_position_in_string(text_box->style,
nsfont.font_position_in_string(text_box->style,
text_box->text,
text_box->length,
x - gadget_box_x - text_box->x,
@ -1483,7 +1483,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
BROWSER_MOUSE_DRAG_2))
selection_init(bw->sel, gadget_box);
nsfont_position_in_string(text_box->style,
nsfont.font_position_in_string(text_box->style,
text_box->text,
text_box->length,
x - gadget_box_x - text_box->x,
@ -1573,7 +1573,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
int pixel_offset;
size_t idx;
nsfont_position_in_string(text_box->style,
nsfont.font_position_in_string(text_box->style,
text_box->text,
text_box->length,
x - text_box_x,
@ -1836,8 +1836,7 @@ void browser_window_mouse_track_html(struct browser_window *bw,
if (box) {
int pixel_offset;
size_t idx;
nsfont_position_in_string(box->style,
nsfont.font_position_in_string(box->style,
box->text, box->length,
dx, &idx, &pixel_offset);
@ -1917,7 +1916,7 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
box = browser_window_pick_text_box(bw,
x, y, dir, &dx, &dy);
if (box) {
nsfont_position_in_string(
nsfont.font_position_in_string(
box->style,
box->text,
box->length,

View File

@ -27,6 +27,7 @@
typedef enum {
GUI_SAVE_SOURCE,
GUI_SAVE_DRAW,
GUI_SAVE_PDF,
GUI_SAVE_TEXT,
GUI_SAVE_COMPLETE,
GUI_SAVE_OBJECT_ORIG,

View File

@ -597,13 +597,13 @@ bool history_redraw_entry(struct history *history,
int tailsize = 5;
if (!plot.bitmap(entry->x, entry->y, WIDTH, HEIGHT,
entry->bitmap, 0xffffff))
entry->bitmap, 0xffffff, NULL))
return false;
if (!plot.rectangle(entry->x - 1, entry->y - 1, WIDTH + 1, HEIGHT + 1,
entry == history->current ? 2 : 1, c, false, false))
return false;
if (!nsfont_position_in_string(&css_base_style, entry->page.title,
if (!nsfont.font_position_in_string(&css_base_style, entry->page.title,
strlen(entry->page.title), WIDTH,
&char_offset, &actual_x))
return false;

View File

@ -61,10 +61,10 @@ static bool knockout_plot_disc(int x, int y, int radius, colour colour, bool fil
static bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2,
colour c);
static bool knockout_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg);
struct bitmap *bitmap, colour bg, struct content *content);
static bool knockout_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y);
bool repeat_x, bool repeat_y, struct content *content);
static bool knockout_plot_group_start(const char *name);
static bool knockout_plot_group_end(void);
@ -194,6 +194,7 @@ struct knockout_entry {
int height;
struct bitmap *bitmap;
colour bg;
struct content *content;
} bitmap;
struct {
int x;
@ -204,6 +205,7 @@ struct knockout_entry {
colour bg;
bool repeat_x;
bool repeat_y;
struct content *content;
} bitmap_tile;
struct {
const char *name;
@ -379,7 +381,8 @@ bool knockout_plot_flush(void)
knockout_entries[i].data.bitmap.width,
knockout_entries[i].data.bitmap.height,
knockout_entries[i].data.bitmap.bitmap,
knockout_entries[i].data.bitmap.bg);
knockout_entries[i].data.bitmap.bg,
knockout_entries[i].data.bitmap.content);
break;
case KNOCKOUT_PLOT_BITMAP_TILE:
box = knockout_entries[i].box->child;
@ -403,7 +406,9 @@ bool knockout_plot_flush(void)
knockout_entries[i].data.
bitmap_tile.repeat_x,
knockout_entries[i].data.
bitmap_tile.repeat_y);
bitmap_tile.repeat_y,
knockout_entries[i].data.
bitmap_tile.content);
}
break;
case KNOCKOUT_PLOT_GROUP_START:
@ -608,7 +613,8 @@ bool knockout_plot_bitmap_tile_recursive(struct knockout_box *box,
entry->data.bitmap_tile.bitmap,
entry->data.bitmap_tile.bg,
entry->data.bitmap_tile.repeat_x,
entry->data.bitmap_tile.repeat_y);
entry->data.bitmap_tile.repeat_y,
entry->data.bitmap_tile.content);
}
}
return success;
@ -802,7 +808,7 @@ bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, colour
}
bool knockout_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg)
struct bitmap *bitmap, colour bg, struct content *content)
{
int kx0, ky0, kx1, ky1;
@ -824,6 +830,7 @@ bool knockout_plot_bitmap(int x, int y, int width, int height,
knockout_entries[knockout_entry_cur].data.bitmap.height = height;
knockout_entries[knockout_entry_cur].data.bitmap.bitmap = bitmap;
knockout_entries[knockout_entry_cur].data.bitmap.bg = bg;
knockout_entries[knockout_entry_cur].data.bitmap.content = content;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_BITMAP;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
@ -833,7 +840,7 @@ bool knockout_plot_bitmap(int x, int y, int width, int height,
bool knockout_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y)
bool repeat_x, bool repeat_y, struct content *content)
{
int kx0, ky0, kx1, ky1;
@ -879,6 +886,7 @@ bool knockout_plot_bitmap_tile(int x, int y, int width, int height,
knockout_entries[knockout_entry_cur].data.bitmap_tile.bg = bg;
knockout_entries[knockout_entry_cur].data.bitmap_tile.repeat_x = repeat_x;
knockout_entries[knockout_entry_cur].data.bitmap_tile.repeat_y = repeat_y;
knockout_entries[knockout_entry_cur].data.bitmap_tile.content = content;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_BITMAP_TILE;
if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) ||
(++knockout_box_cur >= KNOCKOUT_BOXES))

View File

@ -25,6 +25,7 @@
#include <stdbool.h>
#include "css/css.h"
#include "content/content.h"
struct bitmap;
@ -46,10 +47,11 @@ struct plotter_table {
bool (*arc)(int x, int y, int radius, int angle1, int angle2,
colour c);
bool (*bitmap)(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg);
struct bitmap *bitmap, colour bg,
struct content *content);
bool (*bitmap_tile)(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y);
bool repeat_x, bool repeat_y, struct content *content);
bool (*group_start)(const char *name); /** optional */
bool (*group_end)(void); /** optional */
bool (*flush)(void);

280
desktop/print.c Normal file
View File

@ -0,0 +1,280 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Output-in-pages implementation
*/
#include "desktop/print.h"
#include "desktop/printer.h"
#include "content/content.h"
#include "utils/log.h"
#include "utils/talloc.h"
#include "render/loosen.h"
#include "render/box.h"
#include "pdf/font_haru.h"
static struct content *print_init(struct content *, struct print_settings *);
static bool print_apply_settings(struct content *, struct print_settings *);
/*TODO: should these be passed as parameters in order to allow simultaneous
printings?
*/
static float page_content_width, page_content_height;
static float text_margin_height;
static struct content *printed_content;
static float done_height;
/**
* This function calls print setup, prints page after page until the whole
* content is printed calls cleaning up afterwise.
* \param content The content to be printed
* \param printer The printer interface for the printer to be used
* \param settings The settings for printing to use or NULL for DEFAULT
* \return true if successful, false otherwise
*/
bool print_basic_run(struct content *content,
const struct printer *printer,
struct print_settings *settings)
{
bool ret = true;
if (settings == NULL)
settings = print_make_settings(DEFAULT);
if (!print_set_up(content, printer, settings, NULL))
ret = false;
while (ret && (done_height < printed_content->height) )
ret = print_draw_next_page(printer, settings);
print_cleanup(content, printer);
return ret;
}
/**
* This function prepares the content to be printed. The current browser content
* is duplicated and resized, printer initialization is called.
* \param content The content to be printed
* \param printer The printer interface for the printer to be used
* \param settings The settings for printing to use
* \param height updated to the height of the printed content
* \return true if successful, false otherwise
*/
bool print_set_up(struct content *content,
const struct printer *printer, struct print_settings *settings,
double *height)
{
printed_content = print_init(content, settings);
if (!printed_content)
return false;
print_apply_settings(printed_content, settings);
if (height)
*height = printed_content->height;
printer->print_begin(settings);
done_height = 0;
return true;
}
/**
* This function draws one page, beginning with the height offset of done_height
* \param printer The printer interface for the printer to be used
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings)
{
/*TODO:Plotter will have to be duplicated and passed
as an argument - to allow simultaneous screen and
page plotting*/
plot = *(printer->plotter);
printer->print_next_page();
if( !content_redraw(printed_content,
0,
-done_height,
0,0,
0,
0,
page_content_width * settings->scale,
page_content_height * settings->scale,
settings->scale, 0xffffff))
return false;
done_height += page_content_height - text_margin_height;
return true;
}
/**
* The content passed to the function is duplicated with its boxes, font
* measuring functions are being set.
* \param content The content to be printed
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
struct content *print_init(struct content *content,
struct print_settings *settings)
{
struct content* printed_content;
struct content_user *user_sentinel;
content_add_user(content, NULL, (intptr_t)print_init, 0);
printed_content = talloc_memdup(content, content, sizeof *content);
if (!printed_content)
return NULL;
printed_content->data.html.bw = 0;
user_sentinel = talloc(printed_content, struct content_user);
user_sentinel->callback = 0;
user_sentinel->p1 = user_sentinel->p2 = 0;
user_sentinel->next = 0;
printed_content->user_list = user_sentinel;
content_add_user(printed_content, NULL, (intptr_t)print_init, 0);
printed_content->data.html.layout =
box_duplicate_tree(content->data.html.layout,
printed_content);
if (!printed_content->data.html.layout)
return NULL;
if (settings->font_func == NULL)
printed_content->data.html.font_func = &haru_nsfont;
else
printed_content->data.html.font_func = settings->font_func;
return printed_content;
}
/**
* The content is resized to fit page width. In case it is to wide, it is
* loosened.
* \param content The content to be printed
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
bool print_apply_settings(struct content *content,
struct print_settings *settings)
{
if (settings == NULL)
return false;
/*Apply settings - adjust page size etc*/
text_margin_height = settings->margins[MARGINTEXT];
page_content_width = (settings->page_width - settings->margins[MARGINLEFT] -
settings->margins[MARGINRIGHT]) / settings->scale;
page_content_height = (settings->page_height - settings->margins[MARGINTOP] -
settings->margins[MARGINBOTTOM]) / settings->scale;
content_reformat(content, page_content_width, 0);
LOG(("New layout applied.New height = %d ; New width = %d ",
content->height, content->width));
if (content->width > page_content_width)
return loosen_document_layout(content, content->data.html.layout,
page_content_width, page_content_height);
return true;
}
/**
* Memory allocated during printing is being freed here.
* \param content The original content
* \param printer The printer interface for the printer to be used
* \return true if successful, false otherwise
*/
bool print_cleanup(struct content *content,
const struct printer *printer)
{
printer->print_end();
if (printed_content) {
content_remove_user(printed_content, NULL, (intptr_t)print_init, 0);
talloc_free(printed_content);
}
content_remove_user(content, NULL, (intptr_t)print_init, 0);
return true;
}
/**
* Generates one of the predefined print settings sets.
* \return print_settings in case if successful, NULL if unknown configuration \
* or lack of memory.
*/
struct print_settings *print_make_settings(print_configuration configuration)
{
struct print_settings *settings;
switch (configuration){
case DEFAULT:
settings = (struct print_settings*)
malloc(sizeof (struct print_settings) );
if (settings == NULL)
return NULL;
settings->page_width = 595;
settings->page_height = 840;
settings->copies = 1;
/*with 0.7 the pages look the best, the value in
haru_nsfont_apply_style should be kept the same as this
*/
settings->scale = 0.7;
settings->margins[MARGINLEFT] = 30;
settings->margins[MARGINRIGHT] = 30;
settings->margins[MARGINTOP] = 30;
settings->margins[MARGINBOTTOM] = 30;
settings->margins[MARGINTEXT] = 10;
settings->output = "out.pdf";
settings->font_func = &haru_nsfont;
break;
default:
return NULL;
}
return settings;
}

75
desktop/print.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Conception:
* Generalized output-in-pages. Allows the current content to be 'printed':
* either into a pdf file (any other later?) or to any kind of other output
* destination that divides the website into pages - as a printer.
* The basic usage is calling print_basic_run which sets everything up,
* prints page after page until the whole content is printed and cleans
* everyting up.
* If there are any other, printer specific routines to be performed in the
* meantime - there can be set up any other printing funcion, which can use
* print_set_up, print_draw_next_page and print_cleanup directly.
*/
#ifndef NETSURF_DESKTOP_PRINT_H
#define NETSURF_DESKTOP_PRINT_H
#include <stdbool.h>
struct content;
struct printer;
enum { MARGINLEFT = 0, MARGINRIGHT = 1, MARGINTOP = 2, MARGINBOTTOM = 3,
MARGINTEXT = 4};
/** Predefined printing configuration names*/
typedef enum {DEFAULT} print_configuration;
/** Settings for a print - filled in by print_make_settings or
* 'manually' by the caller
*/
struct print_settings{
/*Standard parameters*/
float page_width, page_height;
float margins[5];
float scale;
unsigned int copies;
/*Output destinations - file/printer name*/
const char *output;
/*TODO: more options?*/
const struct font_functions *font_func;
};
bool print_basic_run(struct content *, const struct printer *, struct print_settings *);
bool print_set_up(struct content *content,
const struct printer *printer, struct print_settings *settings,
double *height);
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings);
bool print_cleanup(struct content *, const struct printer *);
struct print_settings *print_make_settings(print_configuration configuration);
#endif

41
desktop/printer.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Printer interface - contains plotter to use, functions for
* initialization, handling pages and cleaning up.
*/
#ifndef NETSURF_DESKTOP_PRINTER_H
#define NETSURF_DESKTOP_PRINTER_H
#include "desktop/plotters.h"
#include "desktop/print.h"
/** Printer interface */
struct printer{
const struct plotter_table *plotter;
bool (*print_begin) (struct print_settings*);
bool (*print_next_page)(void);
void (*print_end)(void);
};
#endif

View File

@ -601,7 +601,7 @@ bool redraw_handler(const char *text, size_t length, struct box *box,
height = box->padding[TOP] + box->height + box->padding[BOTTOM];
if (box->type == BOX_TEXT && box->space &&
nsfont_width(box->style, " ", 1, &space_width))
nsfont.font_width(box->style, " ", 1, &space_width))
width += space_width;
if (r->inited) {

View File

@ -181,7 +181,7 @@ struct box *textarea_get_position(struct box *textarea, int x, int y,
assert(text_box->type == BOX_TEXT);
assert(text_box->text);
/** \todo handle errors */
nsfont_position_in_string(text_box->style, text_box->text,
nsfont.font_position_in_string(text_box->style, text_box->text,
text_box->length,
(unsigned int)(x - text_box->x),
(size_t *) pchar_offset, ppixel_offset);
@ -203,7 +203,7 @@ struct box *textarea_get_position(struct box *textarea, int x, int y,
text_box = inline_container->last;
assert(text_box->type == BOX_TEXT);
assert(text_box->text);
nsfont_position_in_string(text_box->style,
nsfont.font_position_in_string(text_box->style,
text_box->text,
text_box->length,
textarea->width,
@ -223,7 +223,7 @@ struct box *textarea_get_position(struct box *textarea, int x, int y,
}
assert(text_box->type == BOX_TEXT);
assert(text_box->text);
nsfont_position_in_string(text_box->style,
nsfont.font_position_in_string(text_box->style,
text_box->text,
text_box->length,
(unsigned int)(x - text_box->x),
@ -761,7 +761,7 @@ bool browser_window_textarea_callback(struct browser_window *bw,
}
}
nsfont_width(text_box->style, text_box->text,
nsfont.font_width(text_box->style, text_box->text,
char_offset, &pixel_offset);
selection_clear(bw->sel, true);
@ -813,7 +813,7 @@ void browser_window_input_click(struct browser_window* bw,
int pixel_offset = 0, dx = 0;
struct box *text_box = input->children->children;
nsfont_position_in_string(text_box->style, text_box->text,
nsfont.font_position_in_string(text_box->style, text_box->text,
text_box->length, x - text_box->x,
&char_offset, &pixel_offset);
assert(char_offset <= text_box->length);
@ -1375,7 +1375,7 @@ bool browser_window_textarea_paste_text(struct browser_window *bw,
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_box_offset = char_offset;
nsfont_width(text_box->style, text_box->text,
nsfont.font_width(text_box->style, text_box->text,
char_offset, &pixel_offset);
textarea->gadget->caret_pixel_offset = pixel_offset;
@ -1508,7 +1508,7 @@ void browser_window_textarea_move_caret(struct browser_window *bw, void *p)
box_x -= textarea->scroll_x;
box_y -= textarea->scroll_y;
nsfont_width(text_box->style, text_box->text,
nsfont.font_width(text_box->style, text_box->text,
char_offset, &pixel_offset);
browser_window_place_caret(bw,
@ -1541,7 +1541,7 @@ void browser_window_input_move_caret(struct browser_window *bw, void *p)
box_coords(input, &box_x, &box_y);
nsfont_width(text_box->style, text_box->text, box_offset,
nsfont.font_width(text_box->style, text_box->text, box_offset,
&pixel_offset);
browser_window_place_caret(bw,
@ -1576,12 +1576,12 @@ void input_update_display(struct browser_window *bw, struct box *input,
int dx;
if (redraw)
nsfont_width(text_box->style, text_box->text, text_box->length,
nsfont.font_width(text_box->style, text_box->text, text_box->length,
&text_box->width);
box_coords(input, &box_x, &box_y);
nsfont_width(text_box->style, text_box->text, box_offset,
nsfont.font_width(text_box->style, text_box->text, box_offset,
(int *) &pixel_offset);
/* Shift text box horizontally, so caret is visible */

View File

@ -37,8 +37,26 @@
/* Until we can consider the descenders etc, we need to not render using cairo */
#undef CAIRO_VERSION
static PangoFontDescription *nsfont_style_to_description(
const struct css_style *style);
static bool nsfont_width(const struct css_style *style,
const char *string, size_t length,
int *width);
static bool 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 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 nsfont = {
nsfont_width,
nsfont_position_in_string,
nsfont_split
};
/**
@ -203,11 +221,11 @@ bool nsfont_paint(const struct css_style *style,
{
PangoFontDescription *desc;
PangoLayout *layout;
PangoLayoutLine *line;
gint size;
#ifdef CAIRO_VERSION
int width, height;
#else
PangoLayoutLine *line;
#else
PangoContext *context;
GdkColor colour = { 0,
((c & 0xff) << 8) | (c & 0xff),
@ -234,14 +252,13 @@ bool nsfont_paint(const struct css_style *style,
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, string, length);
#ifdef CAIRO_VERSION
pango_layout_get_pixel_size(layout, &width, &height);
cairo_move_to(current_cr, x, y - height);
nsgtk_set_colour(c);
pango_cairo_show_layout(current_cr, layout);
#else
line = pango_layout_get_line(layout, 0);
#ifdef CAIRO_VERSION
cairo_move_to(current_cr, x, y);
nsgtk_set_colour(c);
pango_cairo_show_layout_line(current_cr, layout, line);
#else
gdk_draw_layout_line_with_colors(current_drawable, current_gc,
x, y, line, &colour, 0);
@ -350,3 +367,4 @@ PangoFontDescription *nsfont_style_to_description(
return desc;
}

View File

@ -20,6 +20,9 @@
* Font handling (GTK interface).
*/
#ifndef _NETSURF_GTK_FONT_PANGO_H_
#define _NETSURF_GTK_FONT_PANGO_H_
#include <stdbool.h>
@ -28,3 +31,9 @@ struct css_style;
bool nsfont_paint(const struct css_style *style,
const char *string, size_t length,
int x, int y, colour c);
PangoFontDescription *nsfont_style_to_description(
const struct css_style *style);
#endif

View File

@ -211,6 +211,14 @@ void bitmap_set_suspendable(struct bitmap *bitmap, void *private_word,
void (*invalidate)(struct bitmap *bitmap, void *private_word)) {
}
int bitmap_get_width(struct bitmap *bitmap){
return gdk_pixbuf_get_width(bitmap->primary);
}
int bitmap_get_height(struct bitmap *bitmap){
return gdk_pixbuf_get_height(bitmap->primary);
}
static GdkPixbuf *
gtk_bitmap_generate_pretile(GdkPixbuf *primary, int repeat_x, int repeat_y)
{

View File

@ -65,10 +65,10 @@ static bool nsgtk_plot_disc(int x, int y, int radius, colour c, bool filled);
static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2,
colour c);
static bool nsgtk_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg);
struct bitmap *bitmap, colour bg, struct content *content);
static bool nsgtk_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y);
bool repeat_x, bool repeat_y, struct content *content);
static void nsgtk_set_solid(void); /**< Set for drawing solid lines */
static void nsgtk_set_dotted(void); /**< Set for drawing dotted lines */
static void nsgtk_set_dashed(void); /**< Set for drawing dashed lines */
@ -281,7 +281,7 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
}
bool nsgtk_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg)
struct bitmap *bitmap, colour bg, struct content *content)
{
GdkPixbuf *pixbuf = gtk_bitmap_get_primary(bitmap);
return nsgtk_plot_pixbuf(x, y, width, height, pixbuf, bg);
@ -289,7 +289,7 @@ bool nsgtk_plot_bitmap(int x, int y, int width, int height,
bool nsgtk_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y)
bool repeat_x, bool repeat_y, struct content *content)
{
int doneheight = 0, donewidth = 0;
GdkPixbuf *primary;
@ -297,7 +297,7 @@ bool nsgtk_plot_bitmap_tile(int x, int y, int width, int height,
if (!(repeat_x || repeat_y)) {
/* Not repeating at all, so just pass it on */
return nsgtk_plot_bitmap(x,y,width,height,bitmap,bg);
return nsgtk_plot_bitmap(x,y,width,height,bitmap,bg,content);
}
if (repeat_x && !repeat_y)

View File

@ -42,3 +42,4 @@ void nsgtk_set_colour(colour c);
void nsgtk_plot_caret(int x, int y, int h);
#endif /* NETSURF_GTK_PLOTTERS_H */

573
gtk/gtk_print.c Normal file
View File

@ -0,0 +1,573 @@
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* GTK printing (implementation).
* All the functions and structures necessary for printing( signal handlers,
* plotters, printer) are here.
* Most of the plotters have been copied from the gtk_plotters.c file.
*/
#include <math.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include "desktop/plotters.h"
#include "gtk/font_pango.h"
#include "gtk/gtk_scaffolding.h"
#include "render/font.h"
#include "utils/log.h"
#include "desktop/options.h"
#include "gtk/options.h"
#include "gtk/gtk_bitmap.h"
#include "desktop/print.h"
#include "desktop/printer.h"
#include "content/content.h"
#include "gtk_print.h"
#include "utils/utils.h"
cairo_t *gtk_print_current_cr;
static struct print_settings* settings;
struct content *content_to_print;
static bool nsgtk_print_plot_clg(colour c);
static bool nsgtk_print_plot_rectangle(int x0, int y0, int width, int height,
int line_width, colour c, bool dotted, bool dashed);
static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, int width,
colour c, bool dotted, bool dashed);
static bool nsgtk_print_plot_polygon(int *p, unsigned int n, colour fill);
static bool nsgtk_print_plot_path(float *p, unsigned int n, colour fill, float width,
colour c, float *transform);
static bool nsgtk_print_plot_fill(int x0, int y0, int x1, int y1, colour c);
static bool nsgtk_print_plot_clip(int clip_x0, int clip_y0,
int clip_x1, int clip_y1);
static bool nsgtk_print_plot_text(int x, int y, const struct css_style *style,
const char *text, size_t length, colour bg, colour c);
static bool nsgtk_print_plot_disc(int x, int y, int radius, colour c, bool filled);
static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2,
colour c);
static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg, struct content *content);
static bool nsgtk_print_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 void nsgtk_print_set_solid(void); /**< Set for drawing solid lines */
static void nsgtk_print_set_dotted(void); /**< Set for drawing dotted lines */
static void nsgtk_print_set_dashed(void); /**< Set for drawing dashed lines */
static void nsgtk_print_set_colour(colour c);
static void nsgtk_print_plot_caret(int x, int y, int h);
static bool gtk_print_font_paint(const struct css_style *style,
const char *string, size_t length,
int x, int y, colour c);
static bool gtk_print_begin(struct print_settings* settings);
static bool gtk_print_next_page(void);
static void gtk_print_end(void);
static GdkRectangle cliprect;
struct plotter_table plot;
static const struct plotter_table nsgtk_print_plotters = {
nsgtk_print_plot_clg,
nsgtk_print_plot_rectangle,
nsgtk_print_plot_line,
nsgtk_print_plot_polygon,
nsgtk_print_plot_fill,
nsgtk_print_plot_clip,
nsgtk_print_plot_text,
nsgtk_print_plot_disc,
nsgtk_print_plot_arc,
nsgtk_print_plot_bitmap,
nsgtk_print_plot_bitmap_tile,
NULL,
NULL,
NULL,
nsgtk_print_plot_path
};
static const struct printer gtk_printer= {
&nsgtk_print_plotters,
gtk_print_begin,
gtk_print_next_page,
gtk_print_end
};
bool nsgtk_print_plot_clg(colour c)
{
return true;
}
bool nsgtk_print_plot_rectangle(int x0, int y0, int width, int height,
int line_width, colour c, bool dotted, bool dashed)
{
LOG(("Plotting rectangle. width: %i ; height: %i", width, height));
nsgtk_print_set_colour(c);
if (dotted)
nsgtk_print_set_dotted();
else if (dashed)
nsgtk_print_set_dashed();
else
nsgtk_print_set_solid();
if (line_width == 0)
line_width = 1;
cairo_set_line_width(gtk_print_current_cr, line_width);
cairo_rectangle(gtk_print_current_cr, x0, y0, width, height);
cairo_stroke(gtk_print_current_cr);
return true;
}
bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, int width,
colour c, bool dotted, bool dashed)
{
nsgtk_print_set_colour(c);
if (dotted)
nsgtk_print_set_dotted();
else if (dashed)
nsgtk_print_set_dashed();
else
nsgtk_print_set_solid();
if (width == 0)
width = 1;
cairo_set_line_width(gtk_print_current_cr, width);
cairo_move_to(gtk_print_current_cr, x0, y0 - 0.5);
cairo_line_to(gtk_print_current_cr, x1, y1 - 0.5);
cairo_stroke(gtk_print_current_cr);
return true;
}
bool nsgtk_print_plot_polygon(int *p, unsigned int n, colour fill)
{
LOG(("Plotting polygon."));
unsigned int i;
nsgtk_print_set_colour(fill);
nsgtk_print_set_solid();
cairo_set_line_width(gtk_print_current_cr, 0);
cairo_move_to(gtk_print_current_cr, p[0], p[1]);
LOG(("Starting line at: %i\t%i",p[0],p[1]));
for (i = 1; i != n; i++) {
cairo_line_to(gtk_print_current_cr, p[i * 2], p[i * 2 + 1]);
LOG(("Drawing line to: %i\t%i",p[i * 2], p[i * 2 + 1]));
}
cairo_fill(gtk_print_current_cr);
cairo_stroke(gtk_print_current_cr);
return true;
}
bool nsgtk_print_plot_fill(int x0, int y0, int x1, int y1, colour c)
{
LOG(("Plotting fill. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", x0,y0,x1,y1));
nsgtk_print_set_colour(c);
nsgtk_print_set_solid();
/*Normalize boundaries of the area - to prevent overflows.
See comment in pdf_plot_fill.
*/
x0 = min(max(x0, 0), settings->page_width);
y0 = min(max(y0, 0), settings->page_height);
x1 = min(max(x1, 0), settings->page_width);
y1 = min(max(y1, 0), settings->page_height);
cairo_set_line_width(gtk_print_current_cr, 0);
cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0);
cairo_fill(gtk_print_current_cr);
cairo_stroke(gtk_print_current_cr);
return true;
}
bool nsgtk_print_plot_clip(int clip_x0, int clip_y0,
int clip_x1, int clip_y1)
{
LOG(("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i",
clip_x0,clip_y0,clip_x1,clip_y1));
/*Normalize cllipping area - to prevent overflows.
See comment in pdf_plot_fill.
*/
clip_x0 = min(max(clip_x0, 0), settings->page_width);
clip_y0 = min(max(clip_y0, 0), settings->page_height);
clip_x1 = min(max(clip_x1, 0), settings->page_width);
clip_y1 = min(max(clip_y1, 0), settings->page_height);
cairo_reset_clip(gtk_print_current_cr);
cairo_rectangle(gtk_print_current_cr, clip_x0, clip_y0,
clip_x1 - clip_x0, clip_y1 - clip_y0);
cairo_clip(gtk_print_current_cr);
cliprect.x = clip_x0;
cliprect.y = clip_y0;
cliprect.width = clip_x1 - clip_x0;
cliprect.height = clip_y1 - clip_y0;
// gdk_gc_set_clip_rectangle(gtk_print_current_gc, &cliprect);
return true;
}
bool nsgtk_print_plot_text(int x, int y, const struct css_style *style,
const char *text, size_t length, colour bg, colour c)
{
return gtk_print_font_paint(style, text, length, x, y, c);
}
bool nsgtk_print_plot_disc(int x, int y, int radius, colour c, bool filled)
{
nsgtk_print_set_colour(c);
nsgtk_print_set_solid();
if (filled)
cairo_set_line_width(gtk_print_current_cr, 0);
else
cairo_set_line_width(gtk_print_current_cr, 1);
cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2);
if (filled)
cairo_fill(gtk_print_current_cr);
cairo_stroke(gtk_print_current_cr);
return true;
}
bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2, colour c)
{
nsgtk_print_set_colour(c);
nsgtk_print_set_solid();
cairo_set_line_width(gtk_print_current_cr, 1);
cairo_arc(gtk_print_current_cr, x, y, radius,
(angle1 + 90) * (M_PI / 180),
(angle2 + 90) * (M_PI / 180));
cairo_stroke(gtk_print_current_cr);
return true;
}
static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height,
GdkPixbuf *pixbuf, colour bg)
{
/* XXX: This currently ignores the background colour supplied.
* Does this matter?
*/
if (width == 0 || height == 0)
return true;
if (gdk_pixbuf_get_width(pixbuf) == width &&
gdk_pixbuf_get_height(pixbuf) == height) {
gdk_cairo_set_source_pixbuf(gtk_print_current_cr, pixbuf, x, y);
cairo_paint(gtk_print_current_cr);
} else {
GdkPixbuf *scaled;
scaled = gdk_pixbuf_scale_simple(pixbuf,
width, height,
/* plotting for the printer doesn't have to be fast
* so we can use always the interp_style
* that gives better quality
*/
GDK_INTERP_BILINEAR
);
if (!scaled)
return false;
gdk_cairo_set_source_pixbuf(gtk_print_current_cr, scaled, x, y);
cairo_paint(gtk_print_current_cr);
g_object_unref(scaled);
}
return true;
}
bool nsgtk_print_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg, struct content *content)
{
GdkPixbuf *pixbuf = gtk_bitmap_get_primary(bitmap);
return nsgtk_print_plot_pixbuf(x, y, width, height, pixbuf, bg);
}
bool nsgtk_print_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)
{
int doneheight = 0, donewidth = 0;
GdkPixbuf *primary;
GdkPixbuf *pretiled;
if (!(repeat_x || repeat_y)) {
/* Not repeating at all, so just pass it on */
return nsgtk_print_plot_bitmap(x,y,width,height,bitmap,bg,content);
}
if (repeat_x && !repeat_y)
pretiled = gtk_bitmap_get_pretile_x(bitmap);
if (repeat_x && repeat_y)
pretiled = gtk_bitmap_get_pretile_xy(bitmap);
if (!repeat_x && repeat_y)
pretiled = gtk_bitmap_get_pretile_y(bitmap);
primary = gtk_bitmap_get_primary(bitmap);
/* use the primary and pretiled widths to scale the w/h provided */
width *= gdk_pixbuf_get_width(pretiled);
width /= gdk_pixbuf_get_width(primary);
height *= gdk_pixbuf_get_height(pretiled);
height /= gdk_pixbuf_get_height(primary);
if (y > cliprect.y)
doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
else
doneheight = y;
while (doneheight < (cliprect.y + cliprect.height)) {
if (x > cliprect.x)
donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
else
donewidth = x;
while (donewidth < (cliprect.x + cliprect.width)) {
nsgtk_print_plot_pixbuf(donewidth, doneheight,
width, height, pretiled, bg);
donewidth += width;
if (!repeat_x) break;
}
doneheight += height;
if (!repeat_y) break;
}
return true;
}
bool nsgtk_print_plot_path(float *p, unsigned int n, colour fill, float width,
colour c, float *transform)
{
/* Only the internal SVG renderer uses this plot call currently,
* and the GTK version uses librsvg. Thus, we ignore this complexity,
* and just return true obliviously.
*/
return true;
}
void nsgtk_print_set_colour(colour c)
{
int r, g, b;
GdkColor colour;
r = c & 0xff;
g = (c & 0xff00) >> 8;
b = (c & 0xff0000) >> 16;
colour.red = r | (r << 8);
colour.green = g | (g << 8);
colour.blue = b | (b << 8);
colour.pixel = (r << 16) | (g << 8) | b;
gdk_color_alloc(gdk_colormap_get_system(),
&colour);
// gdk_gc_set_foreground(gtk_print_current_gc, &colour);
cairo_set_source_rgba(gtk_print_current_cr, r / 255.0,
g / 255.0, b / 255.0, 1.0);
}
void nsgtk_print_set_solid()
{
double dashes = 0;
cairo_set_dash(gtk_print_current_cr, &dashes, 0, 0);
}
void nsgtk_print_set_dotted()
{
double cdashes = 1;
gint8 dashes[] = { 1, 1 };
cairo_set_dash(gtk_print_current_cr, &cdashes, 1, 0);
}
void nsgtk_print_set_dashed()
{
double cdashes = 3;
gint8 dashes[] = { 3, 3 };
cairo_set_dash(gtk_print_current_cr, &cdashes, 1, 0);
}
bool gtk_print_font_paint(const struct css_style *style,
const char *string, size_t length,
int x, int y, colour c)
{
PangoFontDescription *desc;
PangoLayout *layout;
gint size;
PangoLayoutLine *line;
int width, height;
if (length == 0)
return true;
desc = nsfont_style_to_description(style);
size = (gint)((double)pango_font_description_get_size(desc) * settings->scale);
if (pango_font_description_get_size_is_absolute(desc))
pango_font_description_set_absolute_size(desc, size);
else
pango_font_description_set_size(desc, size);
layout = pango_cairo_create_layout(gtk_print_current_cr);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, string, length);
line = pango_layout_get_line(layout, 0);
cairo_move_to(gtk_print_current_cr, x, y);
nsgtk_print_set_colour(c);
pango_cairo_show_layout_line(gtk_print_current_cr, line);
g_object_unref(layout);
pango_font_description_free(desc);
return true;
}
static bool gtk_print_begin(struct print_settings* settings)
{
return true;
}
static bool gtk_print_next_page()
{
return true;
}
static void gtk_print_end()
{
}
/** Handle the begin_print signal from the GtkPrintOperation
* \param operation the operation which emited the signal
* \param context the print context used to set up the pages
* \param user_data nothing in here
*/
void gtk_print_signal_begin_print (GtkPrintOperation *operation,
GtkPrintContext *context,
gpointer user_data)
{
int page_number;
double height_on_page, height_to_print;
LOG(("Begin print"));
settings = print_make_settings(DEFAULT);
settings->margins[MARGINTEXT] = 0;
settings->margins[MARGINTOP] = 0;
settings->margins[MARGINLEFT] = 0;
settings->margins[MARGINBOTTOM] = 0;
settings->margins[MARGINRIGHT] = 0;
settings->page_width = gtk_print_context_get_width(context);
settings->page_height = gtk_print_context_get_height(context);
settings->scale = 0.7;
settings->font_func = &nsfont;
print_set_up(content_to_print, &gtk_printer, settings, &height_to_print);
LOG(("page_width: %f ;page_height: %f; content height: %lf",settings->page_width,
settings->page_height, height_to_print));
height_on_page = settings->page_height;
height_on_page = height_on_page - settings->margins[MARGINTOP]
- settings->margins[MARGINBOTTOM];
height_to_print *= settings->scale;
page_number = height_to_print / height_on_page;
if (height_to_print - page_number * height_on_page > 0)
page_number += 1;
gtk_print_operation_set_n_pages(operation, page_number);
}
/** Handle the draw_page signal from the GtkPrintOperation.
* This function changes only the cairo context to print on.
*/
void gtk_print_signal_draw_page(GtkPrintOperation *operation,
GtkPrintContext *context,
gint page_nr,
gpointer user_data)
{
LOG(("Draw Page"));
gtk_print_current_cr = gtk_print_context_get_cairo_context(context);
print_draw_next_page(&gtk_printer, settings);
}
/** Handle the end_print signal from the GtkPrintOperation.
* This functions calls only the print_cleanup function from the print interface
*/
void gtk_print_signal_end_print(GtkPrintOperation *operation,
GtkPrintContext *context,
gpointer user_data)
{
LOG(("End print"));
print_cleanup(content_to_print, &gtk_printer);
}

48
gtk/gtk_print.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* GTK printing (interface).
*/
#ifndef NETSURF_GTK_PRINT_PLOTTERS_H
#define NETSURF_GTK_PRINT_PLOTTERS_H
#include <gtk/gtk.h>
extern cairo_t *gtk_print_current_cr;
extern struct content *content_to_print;
/*handlers for signals from the GTK print operation*/
void gtk_print_signal_begin_print(GtkPrintOperation *operation,
GtkPrintContext *context,
gpointer user_data);
void gtk_print_signal_draw_page(GtkPrintOperation *operation,
GtkPrintContext *context,
gint page_nr,
gpointer user_data);
void gtk_print_signal_end_print(GtkPrintOperation *operation,
GtkPrintContext *context,
gpointer user_data);
#endif

View File

@ -49,6 +49,11 @@
#include "render/html.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "pdf/pdf_plotters.h"
#include "desktop/print.h"
#include "gtk/gtk_print.h"
#undef NDEBUG
#include "utils/log.h"
@ -138,6 +143,9 @@ void nsgtk_openfile_open(char *filename);
MENUPROTO(new_window);
MENUPROTO(open_location);
MENUPROTO(open_file);
MENUPROTO(export_pdf);
MENUPROTO(print);
MENUPROTO(print_preview);
MENUPROTO(close_window);
MENUPROTO(quit);
@ -181,6 +189,9 @@ static struct menu_events menu_events[] = {
MENUEVENT(new_window),
MENUEVENT(open_location),
MENUEVENT(open_file),
MENUEVENT(export_pdf),
MENUEVENT(print),
MENUEVENT(print_preview),
MENUEVENT(close_window),
MENUEVENT(quit),
@ -467,6 +478,86 @@ MENUHANDLER(open_file)
return TRUE;
}
MENUHANDLER(export_pdf){
GtkWidget *save_dialog;
struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
struct print_settings* settings;
LOG(("Print preview (generating PDF) started."));
settings = print_make_settings(DEFAULT);
save_dialog = gtk_file_chooser_dialog_new("Export to PDF", gw->window,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog),
getenv("HOME") ? getenv("HOME") : "/");
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog),
"out.pdf");
if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) {
settings->output = gtk_file_chooser_get_filename(
GTK_FILE_CHOOSER(save_dialog));
}
gtk_widget_destroy(save_dialog);
print_basic_run(bw->current_content, &pdf_printer, settings);
return TRUE;
}
MENUHANDLER(print){
struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
GtkPrintOperation* print_op;
GtkPageSetup* page_setup;
struct print_settings* settings;
settings = print_make_settings(DEFAULT);
print_op = gtk_print_operation_new();
page_setup = gtk_page_setup_new();
content_to_print = bw->current_content;
page_setup = gtk_print_run_page_setup_dialog(gw->window, page_setup, NULL);
gtk_print_operation_set_default_page_setup (print_op, page_setup);
g_signal_connect(print_op, "begin_print", G_CALLBACK (gtk_print_signal_begin_print), NULL);
g_signal_connect(print_op, "draw_page", G_CALLBACK (gtk_print_signal_draw_page), NULL);
g_signal_connect(print_op, "end_print", G_CALLBACK (gtk_print_signal_end_print), NULL);
gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
gw->window,
NULL);
return TRUE;
}
MENUHANDLER(print_preview){
struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
LOG(("Print preview (generating PDF) started."));
print_basic_run(bw->current_content, &pdf_printer, NULL);
return TRUE;
}
MENUHANDLER(close_window)
{
struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;

View File

@ -91,7 +91,7 @@
<child>
<widget class="GtkMenuItem" id="export">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="sensitive">True</property>
<property name="tooltip" translatable="yes">Export the page to a different format.</property>
<property name="label" translatable="yes">Export</property>
<property name="use_underline">True</property>
@ -100,6 +100,7 @@
<child>
<widget class="GtkMenuItem" id="export_plain_text">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="tooltip" translatable="yes">Plain ASCII text, readable in text editors and views.</property>
<property name="label" translatable="yes">Plain text...</property>
<property name="use_underline">True</property>
@ -108,6 +109,7 @@
<child>
<widget class="GtkMenuItem" id="export_drawfile">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="tooltip" translatable="yes">RISC OS Drawfile vector graphic.</property>
<property name="label" translatable="yes">Drawfile...</property>
<property name="use_underline">True</property>
@ -116,11 +118,21 @@
<child>
<widget class="GtkMenuItem" id="export_postscript">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="tooltip" translatable="yes">PostScript for printing and converting to PDFs.</property>
<property name="label" translatable="yes">PostScript...</property>
<property name="use_underline">True</property>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="export_pdf">
<property name="visible">True</property>
<property name="sensitive">True</property>
<property name="tooltip" translatable="yes">Portable Document Format.</property>
<property name="label" translatable="yes">PDF...</property>
<property name="use_underline">True</property>
</widget>
</child>
</widget>
</child>
</widget>
@ -133,10 +145,11 @@
<child>
<widget class="GtkImageMenuItem" id="print_preview">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="sensitive">True</property>
<property name="tooltip" translatable="yes">Show how a print out might look like.</property>
<property name="label" translatable="yes">Print preview...</property>
<property name="use_underline">True</property>
<accelerator key="P" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image558">
<property name="visible">True</property>
@ -149,7 +162,7 @@
<child>
<widget class="GtkImageMenuItem" id="print">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="sensitive">True</property>
<property name="tooltip" translatable="yes">Produce a hardcopy on your printer.</property>
<property name="label" translatable="yes">Print...</property>
<property name="use_underline">True</property>

View File

@ -98,7 +98,7 @@ bool nsbmp_redraw(struct content *c, int x, int y,
if (!c->data.bmp.bmp->decoded)
bmp_decode(c->data.bmp.bmp);
c->bitmap = c->data.bmp.bmp->bitmap;
return plot.bitmap(x, y, width, height, c->bitmap, background_colour);
return plot.bitmap(x, y, width, height, c->bitmap, background_colour, c);
}
@ -112,7 +112,7 @@ bool nsbmp_redraw_tiled(struct content *c, int x, int y,
bmp_decode(c->data.bmp.bmp);
c->bitmap = c->data.bmp.bmp->bitmap;
return plot.bitmap_tile(x, y, width, height, c->bitmap,
background_colour, repeat_x, repeat_y);
background_colour, repeat_x, repeat_y, c);
}

View File

@ -141,7 +141,7 @@ bool nsgif_redraw(struct content *c, int x, int y,
if (c->data.gif.current_frame != c->data.gif.gif->decoded_frame)
nsgif_get_frame(c);
c->bitmap = c->data.gif.gif->frame_image;
return plot.bitmap(x, y, width, height, c->bitmap, background_colour);
return plot.bitmap(x, y, width, height, c->bitmap, background_colour, c);
}
@ -155,7 +155,7 @@ bool nsgif_redraw_tiled(struct content *c, int x, int y,
nsgif_get_frame(c);
c->bitmap = c->data.gif.gif->frame_image;
return plot.bitmap_tile(x, y, width, height, c->bitmap, background_colour,
repeat_x, repeat_y);
repeat_x, repeat_y, c);
}

View File

@ -101,7 +101,7 @@ bool nsico_redraw(struct content *c, int x, int y,
bmp_decode(bmp);
c->bitmap = bmp->bitmap;
return plot.bitmap(x, y, width, height, c->bitmap,
background_colour);
background_colour, c);
}
@ -115,7 +115,7 @@ bool nsico_redraw_tiled(struct content *c, int x, int y,
bmp_decode(bmp);
c->bitmap = bmp->bitmap;
return plot.bitmap_tile(x, y, width, height, c->bitmap,
background_colour, repeat_x, repeat_y);
background_colour, repeat_x, repeat_y, c);
}

View File

@ -235,7 +235,7 @@ bool nsjpeg_redraw(struct content *c, int x, int y,
float scale, unsigned long background_colour)
{
return plot.bitmap(x, y, width, height,
c->bitmap, background_colour);
c->bitmap, background_colour, c);
}
@ -251,7 +251,7 @@ bool nsjpeg_redraw_tiled(struct content *c, int x, int y,
{
return plot.bitmap_tile(x, y, width, height,
c->bitmap, background_colour,
repeat_x, repeat_y);
repeat_x, repeat_y, c);
}

View File

@ -505,7 +505,7 @@ bool nsmng_redraw(struct content *c, int x, int y,
}
ret = plot.bitmap(x, y, width, height,
c->bitmap, background_colour);
c->bitmap, background_colour, c);
/* Check if we need to restart the animation
*/
@ -534,7 +534,7 @@ bool nsmng_redraw_tiled(struct content *c, int x, int y,
ret = plot.bitmap_tile(x, y, width, height,
c->bitmap, background_colour,
repeat_x, repeat_y);
repeat_x, repeat_y, c);
/* Check if we need to restart the animation
*/

View File

@ -131,7 +131,7 @@ bool nssprite_redraw(struct content *c, int x, int y,
float scale, colour background_colour)
{
return plot.bitmap(x, y, width, height,
c->bitmap, background_colour);
c->bitmap, background_colour, c);
}
#endif

View File

@ -182,7 +182,7 @@ bool rsvg_redraw(struct content *c, int x, int y, int width, int height,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, unsigned long background_colour)
{
plot.bitmap(x, y, width, height, c->bitmap, background_colour);
plot.bitmap(x, y, width, height, c->bitmap, background_colour, c);
return true;
}

19
pdf/TODO Normal file
View File

@ -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.

373
pdf/font_haru.c Normal file
View File

@ -0,0 +1,373 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Font handling in Haru pdf documents (implementation).
*
* The functions were written to implement the same interface as the Pango ones
* so that the usage of the latter wouldn't have to be modified.
*/
#define FONT_HARU_DEBUG
#include <assert.h>
#include <float.h>
#include <math.h>
#include <string.h>
#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;
}

36
pdf/font_haru.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Font handling in Haru pdf documents (interface).
*/
#ifndef _NETSURF_RENDER_FONT_HARU_H_
#define _NETSURF_RENDER_FONT_HARU_H_
#include "render/font.h"
#include "hpdf.h"
bool haru_nsfont_apply_style(const struct css_style *style,
HPDF_Doc doc, HPDF_Page page,
HPDF_Font *font);
extern const struct font_functions haru_nsfont;
#endif

774
pdf/pdf_plotters.c Normal file
View File

@ -0,0 +1,774 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Target independent PDF plotting using Haru Free PDF Library.
* Contains also the current solution for some text being cropped over page
* boundaries a 'fuzzy' bottom margin.
*/
#include <stdlib.h>
#include <string.h>
#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 ; i<n ; i++) {
HPDF_Page_LineTo(pdf_page, p[i*2], page_height - p[i*2+1]);
#ifdef PDF_DEBUG
pmaxx = max(pmaxx, p[i*2]);
pmaxy = max(pmaxy, p[i*2+1]);
pminx = min(pminx, p[i*2]);
pminy = min(pminy, p[i*2+1]);
#endif
}
#ifdef PDF_DEBUG
LOG(("%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy, page_height-pminy));
#endif
HPDF_Page_LineTo(pdf_page, p[0], page_height - p[1]);
HPDF_Page_Fill(pdf_page);
return true;
}
bool pdf_plot_fill(int x0, int y0, int x1, int y1, colour c){
#ifdef PDF_DEBUG
LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height-y0, c));
#endif
/*Normalize boundaries of the area - to prevent overflows.
It is needed only in a few functions, where integers are subtracted.
When the whole browser window is meant min and max int values are used
what must be handled in paged output.
*/
x0 = min(max(x0, 0), page_width);
y0 = min(max(y0, 0), page_height);
x1 = min(max(x1, 0), page_width);
y1 = min(max(y1, 0), page_height);
HPDF_Page_SetRGBFill(pdf_page, R(c), G(c), B(c));
HPDF_Page_Rectangle(pdf_page, x0, page_height - y1, x1-x0, y1-y0);
HPDF_Page_Fill(pdf_page);
return true;
}
bool pdf_plot_clip(int clip_x0, int clip_y0,
int clip_x1, int clip_y1){
#ifdef PDF_DEBUG
LOG(("%d %d %d %d", clip_x0, clip_y0, clip_x1, clip_y1));
#endif
HPDF_Page_GRestore(pdf_page);
if (page_clipped)
HPDF_Page_GRestore(pdf_page);
/*Normalize cllipping area - to prevent overflows.
See comment in pdf_plot_fill.
*/
clip_x0 = min(max(clip_x0, 0), page_width);
clip_y0 = min(max(clip_y0, 0), page_height);
clip_x1 = min(max(clip_x1, 0), page_width);
clip_y1 = min(max(clip_y1, 0), page_height);
HPDF_Page_GSave(pdf_page);
HPDF_Page_Rectangle(pdf_page, clip_x0, page_height-clip_y1,
clip_x1-clip_x0, clip_y1-clip_y0);
HPDF_Page_Clip(pdf_page);
HPDF_Page_EndPath(pdf_page);
pdf_page_apply_notext_clip();
page_clipped = true;
return true;
}
bool pdf_plot_text(int x, int y, const struct css_style *style,
const char *text, size_t length, colour bg, colour c){
#ifdef PDF_DEBUG
LOG((". %d %d %s", x, y, text));
#endif
char *word;
HPDF_REAL size;
bool fuzzy=false;
float text_bottom_position, descent;
if (length == 0)
return true;
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);
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; i<img_height; i++)
for (j = 0 ; j<img_width ; j++) {
rgb_buffer[((i * img_width) + j) * 3] =
img_buffer[(i * img_rowstride) + (j * 4)];
rgb_buffer[(((i * img_width) + j) * 3) + 1] =
img_buffer[(i * img_rowstride) + (j * 4) + 1];
rgb_buffer[(((i * img_width) + j) * 3) + 2] =
img_buffer[(i * img_rowstride) + (j * 4) + 2];
alpha_buffer[(i * img_width)+j] =
img_buffer[(i * img_rowstride) + (j * 4) + 3];
}
smask = HPDF_LoadRawImageFromMem(pdf_doc, alpha_buffer,
img_width, img_height,
HPDF_CS_DEVICE_GRAY, 8);
image = HPDF_LoadRawImageFromMem(pdf_doc, rgb_buffer,
img_width, img_height,
HPDF_CS_DEVICE_RGB, 8);
if (HPDF_Image_AddSMask(pdf_doc, image,smask) != HPDF_OK)
image = NULL;
free(rgb_buffer);
free(alpha_buffer);
}
return image;
}
bool pdf_plot_flush(){
return true;
}
static inline float transform_x(float *transform,float x,float y){
return ((transform[0] * x) + (transform[2] * (-y) ) + transform[4]) * 2;
}
static inline float transform_y(float *transform,float x,float y){
return page_height - (((transform[1] * x) +
(transform[3] * (-y)) - transform[5]) * 2);
}
bool pdf_plot_path(float *p, unsigned int n, colour fill, float width,
colour c, float *transform){
#ifdef PDF_DEBUG
LOG(("."));
#endif
unsigned int i;
bool empty_path = true;
if (n == 0)
return true;
if ((c == TRANSPARENT) && (fill == TRANSPARENT))
return true;
if (p[0] != PLOTTER_PATH_MOVE) {
return false;
}
HPDF_Page_SetRGBFill(pdf_page, R(fill), G(fill), B(fill));
HPDF_Page_SetRGBStroke(pdf_page, R(c), G(c), B(c));
transform[0] = 0.1;
transform[1] = 0;
transform[2] = 0;
transform[3] = -0.1;
transform[4] = 0;
transform[5] = 0;
for (i = 0 ; i<n ; ) {
if (p[i] == PLOTTER_PATH_MOVE) {
HPDF_Page_MoveTo(pdf_page,
transform_x(transform, p[i+1], p[i+2]),
transform_y(transform, p[i+1], p[i+2]));
i+= 3;
} else if (p[i] == PLOTTER_PATH_CLOSE) {
if (!empty_path)
HPDF_Page_ClosePath(pdf_page);
i++;
} else if (p[i] == PLOTTER_PATH_LINE) {
HPDF_Page_LineTo(pdf_page,
transform_x(transform, p[i+1], p[i+2]),
transform_y(transform, p[i+1], p[i+2]));
i+=3;
empty_path = false;
} else if (p[i] == PLOTTER_PATH_BEZIER) {
HPDF_Page_CurveTo(pdf_page,
transform_x(transform, p[i+1], p[i+2]),
transform_y(transform, p[i+1], p[i+2]),
transform_x(transform, p[i+3], p[i+4]),
transform_y(transform, p[i+3], p[i+4]),
transform_x(transform, p[i+5], p[i+6]),
transform_y(transform, p[i+5], p[i+6]));
i += 7;
empty_path = false;
} else {
LOG(("bad path command %f", p[i]));
return false;
}
}
if (empty_path) {
HPDF_Page_EndPath(pdf_page);
return true;
}
if (fill!=TRANSPARENT) {
if (c != TRANSPARENT)
HPDF_Page_FillStroke(pdf_page);
else
HPDF_Page_Fill(pdf_page);
}
else
HPDF_Page_Stroke(pdf_page);
return true;
}
void pdf_set_solid()
{
HPDF_Page_SetDash(pdf_page, NULL, 0, 0);
}
void pdf_set_dashed()
{
HPDF_UINT16 dash_ptn[] = {3};
HPDF_Page_SetDash(pdf_page, dash_ptn, 1, 1);
}
void pdf_set_dotted()
{
HPDF_UINT16 dash_ptn[] = {1};
HPDF_Page_SetDash(pdf_page, dash_ptn, 1, 1);
}
/**
* Begin pdf plotting - initialize a new document
* \param path Output file path
* \param pg_width page width
* \param pg_height page height
*/
bool pdf_begin(struct print_settings* print_settings)
{
pdf_doc = NULL;
pdf_doc = HPDF_New(error_handler, NULL);
if (!pdf_doc) {
LOG(("Error creating pdf_doc"));
return false;
}
settings = print_settings;
page_width = settings->page_width - settings->margins[MARGINLEFT] -
settings->margins[MARGINRIGHT];
page_height = settings->page_height - settings->margins[MARGINTOP];
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
}

40
pdf/pdf_plotters.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
PDF Plotting
*/
#ifndef NETSURF_PDF_PLOTTERS_H
#define NETSURF_PDF_PLOTTERS_H
#include "desktop/print.h"
struct plotter_table;
extern struct printer pdf_printer;
/**Start plotting a pdf file*/
bool pdf_begin(struct print_settings* settings);
/**Finish the current page and start a new one*/
bool pdf_next_page(void);
/**Close pdf document and save changes to file*/
void pdf_end(void);
#endif /*NETSURF_PDF_PLOTTERS_H*/

36
pdf/pdf_printer.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* 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

View File

@ -33,7 +33,6 @@
#include "utils/log.h"
#include "utils/talloc.h"
static bool box_contains_point(struct box *box, int x, int y);
#define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \
@ -545,6 +544,10 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
fprintf(stream, "(%i %i %i %i) ",
box->descendant_x0, box->descendant_y0,
box->descendant_x1, box->descendant_y1);
fprintf(stream, "m(%i %i %i %i) ",
box->margin[TOP], box->margin[LEFT],
box->margin[BOTTOM], box->margin[RIGHT]);
switch (box->type) {
case BOX_BLOCK: fprintf(stream, "BLOCK "); break;
@ -638,3 +641,201 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
box_dump(stream, c, depth + 1);
}
}
/* Box tree duplication below
*/
/** structure for translating addresses in the box tree */
struct box_dict_element{
struct box *old, *new;
};
static bool box_duplicate_main_tree(struct box *box, struct content *c,
int *count);
static void box_duplicate_create_dict(struct box *old_box, struct box *new_box,
struct box_dict_element **dict);
static void box_duplicate_update( struct box *box,
struct box_dict_element *dict,
int n);
static int box_compare_dict_elements(const struct box_dict_element *a,
const struct box_dict_element *b);
int box_compare_dict_elements(const struct box_dict_element *a,
const struct box_dict_element *b)
{
return (a->old < b->old) ? -1 : ((a->old > b->old) ? 1 : 0);
}
/** Duplication of a box tree. We assume that all the content is fetched,
fallbacks have been applied where necessary and we reuse a lot of content
like strings, fetched objects etc - just replicating all we need to create
two different layouts.
\return true on success, false on lack of memory
*/
struct box* box_duplicate_tree(struct box *root, struct content *c)
{
struct box *new_root;/**< Root of the new box tree*/
int box_number = 0;
struct box *old_addr, *new_addr;
struct box_dict_element *box_dict, *box_dict_end;
/* 1. Duplicate parent - children structure, list_markers*/
new_root = talloc_memdup(c, root, sizeof (struct box));
if (!box_duplicate_main_tree(new_root, c, &box_number))
return NULL;
/* 2. Create address translation dictionary*/
/*TODO: dont save unnecessary addresses*/
box_dict_end = box_dict = malloc(box_number *
sizeof(struct box_dict_element));
if (box_dict == NULL)
return NULL;
box_duplicate_create_dict(root, new_root, &box_dict_end);
assert((box_dict_end - box_dict) == box_number);
/*3. Sort it*/
qsort(box_dict, (box_dict_end - box_dict), sizeof(struct box_dict_element),
(int (*)(const void *, const void *))box_compare_dict_elements);
/* 4. Update inline_end and float_children pointers */
box_duplicate_update(new_root, box_dict, (box_dict_end - box_dict));
free(box_dict);
return new_root;
}
/**
* Recursively duplicates children of an element, and also if present - its
* list_marker, style and text.
* \param box Current box to duplicate its children
* \param c talloc memory pool
* \param count number of boxes seen so far
* \return true if successful, false otherwise (lack of memory)
*/
bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
{
struct box *b, *prev, *copy;
prev = NULL;
for (b = box->children; b; b = b->next) {
/*Copy child*/
copy = talloc_memdup(c, b, sizeof (struct box));
if (copy == NULL)
return false;
copy->parent = box;
if (prev != NULL)
prev->next = copy;
else
box->children = copy;
/* Recursively visit child */
box_duplicate_main_tree(copy, c, count);
prev = copy;
}
box->last = prev;
if (box->list_marker) {
box->list_marker = talloc_memdup(c, box->list_marker,
sizeof *box->list_marker);
if (box->list_marker == NULL)
return false;
box->list_marker->parent = box;
}
if (box->text) {
box->text = talloc_memdup(c, box->text, box->length);
if (box->text == NULL)
return false;
}
if (box->style) {
box->style = talloc_memdup(c, box->style, sizeof *box->style);
if (box->style == NULL)
return false;
}
/*Make layout calculate the size of this element later
(might change because of font change etc.) */
box->width = UNKNOWN_WIDTH;
box->min_width = 0;
box->max_width = UNKNOWN_MAX_WIDTH;
(*count)++;
return true;
}
/**
* Recursively creates a dictionary of addresses - binding the address of a box
* with its copy.
* \param old_box original box
* \param new_box copy of the original box
* \param dict pointer to a pointer to the current position in the dictionary
*/
void box_duplicate_create_dict(struct box *old_box, struct box *new_box,
struct box_dict_element **dict)
{
/**Children of the old and new boxes*/
struct box *b_old, *b_new;
for (b_old = old_box->children, b_new = new_box->children;
b_old != NULL && b_new != NULL;
b_old = b_old->next, b_new = b_new->next)
box_duplicate_create_dict(b_old, b_new, dict);
/*The new tree should be a exact copy*/
assert(b_old == NULL && b_new == NULL);
(*dict)->old = old_box;
(*dict)->new = new_box;
(*dict)++;
}
/**
* Recursively updates pointers in box tree.
* \param box current box in the new box tree
* \param box_dict box pointers dictionary
* \param n number of memory addresses in the dictionary
*/
void box_duplicate_update(struct box *box,
struct box_dict_element *box_dict,
int n)
{
struct box_dict_element *box_dict_element;
struct box *b;
struct box_dict_element element;
for (b = box->children; b; b = b->next)
box_duplicate_update(b, box_dict, n);
if (box->float_children) {
element.old = box->float_children;
box_dict_element = bsearch(&element,
box_dict, n,
sizeof(struct box_dict_element),
(int (*)(const void *, const void *))box_compare_dict_elements);
box->float_children = box_dict_element->new;
}
if (box->next_float) {
element.old = box->next_float;
box_dict_element = bsearch(&element,
box_dict, n,
sizeof(struct box_dict_element),
(int (*)(const void *, const void *))box_compare_dict_elements);
box->next_float = box_dict_element->new;
}
}

View File

@ -311,4 +311,6 @@ bool xml_to_box(xmlNode *n, struct content *c);
bool box_normalise_block(struct box *block, struct content *c);
struct box* box_duplicate_tree(struct box *root, struct content *c);
#endif

View File

@ -39,14 +39,19 @@
struct css_style;
bool nsfont_width(const struct css_style *style,
const char *string, size_t length,
int *width);
bool nsfont_position_in_string(const struct css_style *style,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
bool nsfont_split(const struct css_style *style,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
struct font_functions
{
bool (*font_width)(const struct css_style *style,
const char *string, size_t length,
int *width);
bool (*font_position_in_string)(const struct css_style *style,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
bool (*font_split)(const struct css_style *style,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
};
extern const struct font_functions nsfont;
#endif

View File

@ -122,6 +122,7 @@ bool html_create(struct content *c, const char *params[])
html->page = 0;
html->index = 0;
html->box = 0;
html->font_func = &nsfont;
for (i = 0; params[i]; i += 2) {
if (strcasecmp(params[i], "charset") == 0) {

View File

@ -130,6 +130,7 @@ struct content_html_data {
struct box *layout; /**< Box tree, or 0. */
colour background_colour; /**< Document background colour. */
const struct font_functions *font_func;
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;

View File

@ -623,17 +623,17 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
endtxt_idx = utf8_len;
}
if (!nsfont_width(style, utf8_text, start_idx, &startx))
if (!nsfont.font_width(style, utf8_text, start_idx, &startx))
startx = 0;
if (!nsfont_width(style, utf8_text, endtxt_idx, &endx))
if (!nsfont.font_width(style, utf8_text, endtxt_idx, &endx))
endx = 0;
/* is there a trailing space that should be highlighted as well? */
if (end_idx > utf8_len) {
int spc_width;
/* \todo is there a more elegant/efficient solution? */
if (nsfont_width(style, " ", 1, &spc_width))
if (nsfont.font_width(style, " ", 1, &spc_width))
endx += spc_width;
}
@ -1175,7 +1175,7 @@ bool html_redraw_file(int x, int y, int width, int height,
text = messages_get("Form_Drop");
length = strlen(text);
if (!nsfont_width(box->style, text, length, &text_width))
if (!nsfont.font_width(box->style, text, length, &text_width))
return false;
text_width *= scale;
if (width < text_width + 8)

View File

@ -55,7 +55,8 @@
#define AUTO INT_MIN
static void layout_minmax_block(struct box *block);
static void layout_minmax_block(struct box *block,
const struct font_functions *font_func);
static bool layout_block_object(struct box *block);
static void layout_block_find_dimensions(int available_width, struct box *box);
static bool layout_apply_minmax_height(struct box *box);
@ -71,24 +72,28 @@ static void layout_find_dimensions(int available_width,
static int layout_clear(struct box *fl, css_clear clear);
static void find_sides(struct box *fl, int y0, int y1,
int *x0, int *x1, struct box **left, struct box **right);
static void layout_minmax_inline_container(struct box *inline_container);
static void layout_minmax_inline_container(struct box *inline_container,
const struct font_functions *font_func);
static int line_height(struct css_style *style);
static bool layout_line(struct box *first, int *width, int *y,
int cx, int cy, struct box *cont, bool indent,
bool has_text_children,
struct content *content, struct box **next_box);
static struct box *layout_minmax_line(struct box *first, int *min, int *max);
static struct box *layout_minmax_line(struct box *first, int *min, int *max,
const struct font_functions *font_func);
static int layout_text_indent(struct css_style *style, int width);
static bool layout_float(struct box *b, int width, struct content *content);
static void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont);
static bool layout_table(struct box *box, int available_width,
struct content *content);
static void layout_minmax_table(struct box *table);
static void layout_minmax_table(struct box *table,
const struct font_functions *font_func);
static void layout_move_children(struct box *box, int x, int y);
static void calculate_mbp_width(struct css_style *style, unsigned int side,
int *fixed, float *frac);
static void layout_lists(struct box *box);
static void layout_lists(struct box *box,
const struct font_functions *font_func);
static void layout_position_relative(struct box *root);
static void layout_compute_relative_offset(struct box *box, int *x, int *y);
static bool layout_position_absolute(struct box *box,
@ -116,10 +121,11 @@ bool layout_document(struct content *content, int width, int height)
{
bool ret;
struct box *doc = content->data.html.layout;
const struct font_functions *font_func = content->data.html.font_func;
assert(content->type == CONTENT_HTML);
layout_minmax_block(doc);
layout_minmax_block(doc, font_func);
layout_block_find_dimensions(width, doc);
doc->x = doc->margin[LEFT] + doc->border[LEFT];
@ -150,7 +156,7 @@ bool layout_document(struct content *content, int width, int height)
doc->children->margin[BOTTOM]);
}
layout_lists(doc);
layout_lists(doc, font_func);
layout_position_absolute(doc, doc, 0, 0, content);
layout_position_relative(doc);
@ -516,7 +522,7 @@ bool layout_block_context(struct box *block, struct content *content)
* 0 <= block->min_width <= block->max_width
*/
void layout_minmax_block(struct box *block)
void layout_minmax_block(struct box *block, const struct font_functions *font_func)
{
struct box *child;
int min = 0, max = 0;
@ -545,7 +551,8 @@ void layout_minmax_block(struct box *block)
if (block->object) {
if (block->object->type == CONTENT_HTML) {
layout_minmax_block(block->object->data.html.layout);
layout_minmax_block(block->object->data.html.layout,
font_func);
min = block->object->data.html.layout->min_width;
max = block->object->data.html.layout->max_width;
} else {
@ -556,13 +563,14 @@ void layout_minmax_block(struct box *block)
for (child = block->children; child; child = child->next) {
switch (child->type) {
case BOX_BLOCK:
layout_minmax_block(child);
layout_minmax_block(child, font_func);
break;
case BOX_INLINE_CONTAINER:
layout_minmax_inline_container(child);
layout_minmax_inline_container(child,
font_func);
break;
case BOX_TABLE:
layout_minmax_table(child);
layout_minmax_table(child, font_func);
break;
default:
assert(0);
@ -1139,7 +1147,8 @@ bool layout_inline_container(struct box *inline_container, int width,
* 0 <= inline_container->min_width <= inline_container->max_width
*/
void layout_minmax_inline_container(struct box *inline_container)
void layout_minmax_inline_container(struct box *inline_container,
const struct font_functions *font_func)
{
struct box *child;
int line_min = 0, line_max = 0;
@ -1152,7 +1161,9 @@ void layout_minmax_inline_container(struct box *inline_container)
return;
for (child = inline_container->children; child; ) {
child = layout_minmax_line(child, &line_min, &line_max);
child = layout_minmax_line(child,
&line_min, &line_max,
font_func);
if (min < line_min)
min = line_min;
if (max < line_max)
@ -1242,6 +1253,8 @@ bool layout_line(struct box *first, int *width, int *y,
struct css_length gadget_size; /* Checkbox / radio buttons */
gadget_size.unit = CSS_UNIT_EM;
gadget_size.value = 1;
const struct font_functions *font_func = content->data.html.font_func;
LOG(("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
first, (int) first->length, first->text, *width,
@ -1334,7 +1347,8 @@ bool layout_line(struct box *first, int *width, int *y,
b->width = 0;
if (b->space) {
/** \todo optimize out */
nsfont_width(b->style, " ", 1, &space_after);
font_func->font_width(b->style, " ", 1,
&space_after);
} else {
space_after = 0;
}
@ -1371,7 +1385,8 @@ bool layout_line(struct box *first, int *width, int *y,
data.select.items; o;
o = o->next) {
int opt_width;
nsfont_width(b->style, o->text,
font_func->font_width(b->style,
o->text,
strlen(o->text),
&opt_width);
@ -1381,7 +1396,7 @@ bool layout_line(struct box *first, int *width, int *y,
b->width = opt_maxwidth;
} else {
nsfont_width(b->style, b->text,
font_func->font_width(b->style, b->text,
b->length, &b->width);
}
}
@ -1389,7 +1404,8 @@ bool layout_line(struct box *first, int *width, int *y,
x += b->width;
if (b->space)
/** \todo optimize out */
nsfont_width(b->style, " ", 1, &space_after);
font_func->font_width(b->style, " ", 1,
&space_after);
else
space_after = 0;
@ -1529,7 +1545,7 @@ bool layout_line(struct box *first, int *width, int *y,
space_after = 0;
if (b->space)
/** \todo handle errors, optimize */
nsfont_width(b->style, " ", 1,
font_func->font_width(b->style, " ", 1,
&space_after);
} else
space_after = 0;
@ -1654,7 +1670,7 @@ bool layout_line(struct box *first, int *width, int *y,
w = split_box->width;
else
/** \todo handle errors */
nsfont_width(split_box->style, split_box->text,
font_func->font_width(split_box->style, split_box->text,
space, &w);
LOG(("splitting: split_box %p \"%.*s\", space %zu, w %i, "
@ -1725,7 +1741,7 @@ bool layout_line(struct box *first, int *width, int *y,
/* fit as many words as possible */
assert(space != 0);
/** \todo handle errors */
nsfont_split(split_box->style,
font_func->font_split(split_box->style,
split_box->text, split_box->length,
x1 - x0 - x - space_before, &space, &w);
LOG(("'%.*s' %i %zu %i", (int) split_box->length,
@ -1827,7 +1843,8 @@ bool layout_line(struct box *first, int *width, int *y,
*/
struct box *layout_minmax_line(struct box *first,
int *line_min, int *line_max)
int *line_min, int *line_max,
const struct font_functions *font_func)
{
int min = 0, max = 0, width, height, fixed;
float frac;
@ -1855,9 +1872,9 @@ struct box *layout_minmax_line(struct box *first,
if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) {
assert(b->children);
if (b->children->type == BOX_BLOCK)
layout_minmax_block(b->children);
layout_minmax_block(b->children, font_func);
else
layout_minmax_table(b->children);
layout_minmax_table(b->children, font_func);
b->min_width = b->children->min_width;
b->max_width = b->children->max_width;
if (min < b->min_width)
@ -1867,7 +1884,7 @@ struct box *layout_minmax_line(struct box *first,
}
if (b->type == BOX_INLINE_BLOCK) {
layout_minmax_block(b);
layout_minmax_block(b, font_func);
if (min < b->min_width)
min = b->min_width;
max += b->max_width;
@ -1890,7 +1907,7 @@ struct box *layout_minmax_line(struct box *first,
if (0 < fixed)
max += fixed;
if (b->next && b->space) {
nsfont_width(b->style, " ", 1, &width);
font_func->font_width(b->style, " ", 1, &width);
max += width;
}
continue;
@ -1916,7 +1933,8 @@ struct box *layout_minmax_line(struct box *first,
data.select.items; o;
o = o->next) {
int opt_width;
nsfont_width(b->style, o->text,
font_func->font_width(b->style,
o->text,
strlen(o->text),
&opt_width);
@ -1926,13 +1944,13 @@ struct box *layout_minmax_line(struct box *first,
b->width = opt_maxwidth;
} else {
nsfont_width(b->style, b->text,
font_func->font_width(b->style, b->text,
b->length, &b->width);
}
}
max += b->width;
if (b->next && b->space) {
nsfont_width(b->style, " ", 1, &width);
font_func->font_width(b->style, " ", 1, &width);
max += width;
}
@ -1942,7 +1960,7 @@ struct box *layout_minmax_line(struct box *first,
for (j = i; j != b->length &&
b->text[j] != ' '; j++)
;
nsfont_width(b->style, b->text + i,
font_func->font_width(b->style, b->text + i,
j - i, &width);
if (min < width)
min = width;
@ -2560,7 +2578,8 @@ bool layout_table(struct box *table, int available_width,
* 0 <= table->min_width <= table->max_width
*/
void layout_minmax_table(struct box *table)
void layout_minmax_table(struct box *table,
const struct font_functions *font_func)
{
unsigned int i, j;
int border_spacing_h = 0;
@ -2597,7 +2616,7 @@ void layout_minmax_table(struct box *table)
if (cell->columns != 1)
continue;
layout_minmax_block(cell);
layout_minmax_block(cell, font_func);
i = cell->start_column;
if (col[i].positioned)
@ -2620,7 +2639,7 @@ void layout_minmax_table(struct box *table)
if (cell->columns == 1)
continue;
layout_minmax_block(cell);
layout_minmax_block(cell, font_func);
i = cell->start_column;
/* find min width so far of spanned columns, and count
@ -2766,7 +2785,8 @@ void calculate_mbp_width(struct css_style *style, unsigned int side,
* Layout list markers.
*/
void layout_lists(struct box *box)
void layout_lists(struct box *box,
const struct font_functions *font_func)
{
struct box *child;
struct box *marker;
@ -2782,7 +2802,7 @@ void layout_lists(struct box *box)
marker->height) / 2;
} else if (marker->text) {
if (marker->width == UNKNOWN_WIDTH)
nsfont_width(marker->style,
font_func->font_width(marker->style,
marker->text,
marker->length,
&marker->width);
@ -2798,7 +2818,7 @@ void layout_lists(struct box *box)
/* Gap between marker and content */
marker->x -= 4;
}
layout_lists(child);
layout_lists(child, font_func);
}
}

415
render/loosen.c Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <assert.h>
#include "content/content.h"
#include "render/box.h"
#include "render/font.h"
#include "utils/log.h"
#include "utils/talloc.h"
#define AUTO INT_MIN
static bool loosen_text(struct box *text, int width, struct content *content);
static bool loosen_table(struct box *box, int available_width,
struct content *content);
static bool loosen_position_static(struct box *box, int width, int cx,
struct content *content);
static bool loosen_shrink_object(struct box *box, int width);
static bool loosen_all_first_pass(struct box *box, int width, int cx,
struct content *content);
static bool loosen_all_second_pass(struct box *box, int width, int cx,
struct content *content);
static bool loosen_all_third_pass(struct box *box, int width, int cx,
struct content *content);
/**
* Main loosing procedure
* \param content Reformated content - talloc memory pool for new boxes
* \param layout Root of the loosened box tree
* \param width Width the content is intended to fit
* \param height Height of a single page - to be taken into consideration for \
* preventing elements for being cropped at top/bottom edges of pages.
* \return true if successful, false otherwise (lack of memory)
*/
bool loosen_document_layout(struct content *content, struct box *layout,
int width, int height)
{
/* Optional try - if the current layout is not more than xx% too wide,
* maybe we scale the content to preserve the original layout?
*/
if (!loosen_all_first_pass(layout, width, 0, content))
return false;
layout->min_width = 0;
layout->max_width = UNKNOWN_MAX_WIDTH;
content_reformat(content, width, 0);
/*Check if pass 1 was enough - if re-layouting doesn't give
*us the right width, go on to pass 2. And again - if pass 2 was not
*enough - go on to pass 3
*/
if (content->width > width) {
if (!loosen_all_second_pass(layout, width, 0, content))
return false;
layout->min_width = 0;
layout->max_width = UNKNOWN_MAX_WIDTH;
content_reformat(content, width, 0);
}
if (content->width > width) {
if (!loosen_all_third_pass(layout, width, 0, content))
return false;
layout->min_width = 0;
layout->max_width = UNKNOWN_MAX_WIDTH;
content_reformat(content, width, 0);
}
return true;
}
/** Primarily - break too wide words into pieces.
* \param text - the box that contains text to be broken
* \param width Width the content is intended to fit
* \param content talloc memory pool for new boxes
* \return true if successful, false otherwise
*/
bool loosen_text(struct box *text, int width, struct content *content)
{
unsigned int offset;
int actual_x;
int *breaks;
int break_count;
int position, i;
const struct font_functions *font_func;
if (content->type == CONTENT_HTML)
font_func = content->data.html.font_func;
else
return false;
if (text->width <= width) {
LOG(("loosen_text called unnecessary?"));
/*Still - not an error for this function*/
return true;
}
breaks = malloc( sizeof(int) * text->length);
if (breaks == NULL)
return false;
break_count = 0;
position = 0;
while (position < text->length) {
font_func->font_position_in_string(text->style,
text->text + position,
text->length - position,
width, &offset, &actual_x);
if (offset < text->length - position) {
/*Another break*/
LOG(("Current text broken at offset %d",
position + offset));
breaks[break_count++] = position + offset-1;
}
position += offset;
}
text->text = talloc_realloc(content, text->text, char,
text->length + break_count);
i = text->length-1;
text->length = text->length + break_count;
for (; i>=0; i--) {
text->text[i + break_count] = text->text[i];
if (i == breaks[break_count - 1]) {
break_count--;
text->text[i + break_count] = ' ';
}
}
free(breaks);
return true;
}
/**
* Changing table layout and structure to fit the contents width.
* In the most extreme case - the table has no influence on the width
* (each row is broken into one-cell rows).
* \param table - the box that contains table to be broken
* \param width Width the content is intended to fit
* \param content talloc memory pool for new boxes
* \return true if successful, false otherwise
*/
bool loosen_table(struct box *table, int width, struct content *content)
{
struct box *row_group, *row, *cell, *br, *prev, *inline_container;
unsigned int row_sum;
bool first_cell_in_row;
if (table->min_width <= width)
return true;
inline_container = box_create(0, 0, 0, 0, 0, content);
inline_container->type = BOX_INLINE_CONTAINER;
inline_container->parent = table;
inline_container->style = talloc_memdup(content, table->style,
sizeof *table->style);
prev = NULL;
for (row_group = table->children; row_group;
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
for (cell = row->children; cell; cell = cell->next) {
cell->type = BOX_INLINE_BLOCK;
cell->prev = prev;
cell->parent = inline_container;
cell->max_width = width;
cell->min_width = 0;
if (prev!=NULL)
prev->next = cell;
else
inline_container->children = cell;
prev = cell;
}
br = box_create(0, 0, 0, 0, 0, content);
br->type = BOX_BR;
br->parent = inline_container;
br->prev = prev;
br->style = talloc_memdup(content, table->style,
sizeof *table->style);
br->style->clear = CSS_CLEAR_BOTH;
if (prev != NULL)
prev->next = br;
else
inline_container->children = br;
prev = br;
}
}
inline_container->last = prev;
table->type = BOX_BLOCK;
table->children = table->last = inline_container;
table->col = NULL;
return true;
}
/**
* Change absolute and relative positioned elements into block elements
* in case they are positioned to far to the rigth
* \param box - the box that should be changed
* \param width Width the content is intended to fit
* \param cx current x - not yet in use
* \param content talloc memory pool for new boxes
* \return true if successful, false otherwise
*/
bool loosen_position_static(struct box *box, int width, int cx,
struct content *content)
{
assert(box->style);
if (box->style->position == CSS_POSITION_ABSOLUTE) {
box->style->position = CSS_POSITION_NOT_SET;
}
return true;
}
/**
* Shrink an object (esp. an image) to fit the page-width
* \note Not sure wheter it won't be better for images to be cropped
* \param box - the box that should be changed
* \param width Width the content is intended to fit
* \return true if successful, false otherwise
*/
bool loosen_shrink_object(struct box *box, int width)
{
assert(box->object != NULL);
box->height = AUTO;
box->width = width;
if (box->style) {
box->style->width.width = CSS_WIDTH_PERCENT;
box->style->width.value.percent = 100;
box->style->height.height= CSS_HEIGHT_AUTO;
}
return true;
}
/**
* Pass 1 of loosening - do such obvious changes as: breaking too long words,
* moving absolute positioned objects into the visibile scope of width.
* \param box - the box that should be changed
* \param width Width the content is intended to fit
* \param cx current x - not yet in use
* \param content talloc memory pool for new boxes
* \return true if successful, false otherwise
*/
bool loosen_all_first_pass(struct box *box, int width, int cx,
struct content *content)
{
struct box* c;
int got_width;
int x;
for (c = box->children; c ; c = c->next) {
x = cx + c->x;
if (c->children != NULL)
if (!loosen_all_first_pass(c, width, x, content))
return false;
if (c->style) {
if (c->style->position == CSS_POSITION_RELATIVE ||
c->style->position == CSS_POSITION_ABSOLUTE )
if (!loosen_position_static(c, width, cx, content))
return false;
if ( c->style->width.width == CSS_WIDTH_LENGTH &&
css_len2px(&c->style->width.value.length, c->style) > width)
c->style->width.width = CSS_WIDTH_NOT_SET;
}
if (c->object && c->width > width)
if (!loosen_shrink_object(c, width))
return false;
switch (c->type) {
case BOX_TEXT:
if (!loosen_text(c, width, content))
return false;
break;
}
c->min_width = 0;
c->max_width = UNKNOWN_MAX_WIDTH;
}
return true;
}
/**
* Pass 2 of loosening - break tables
* \param box - the box that should be changed
* \param width Width the content is intended to fit
* \param cx current x - not yet in use
* \param content talloc memory pool for new boxes
* \return true if successful, false otherwise
*/
bool loosen_all_second_pass(struct box *box, int width, int cx,
struct content *content)
{
struct box *c;
int got_width;
int x;
for (c = box->children; c; c = c->next) {
x = cx + c->x;
if (c->children != NULL)
if (!loosen_all_second_pass(c, width, x, content))
return false;
switch (c->type) {
case BOX_TABLE:
if (!loosen_table(c, width, content))
return false;
break;
}
c->min_width = 0;
c->max_width = UNKNOWN_MAX_WIDTH;
}
return true;
}
/**
* Pass 3 of loosening -zero all margins and paddings
* \param box - the box that should be changed
* \param width Width the content is intended to fit
* \param cx current x - not yet in use
* \param content talloc memory pool for new boxes
* \return true if successful, false otherwise
*/
bool loosen_all_third_pass(struct box *box, int width, int cx,
struct content *content)
{
struct box *c;
int got_width;
int x;
for (c = box->children; c; c = c->next) {
x = cx + c->x;
if (c->children != NULL)
if (!loosen_all_third_pass(c, width, x, content))
return false;
c->padding[LEFT] = c->padding[RIGHT] = 0;
c->margin[LEFT] = c->margin[RIGHT] = 0;
if (c->style) {
c->style->margin[LEFT].margin = CSS_MARGIN_PERCENT;
c->style->margin[LEFT].value.percent = 0;
c->style->margin[RIGHT].margin = CSS_MARGIN_PERCENT;
c->style->margin[RIGHT].value.percent = 0;
c->style->padding[LEFT].padding = CSS_PADDING_PERCENT;
c->style->padding[LEFT].value.percent = 0;
c->style->padding[RIGHT].padding = CSS_PADDING_PERCENT;
c->style->padding[RIGHT].value.percent = 0;
}
c->min_width = 0;
c->max_width = UNKNOWN_MAX_WIDTH;
}
return true;
}

35
render/loosen.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
\file
General idea - a set of routines working themselves recursively through
the box tree and trying to change the layout of the document as little
as possible to acquire the desired width ( - to make it fit in a printed
page ), where possible - also taking the dividing height into consideration,
to prevent objects being cut by ends of pages.
*/
#ifndef NETSURF_RENDER_LOOSEN_H
#define NETSURF_RENDER_LOOSEN_H
#include <stdbool.h>
bool loosen_document_layout(struct content *content, struct box *layout,
int width, int height);
#endif

View File

@ -213,7 +213,7 @@ void textplain_reformat(struct content *c, int width, int height)
/* compute available columns (assuming monospaced font) - use 8
* characters for better accuracy */
if (!nsfont_width(&textplain_style, "ABCDEFGH", 8, &character_width))
if (!nsfont.font_width(&textplain_style, "ABCDEFGH", 8, &character_width))
return;
columns = (width - MARGIN - MARGIN) * 8 / character_width;
textplain_tab_width = (TAB_WIDTH * character_width) / 8;
@ -402,7 +402,7 @@ bool textplain_redraw(struct content *c, int x, int y,
break;
/* locate end of string and align to next tab position */
if (nsfont_width(&textplain_style, &text[offset],
if (nsfont.font_width(&textplain_style, &text[offset],
next_offset - offset, &width))
tx += (int)(width * scale);
@ -499,13 +499,13 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
next_offset = utf8_next(text, length, next_offset);
if (next_offset < length)
nsfont_width(&textplain_style, text, next_offset, &width);
nsfont.font_width(&textplain_style, text, next_offset, &width);
if (x <= width) {
int pixel_offset;
size_t char_offset;
nsfont_position_in_string(&textplain_style,
nsfont.font_position_in_string(&textplain_style,
text, next_offset, x,
&char_offset, &pixel_offset);
@ -584,7 +584,7 @@ int textplain_coord_from_offset(const char *text, size_t offset, size_t length)
while (next_offset < offset && text[next_offset] != '\t')
next_offset = utf8_next(text, length, next_offset);
nsfont_width(&textplain_style, text, next_offset, &tx);
nsfont.font_width(&textplain_style, text, next_offset, &tx);
x += tx;
if (next_offset >= offset)

View File

@ -35,20 +35,32 @@
#include "utils/messages.h"
#include "utils/utils.h"
/** desktop font, size and style being used */
char ro_gui_desktop_font_family[80];
int ro_gui_desktop_font_size = 12;
rufl_style ro_gui_desktop_font_style = rufl_WEIGHT_400;
static void nsfont_check_option(char **option, const char *family,
const char *fallback);
static int nsfont_list_cmp(const void *keyval, const void *datum);
static void nsfont_check_fonts(void);
static void ro_gui_wimp_desktop_font(char *family, size_t bufsize, int *psize,
rufl_style *pstyle);
static bool nsfont_width(const struct css_style *style,
const char *string, size_t length,
int *width);
static bool 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 nsfont_split(const struct css_style *style,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
/** desktop font, size and style being used */
char ro_gui_desktop_font_family[80];
int ro_gui_desktop_font_size = 12;
rufl_style ro_gui_desktop_font_style = rufl_WEIGHT_400;
const struct font_functions nsfont = {
nsfont_width,
nsfont_position_in_string,
nsfont_split
};
/**
* Initialize font handling.

View File

@ -182,9 +182,16 @@ void ro_gui_menu_init(void)
{ "Page", BROWSER_PAGE, 0 },
{ "Page.PageInfo",BROWSER_PAGE_INFO, dialog_pageinfo },
{ "Page.Save", BROWSER_SAVE, dialog_saveas },
#ifdef WITH_SAVE_COMPLETE
{ "Page.SaveComp", BROWSER_SAVE_COMPLETE, dialog_saveas },
#endif
{ "Page.Export", NO_ACTION, 0 },
#ifdef WITH_DRAW_EXPORT
{ "Page.Export.Draw", BROWSER_EXPORT_DRAW, dialog_saveas },
#endif
#ifdef WITH_PDF_EXPORT
{ "Page.Export.PDF", BROWSER_EXPORT_PDF, dialog_saveas },
#endif
{ "Page.Export.Text", BROWSER_EXPORT_TEXT, dialog_saveas },
{ "Page.SaveURL", NO_ACTION, 0 },
{ "Page.SaveURL.URI", BROWSER_SAVE_URL_URI, dialog_saveas },
@ -1520,15 +1527,18 @@ bool ro_gui_menu_handle_action(wimp_w owner, menu_action action,
case BROWSER_OBJECT_SAVE_URL_TEXT:
c = current_menu_object_box ?
current_menu_object_box->object : NULL;
/* Fall through */
case BROWSER_SAVE:
case BROWSER_SAVE_COMPLETE:
case BROWSER_EXPORT_DRAW:
case BROWSER_EXPORT_PDF:
case BROWSER_EXPORT_TEXT:
case BROWSER_SAVE_URL_URI:
case BROWSER_SAVE_URL_URL:
case BROWSER_SAVE_URL_TEXT:
if (!c)
return false;
/* Fall through */
case HOTLIST_EXPORT:
case HISTORY_EXPORT:
ro_gui_menu_prepare_action(owner, action, true);
@ -1872,6 +1882,7 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
if ((windows) && (current_menu_object_box))
ro_gui_menu_prepare_objectinfo(
current_menu_object_box);
/* Fall through */
case BROWSER_OBJECT_RELOAD:
ro_gui_menu_set_entry_shaded(current_menu, action,
!current_menu_object_box);
@ -1917,6 +1928,12 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
if ((c) && (windows))
ro_gui_save_prepare(GUI_SAVE_DRAW, c);
break;
case BROWSER_EXPORT_PDF:
ro_gui_menu_set_entry_shaded(current_menu,
action, !c);
if ((c) && (windows))
ro_gui_save_prepare(GUI_SAVE_PDF, c);
break;
case BROWSER_EXPORT_TEXT:
ro_gui_menu_set_entry_shaded(current_menu,
action, !c);
@ -1926,6 +1943,7 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
case BROWSER_OBJECT_SAVE_URL_URI:
c = current_menu_object_box ?
current_menu_object_box->object : NULL;
/* Fall through */
case BROWSER_SAVE_URL_URI:
ro_gui_menu_set_entry_shaded(current_menu,
action, !c);
@ -1935,6 +1953,7 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
case BROWSER_OBJECT_SAVE_URL_URL:
c = current_menu_object_box ?
current_menu_object_box->object : NULL;
/* Fall through */
case BROWSER_SAVE_URL_URL:
ro_gui_menu_set_entry_shaded(current_menu,
action, !c);
@ -1944,6 +1963,7 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
case BROWSER_OBJECT_SAVE_URL_TEXT:
c = current_menu_object_box ?
current_menu_object_box->object : NULL;
/* Fall through */
case BROWSER_SAVE_URL_TEXT:
ro_gui_menu_set_entry_shaded(current_menu,
action, !c);

View File

@ -76,6 +76,7 @@ typedef enum {
BROWSER_SAVE,
BROWSER_SAVE_COMPLETE,
BROWSER_EXPORT_DRAW,
BROWSER_EXPORT_PDF,
BROWSER_EXPORT_TEXT,
BROWSER_SAVE_URL_URI,
BROWSER_SAVE_URL_URL,

View File

@ -52,10 +52,10 @@ static bool ro_plot_disc(int x, int y, int radius, colour colour, bool filled);
static bool ro_plot_arc(int x, int y, int radius, int angle1, int angle2,
colour c);
static bool ro_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg);
struct bitmap *bitmap, colour bg, struct content *content);
static bool ro_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y);
bool repeat_x, bool repeat_y, struct content *content);
struct plotter_table plot;
@ -496,7 +496,7 @@ bool ro_plot_arc(int x, int y, int radius, int angle1, int angle2, colour c)
}
bool ro_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg)
struct bitmap *bitmap, colour bg, struct content *content)
{
char *buffer;
@ -521,7 +521,7 @@ bool ro_plot_bitmap(int x, int y, int width, int height,
bool ro_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y)
bool repeat_x, bool repeat_y, struct content *content)
{
char *buffer;

View File

@ -28,13 +28,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "oslib/dragasprite.h"
#include "oslib/osbyte.h"
#include "oslib/osfile.h"
#include "oslib/osmodule.h"
#include <oslib/dragasprite.h>
#include <oslib/osbyte.h>
#include <oslib/osfile.h>
#include <oslib/osmodule.h>
#include <oslib/osspriteop.h>
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
#include <oslib/wimp.h>
#include <oslib/wimpspriteop.h>
#include "desktop/netsurf.h"
#include "desktop/save_text.h"
#include "desktop/selection.h"
@ -47,6 +47,7 @@
#include "riscos/save.h"
#include "riscos/save_complete.h"
#include "riscos/save_draw.h"
#include "riscos/save_pdf.h"
#include "riscos/textselection.h"
#include "riscos/thumbnail.h"
#include "riscos/wimp.h"
@ -92,10 +93,12 @@ struct gui_save_table_entry {
/** Table of filetypes and default filenames. Must be in sync with
* gui_save_type (riscos/gui.h). A filetype of 0 indicates the content should
* be used. */
struct gui_save_table_entry gui_save_table[] = {
* be used.
*/
static const struct gui_save_table_entry gui_save_table[] = {
/* GUI_SAVE_SOURCE, */ { 0, "SaveSource" },
/* GUI_SAVE_DRAW, */ { 0xaff, "SaveDraw" },
/* GUI_SAVE_PDF, */ { 0xadf, "SavePDF" },
/* GUI_SAVE_TEXT, */ { 0xfff, "SaveText" },
/* GUI_SAVE_COMPLETE, */ { 0xfaf, "SaveComplete" },
/* GUI_SAVE_OBJECT_ORIG, */ { 0, "SaveObject" },
@ -633,7 +636,7 @@ void ro_gui_save_datasave_ack(wimp_message *message)
/**
* Does the actual saving
*
* \param c content to save (or 0 for other)
* \param c content to save (or NULL for other)
* \param path path to save as
* \return true on success, false on error and error reported
*/
@ -646,6 +649,10 @@ bool ro_gui_save_content(struct content *c, char *path)
#ifdef WITH_DRAW_EXPORT
case GUI_SAVE_DRAW:
return save_as_draw(c, path);
#endif
#ifdef WITH_PDF_EXPORT
case GUI_SAVE_PDF:
return save_as_pdf(c, path);
#endif
case GUI_SAVE_TEXT:
save_as_text(c, path);

View File

@ -54,10 +54,10 @@ static bool ro_save_draw_disc(int x, int y, int radius, colour colour,
static bool ro_save_draw_arc(int x, int y, int radius, int angle1, int angle2,
colour c);
static bool ro_save_draw_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg);
struct bitmap *bitmap, colour bg, struct content *content);
static bool ro_save_draw_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y);
bool repeat_x, bool repeat_y, struct content *content);
static bool ro_save_draw_group_start(const char *name);
static bool ro_save_draw_group_end(void);
static bool ro_save_draw_error(pencil_code code);
@ -377,7 +377,7 @@ bool ro_save_draw_arc(int x, int y, int radius, int angle1, int angle2,
}
bool ro_save_draw_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg)
struct bitmap *bitmap, colour bg, struct content *content)
{
pencil_code code;
char *buffer;
@ -401,7 +401,7 @@ bool ro_save_draw_bitmap(int x, int y, int width, int height,
bool ro_save_draw_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bool repeat_x, bool repeat_y)
bool repeat_x, bool repeat_y, struct content *content)
{
return true;
}

55
riscos/save_pdf.c Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright 2008 John Tytgat <John.Tytgat@aaug.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Export a content as a PDF file (implementation).
*/
#include <oslib/osfile.h>
#include "content/content.h"
#include "desktop/print.h"
#include "pdf/pdf_plotters.h"
#include "riscos/save_pdf.h"
#include "utils/log.h"
#include "utils/config.h"
#ifdef WITH_PDF_EXPORT
/**
* Export a content as a PDF file.
*
* \param c content to export
* \param path path to save PDF as
* \return true on success, false on error and error reported
*/
bool save_as_pdf(struct content *c, const char *path)
{
struct print_settings *psettings;
psettings = print_make_settings(DEFAULT);
if (psettings == NULL)
return false;
psettings->output = path;
if (!print_basic_run(c, &pdf_printer, psettings))
return false;
xosfile_set_type(path, 0xadf);
return true;
}
#endif

30
riscos/save_pdf.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright 2008 John Tytgat <John.Tytgat@aaug.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NETSURF_RISCOS_SAVE_PDF_H_
#define _NETSURF_RISCOS_SAVE_PDF_H_
#include "utils/config.h"
#ifdef WITH_PDF_EXPORT
struct content;
bool save_as_pdf(struct content *c, const char *path);
#endif
#endif

BIN
testres/jpeg.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
testres/png.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

68
testres/text.html Normal file
View File

@ -0,0 +1,68 @@
<html>
<head>
<title>Sample page with lots of text</title>
</head>
<body style='font-size:14pt;background-color:#CCFFCC;'>
<br><br><br><br><br><br><br><br>
This demonstrates the fuzzy margin at the bottom. After pdf-printing this page,
we can see the bottoms of letters printed just below the lower margin of this page.
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
a1312312312312dadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
a1312312312312dadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
a1312312312312dadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
a1312312312312dadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
asdadadafgsdsgsdfsdfsdfgdbbdfbxccvsds
</body>
</html>

29
testres/text2.html Normal file
View File

@ -0,0 +1,29 @@
<html>
<head>
<title>Sample page with some text</title>
<style type="text/css">
td {border: 2px;}
a { font-family: monospace;
font-weight: bold;
font-style: italic
}
body {font-style: oblique}
</style>
</head>
<body style='font-size:13pt;background-color:#CCFFCC;'>
<a href='http://www.google.co.uk/search?hl=en&q=making+a+very+long+hyperlink+to+demonstrate+how+it+will+be+broken+&btnG=Search&meta='>
http://www.google.co.uk/search?hl=en&q=making+a+very+long+hyperlink+to+demonstrate+how+it+will+be+broken+&btnG=Search&meta=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssss</a>
a1312312312312dadadafgsdsgsdddddddddddddddddddddddddddddfsdfsdfgdbbdfbxccvsdsddddddddddd
12345678901011121314151617181920212223242526272829303132333435363738394041424344454647484950
<table border=5>
<tr>
<td>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</td>
<td>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</td>
</tr>
<tr>
<td>bbbbbbbbbbbbbbbb</td>
<td>bbbbbbbbbbbbbb</td>
</tr>
</table>
</body>
</html>

View File

@ -35,7 +35,7 @@ char *strndup(const char *s, size_t n);
/* This section toggles build options on and off.
* Simply undefine a symbol to turn the relevant feature off.
*
* IF ADDING A FEATURE HERE, ADD IT TO Docs/Doxyfile LINE 892 AS WELL.
* IF ADDING A FEATURE HERE, ADD IT TO Docs/Doxyfile's "PREDEFINED" DEFINITION AS WELL.
*/
/* HTTP Auth */
@ -80,7 +80,14 @@ char *strndup(const char *s, size_t n);
#define WITH_RSVG
#endif
#endif
#if defined(riscos) || defined(DEBUG_BUILD)
/* Export modules */
#define WITH_SAVE_COMPLETE
#define WITH_DRAW_EXPORT
#define WITH_PDF_EXPORT
#endif
/* Configuration sanity checks: */
#if defined(WITH_NS_SVG) && defined(WITH_RSVG)
#error Cannot build WITH_NS_SVG and WITH_RSVG both enabled
#endif
@ -89,10 +96,4 @@ char *strndup(const char *s, size_t n);
#error Cannot build WITH_NSSPRITE and WITH_SPRITE both enabled
#endif
#if defined(riscos) || defined(DEBUG_BUILD)
/* Export modules */
#define WITH_SAVE_COMPLETE
#define WITH_DRAW_EXPORT
#endif
#endif