mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-22 20:16:54 +03:00
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:
parent
9fb65c7096
commit
35d3d6d0bb
@ -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.
|
||||
|
17
Makefile
17
Makefile
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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
280
desktop/print.c
Normal 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
75
desktop/print.h
Normal 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
41
desktop/printer.h
Normal 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
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
573
gtk/gtk_print.c
Normal 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, >k_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(>k_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, >k_printer);
|
||||
}
|
48
gtk/gtk_print.h
Normal file
48
gtk/gtk_print.h
Normal 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
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
19
pdf/TODO
Normal 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
373
pdf/font_haru.c
Normal 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
36
pdf/font_haru.h
Normal 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
774
pdf/pdf_plotters.c
Normal 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
40
pdf/pdf_plotters.h
Normal 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
36
pdf/pdf_printer.h
Normal 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
|
203
render/box.c
203
render/box.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
415
render/loosen.c
Normal 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
35
render/loosen.h
Normal 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
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
55
riscos/save_pdf.c
Normal 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
30
riscos/save_pdf.h
Normal 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
BIN
testres/jpeg.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
BIN
testres/png.png
Normal file
BIN
testres/png.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
68
testres/text.html
Normal file
68
testres/text.html
Normal 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
29
testres/text2.html
Normal 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>
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user