diff options
author | Richard Wilson <rjw@netsurf-browser.org> | 2006-07-01 18:16:05 +0000 |
---|---|---|
committer | Richard Wilson <rjw@netsurf-browser.org> | 2006-07-01 18:16:05 +0000 |
commit | cf4294d3a85518a6502ce63a58c0b05d5baab949 (patch) | |
tree | 86af17af135871cee20434cad3fbfecca9a7f310 | |
parent | f22838ab626bed6948b18bd6eeb28c8bdf210057 (diff) | |
download | netsurf-cf4294d3a85518a6502ce63a58c0b05d5baab949.tar.gz netsurf-cf4294d3a85518a6502ce63a58c0b05d5baab949.tar.bz2 |
Implement knockout rendering (controlled by 'knockout_rendering' option or Ctrl+F11, default is off). This attempts to minimise the amount of overlapping redraw performed, and thus can drasticly reduce the rendering time of many pages.
svn path=/trunk/netsurf/; revision=2682
-rw-r--r-- | desktop/knockout.c | 765 | ||||
-rw-r--r-- | desktop/knockout.h | 19 | ||||
-rw-r--r-- | desktop/options.c | 3 | ||||
-rw-r--r-- | desktop/options.h | 1 | ||||
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | render/html_redraw.c | 16 | ||||
-rw-r--r-- | riscos/window.c | 5 |
7 files changed, 808 insertions, 3 deletions
diff --git a/desktop/knockout.c b/desktop/knockout.c new file mode 100644 index 000000000..89ef58bc3 --- /dev/null +++ b/desktop/knockout.c @@ -0,0 +1,765 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson <info@tinct.net> + */ + +/** \file + * Knockout rendering (implementation). + */ + +#include <assert.h> +#include <string.h> +#include "netsurf/desktop/knockout.h" +#include "netsurf/desktop/plotters.h" +#include "netsurf/image/bitmap.h" +#include "netsurf/utils/log.h" + + +#define KNOCKOUT_BOXES 512 /* 28 bytes each */ +#define KNOCKOUT_ENTRIES 4096 /* 40 bytes each */ +#define KNOCKOUT_POLYGONS 512 /* 4 bytes each */ + +struct knockout_box; +struct knockout_entry; + +static void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *box); +static bool knockout_plot_fill_recursive(struct knockout_box *box, colour c); +static bool knockout_plot_bitmap_tile_recursive(struct knockout_box *box, + struct knockout_entry *entry); + +static bool knockout_plot_clg(colour c); +static bool knockout_plot_rectangle(int x0, int y0, int width, int height, + int line_width, colour c, bool dotted, bool dashed); +static bool knockout_plot_line(int x0, int y0, int x1, int y1, int width, + colour c, bool dotted, bool dashed); +static bool knockout_plot_polygon(int *p, unsigned int n, colour fill); +static bool knockout_plot_fill(int x0, int y0, int x1, int y1, colour c); +static bool knockout_plot_clip(int clip_x0, int clip_y0, + int clip_x1, int clip_y1); +static bool knockout_plot_text(int x, int y, struct css_style *style, + const char *text, size_t length, colour bg, colour c); +static bool knockout_plot_disc(int x, int y, int radius, colour colour, bool filled); +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); +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); +static bool knockout_plot_group_start(const char *name); +static bool knockout_plot_group_end(void); + + +struct knockout_entry knockout_entries[KNOCKOUT_ENTRIES]; +struct knockout_box knockout_boxes[KNOCKOUT_BOXES]; +int knockout_polygons[KNOCKOUT_POLYGONS]; +int knockout_entry_cur = 0; +int knockout_box_cur = 0; +int knockout_polygon_cur = 0; +struct knockout_box *knockout_list = NULL; + +struct plotter_table real_plot; + +int clip_x0_cur; +int clip_y0_cur; +int clip_x1_cur; +int clip_y1_cur; + + +const struct plotter_table knockout_plotters = { + knockout_plot_clg, + knockout_plot_rectangle, + knockout_plot_line, + knockout_plot_polygon, + knockout_plot_fill, + knockout_plot_clip, + knockout_plot_text, + knockout_plot_disc, + knockout_plot_arc, + knockout_plot_bitmap, + knockout_plot_bitmap_tile, + knockout_plot_group_start, + knockout_plot_group_end +}; + + +typedef enum { + KNOCKOUT_PLOT_CLG, /* translated to _FILL */ + KNOCKOUT_PLOT_RECTANGLE, + KNOCKOUT_PLOT_LINE, + KNOCKOUT_PLOT_POLYGON, + KNOCKOUT_PLOT_FILL, /* knockout, knocked out */ + KNOCKOUT_PLOT_CLIP, + KNOCKOUT_PLOT_TEXT, + KNOCKOUT_PLOT_DISC, + KNOCKOUT_PLOT_ARC, + KNOCKOUT_PLOT_BITMAP, /* knockout */ + KNOCKOUT_PLOT_BITMAP_TILE, /* knockout, knocked out */ + KNOCKOUT_PLOT_GROUP_START, + KNOCKOUT_PLOT_GROUP_END, +} knockout_type; + + +struct knockout_box { + struct { + int x0; + int y0; + int x1; + int y1; + } bbox; + bool deleted; /* box has been totally knocked out */ + struct knockout_box *child; + struct knockout_box *next; +}; + + +struct knockout_entry { + knockout_type type; + struct knockout_box *box; /* relating series of knockout clips */ + union { + struct { + colour c; + } clg; + struct { + int x0; + int y0; + int width; + int height; + int line_width; + colour c; + bool dotted; + bool dashed; + } rectangle; + struct { + int x0; + int y0; + int x1; + int y1; + int width; + colour c; + bool dotted; + bool dashed; + } line; + struct { + int *p; + unsigned int n; + colour fill; + } polygon; + struct { + int x0; + int y0; + int x1; + int y1; + colour c; + } fill; + struct { + int x0; + int y0; + int x1; + int y1; + } clip; + struct { + int x; + int y; + struct css_style *style; + const char *text; + size_t length; + colour bg; + colour c; + } text; + struct { + int x; + int y; + int radius; + colour colour; + bool filled; + } disc; + struct { + int x; + int y; + int radius; + int angle1; + int angle2; + colour c; + } arc; + struct { + int x; + int y; + int width; + int height; + struct bitmap *bitmap; + colour bg; + } bitmap; + struct { + int x; + int y; + int width; + int height; + struct bitmap *bitmap; + colour bg; + bool repeat_x; + bool repeat_y; + } bitmap_tile; + struct { + const char *name; + } group_start; + } data; +}; + + +/** + * Start a knockout plotting session + * + * \param plotter the plotter to use + * \return true on success, false otherwise + */ +bool knockout_plot_start(struct plotter_table *plotter) +{ + /* end any previous sessions */ + if (knockout_entry_cur > 0) + knockout_plot_end(); + + /* take over the plotter */ + real_plot = *plotter; + plot = knockout_plotters; + return true; +} + + +/** + * End a knockout plotting session + * + * \return true on success, false otherwise + */ +bool knockout_plot_end(void) +{ + int i; + bool success = true; + struct knockout_box *box; + + /* release our plotter */ + plot = real_plot; + + for (i = 0; i < knockout_entry_cur; i++) { + switch (knockout_entries[i].type) { + case KNOCKOUT_PLOT_CLG: + success &= plot.clg( + knockout_entries[i].data.clg.c); + break; + case KNOCKOUT_PLOT_RECTANGLE: + success &= plot.rectangle( + knockout_entries[i].data.rectangle.x0, + knockout_entries[i].data.rectangle.y0, + knockout_entries[i].data.rectangle.width, + knockout_entries[i].data.rectangle.height, + knockout_entries[i].data.rectangle.line_width, + knockout_entries[i].data.rectangle.c, + knockout_entries[i].data.rectangle.dotted, + knockout_entries[i].data.rectangle.dashed); + break; + case KNOCKOUT_PLOT_LINE: + success &= plot.line( + knockout_entries[i].data.line.x0, + knockout_entries[i].data.line.y0, + knockout_entries[i].data.line.x1, + knockout_entries[i].data.line.y1, + knockout_entries[i].data.line.width, + knockout_entries[i].data.line.c, + knockout_entries[i].data.line.dotted, + knockout_entries[i].data.line.dashed); + break; + case KNOCKOUT_PLOT_POLYGON: + success &= plot.polygon( + knockout_entries[i].data.polygon.p, + knockout_entries[i].data.polygon.n, + knockout_entries[i].data.polygon.fill); + break; + case KNOCKOUT_PLOT_FILL: + box = knockout_entries[i].box->child; + if (box) + success &= knockout_plot_fill_recursive(box, + knockout_entries[i].data.fill.c); + else if (!knockout_entries[i].box->deleted) + success &= plot.fill( + knockout_entries[i].data.fill.x0, + knockout_entries[i].data.fill.y0, + knockout_entries[i].data.fill.x1, + knockout_entries[i].data.fill.y1, + knockout_entries[i].data.fill.c); + break; + case KNOCKOUT_PLOT_CLIP: + success &= plot.clip( + knockout_entries[i].data.clip.x0, + knockout_entries[i].data.clip.y0, + knockout_entries[i].data.clip.x1, + knockout_entries[i].data.clip.y1); + break; + case KNOCKOUT_PLOT_TEXT: + success &= plot.text( + knockout_entries[i].data.text.x, + knockout_entries[i].data.text.y, + knockout_entries[i].data.text.style, + knockout_entries[i].data.text.text, + knockout_entries[i].data.text.length, + knockout_entries[i].data.text.bg, + knockout_entries[i].data.text.c); + break; + case KNOCKOUT_PLOT_DISC: + success &= plot.disc( + knockout_entries[i].data.disc.x, + knockout_entries[i].data.disc.y, + knockout_entries[i].data.disc.radius, + knockout_entries[i].data.disc.colour, + knockout_entries[i].data.disc.filled); + break; + case KNOCKOUT_PLOT_ARC: + success &= plot.arc( + knockout_entries[i].data.arc.x, + knockout_entries[i].data.arc.y, + knockout_entries[i].data.arc.radius, + knockout_entries[i].data.arc.angle1, + knockout_entries[i].data.arc.angle2, + knockout_entries[i].data.arc.c); + break; + case KNOCKOUT_PLOT_BITMAP: + success &= plot.bitmap( + knockout_entries[i].data.bitmap.x, + knockout_entries[i].data.bitmap.y, + knockout_entries[i].data.bitmap.width, + knockout_entries[i].data.bitmap.height, + knockout_entries[i].data.bitmap.bitmap, + knockout_entries[i].data.bitmap.bg); + break; + case KNOCKOUT_PLOT_BITMAP_TILE: + box = knockout_entries[i].box->child; + if (box) { + success &= knockout_plot_bitmap_tile_recursive(box, + &knockout_entries[i]); + success &= plot.clip(knockout_entries[i].box->bbox.x0, + knockout_entries[i].box->bbox.y0, + knockout_entries[i].box->bbox.x1, + knockout_entries[i].box->bbox.y1); + } else if (!knockout_entries[i].box->deleted) { + success &= plot.bitmap_tile( + knockout_entries[i].data. + bitmap_tile.x, + knockout_entries[i].data. + bitmap_tile.y, + knockout_entries[i].data. + bitmap_tile.width, + knockout_entries[i].data. + bitmap_tile.height, + knockout_entries[i].data. + bitmap_tile.bitmap, + knockout_entries[i].data. + bitmap_tile.bg, + knockout_entries[i].data. + bitmap_tile.repeat_x, + knockout_entries[i].data. + bitmap_tile.repeat_y); + } + break; + case KNOCKOUT_PLOT_GROUP_START: + success &= plot.group_start( + knockout_entries[i].data.group_start.name); + break; + case KNOCKOUT_PLOT_GROUP_END: + success &= plot.group_end(); + break; + } + } + + knockout_entry_cur = 0; + knockout_box_cur = 0; + knockout_polygon_cur = 0; + knockout_list = NULL; + return success; +} + + +/** + * Knockout a section of previous rendering + * + * \param x0 the left edge of the removal box + * \param y0 the bottom edge of the removal box + * \param x1 the right edge of the removal box + * \param y1 the top edge of the removal box + * \param box the current box set to consider +*/ +void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *box) +{ + struct knockout_box *parent; + int nx0, ny0, nx1, ny1; + + for (parent = box; parent; parent = parent->next) { + if (parent->deleted) + continue; + /* reject non-overlapping boxes */ + if ((parent->bbox.x0 >= x1) || + (parent->bbox.x1 <= x0) || + (parent->bbox.y0 >= y1) || + (parent->bbox.y1 <= y0)) + continue; + /* has the box been replaced by children? */ + if (parent->child) { + knockout_calculate(x0, y0, x1, y1, parent->child); + } else { + nx0 = parent->bbox.x0; + ny0 = parent->bbox.y0; + nx1 = parent->bbox.x1; + ny1 = parent->bbox.y1; + + /* check for a total knockout */ + if ((x0 <= nx0) && (x1 >= nx1) && (y0 <= ny0) && (y1 >= ny1)) { + parent->deleted = true; + continue; + } + + /* we need a maximum of 4 child boxes */ + if (knockout_box_cur + 4 >= KNOCKOUT_ENTRIES) { + knockout_plot_start(&real_plot); + return; + } + + /* clip top */ + if (y1 < ny1) { + knockout_boxes[knockout_box_cur].bbox.x0 = nx0; + knockout_boxes[knockout_box_cur].bbox.y0 = y1; + knockout_boxes[knockout_box_cur].bbox.x1 = nx1; + knockout_boxes[knockout_box_cur].bbox.y1 = ny1; + knockout_boxes[knockout_box_cur].deleted = false; + knockout_boxes[knockout_box_cur].child = NULL; + knockout_boxes[knockout_box_cur].next = parent->child; + parent->child = &knockout_boxes[knockout_box_cur++]; + ny1 = y1; + } + /* clip bottom */ + if (y0 > ny0) { + knockout_boxes[knockout_box_cur].bbox.x0 = nx0; + knockout_boxes[knockout_box_cur].bbox.y0 = ny0; + knockout_boxes[knockout_box_cur].bbox.x1 = nx1; + knockout_boxes[knockout_box_cur].bbox.y1 = y0; + knockout_boxes[knockout_box_cur].deleted = false; + knockout_boxes[knockout_box_cur].child = NULL; + knockout_boxes[knockout_box_cur].next = parent->child; + parent->child = &knockout_boxes[knockout_box_cur++]; + ny0 = y0; + } + /* clip right */ + if (x1 < nx1) { + knockout_boxes[knockout_box_cur].bbox.x0 = x1; + knockout_boxes[knockout_box_cur].bbox.y0 = ny0; + knockout_boxes[knockout_box_cur].bbox.x1 = nx1; + knockout_boxes[knockout_box_cur].bbox.y1 = ny1; + knockout_boxes[knockout_box_cur].deleted = false; + knockout_boxes[knockout_box_cur].child = NULL; + knockout_boxes[knockout_box_cur].next = parent->child; + parent->child = &knockout_boxes[knockout_box_cur++]; + nx1 = x1; + } + /* clip left */ + if (x0 > nx0) { + knockout_boxes[knockout_box_cur].bbox.x0 = nx0; + knockout_boxes[knockout_box_cur].bbox.y0 = ny0; + knockout_boxes[knockout_box_cur].bbox.x1 = x0; + knockout_boxes[knockout_box_cur].bbox.y1 = ny1; + knockout_boxes[knockout_box_cur].deleted = false; + knockout_boxes[knockout_box_cur].child = NULL; + knockout_boxes[knockout_box_cur].next = parent->child; + parent->child = &knockout_boxes[knockout_box_cur++]; + //nx0 = x0; + } + } + } +} + + +bool knockout_plot_fill_recursive(struct knockout_box *box, colour c) +{ + bool success = true; + struct knockout_box *parent; + + for (parent = box; parent; parent = parent->next) { + if (parent->deleted) + continue; + if (parent->child) + knockout_plot_fill_recursive(parent->child, c); + else + success &= plot.fill(parent->bbox.x0, + parent->bbox.y0, + parent->bbox.x1, + parent->bbox.y1, + c); + } + return success; +} + + +bool knockout_plot_bitmap_tile_recursive(struct knockout_box *box, + struct knockout_entry *entry) +{ + bool success = true; + struct knockout_box *parent; + + for (parent = box; parent; parent = parent->next) { + if (parent->deleted) + continue; + if (parent->child) + knockout_plot_bitmap_tile_recursive(parent->child, entry); + else { + success &= plot.clip(parent->bbox.x0, + parent->bbox.y0, + parent->bbox.x1, + parent->bbox.y1); + success &= plot.bitmap_tile(entry->data.bitmap_tile.x, + entry->data.bitmap_tile.y, + entry->data.bitmap_tile.width, + entry->data.bitmap_tile.height, + entry->data.bitmap_tile.bitmap, + entry->data.bitmap_tile.bg, + entry->data.bitmap_tile.repeat_x, + entry->data.bitmap_tile.repeat_y); + } + } + return success; +} + +bool knockout_plot_clg(colour c) +{ + return knockout_plot_fill(clip_x0_cur, clip_y0_cur, clip_x1_cur, clip_y1_cur, c); +} + + +bool knockout_plot_rectangle(int x0, int y0, int width, int height, + int line_width, colour c, bool dotted, bool dashed) +{ + knockout_entries[knockout_entry_cur].data.rectangle.x0 = x0; + knockout_entries[knockout_entry_cur].data.rectangle.y0 = y0; + knockout_entries[knockout_entry_cur].data.rectangle.width = width; + knockout_entries[knockout_entry_cur].data.rectangle.height = height; + knockout_entries[knockout_entry_cur].data.rectangle.line_width = line_width; + knockout_entries[knockout_entry_cur].data.rectangle.c = c; + knockout_entries[knockout_entry_cur].data.rectangle.dotted = dotted; + knockout_entries[knockout_entry_cur].data.rectangle.dashed = dashed; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_RECTANGLE; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_line(int x0, int y0, int x1, int y1, int width, + colour c, bool dotted, bool dashed) +{ + knockout_entries[knockout_entry_cur].data.line.x0 = x0; + knockout_entries[knockout_entry_cur].data.line.y0 = y0; + knockout_entries[knockout_entry_cur].data.line.x1 = x1; + knockout_entries[knockout_entry_cur].data.line.y1 = y1; + knockout_entries[knockout_entry_cur].data.line.width = width; + knockout_entries[knockout_entry_cur].data.line.c = c; + knockout_entries[knockout_entry_cur].data.line.dotted = dotted; + knockout_entries[knockout_entry_cur].data.line.dashed = dashed; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_LINE; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_polygon(int *p, unsigned int n, colour fill) +{ + bool success = true; + int *dest; + + /* ensure we have sufficient room even when flushed */ + if (n * 2 >= KNOCKOUT_POLYGONS) { + knockout_plot_end(); + success = plot.polygon(p, n, fill); + knockout_plot_start(&real_plot); + return success; + } + + /* ensure we have enough room right now */ + if (knockout_polygon_cur + n * 2 >= KNOCKOUT_POLYGONS) + knockout_plot_start(&real_plot); + + /* copy our data */ + dest = &(knockout_polygons[knockout_polygon_cur]); + memcpy(dest, p, n * 2 * sizeof(int)); + knockout_polygon_cur += n * 2; + knockout_entries[knockout_entry_cur].data.polygon.p = dest; + knockout_entries[knockout_entry_cur].data.polygon.n = n; + knockout_entries[knockout_entry_cur].data.polygon.fill = fill; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_POLYGON; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_fill(int x0, int y0, int x1, int y1, colour c) +{ + /* fills both knock out and get knocked out */ + knockout_calculate(x0, y0, x1, y1, knockout_list); + knockout_boxes[knockout_box_cur].bbox.x0 = x0; + knockout_boxes[knockout_box_cur].bbox.y0 = y0; + knockout_boxes[knockout_box_cur].bbox.x1 = x1; + knockout_boxes[knockout_box_cur].bbox.y1 = y1; + knockout_boxes[knockout_box_cur].deleted = false; + knockout_boxes[knockout_box_cur].child = NULL; + knockout_boxes[knockout_box_cur].next = knockout_list; + knockout_list = &knockout_boxes[knockout_box_cur]; + knockout_entries[knockout_entry_cur].box = &knockout_boxes[knockout_box_cur]; + knockout_entries[knockout_entry_cur].data.fill.x0 = x0; + knockout_entries[knockout_entry_cur].data.fill.y0 = y0; + knockout_entries[knockout_entry_cur].data.fill.x1 = x1; + knockout_entries[knockout_entry_cur].data.fill.y1 = y1; + knockout_entries[knockout_entry_cur].data.fill.c = c; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_FILL; + if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) || + (++knockout_box_cur >= KNOCKOUT_BOXES)) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_clip(int clip_x0, int clip_y0, + int clip_x1, int clip_y1) +{ + if (clip_x1 < clip_x0 || clip_y0 > clip_y1) { + LOG(("bad clip rectangle %i %i %i %i", + clip_x0, clip_y0, clip_x1, clip_y1)); + return false; + } + + /* memorise clip for bitmap tiling */ + clip_x0_cur = clip_x0; + clip_y0_cur = clip_y0; + clip_x1_cur = clip_x1; + clip_y1_cur = clip_y1; + + knockout_entries[knockout_entry_cur].data.clip.x0 = clip_x0; + knockout_entries[knockout_entry_cur].data.clip.y0 = clip_y0; + knockout_entries[knockout_entry_cur].data.clip.x1 = clip_x1; + knockout_entries[knockout_entry_cur].data.clip.y1 = clip_y1; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_CLIP; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_text(int x, int y, struct css_style *style, + const char *text, size_t length, colour bg, colour c) +{ + knockout_entries[knockout_entry_cur].data.text.x = x; + knockout_entries[knockout_entry_cur].data.text.y = y; + knockout_entries[knockout_entry_cur].data.text.style = style; + knockout_entries[knockout_entry_cur].data.text.text = text; + knockout_entries[knockout_entry_cur].data.text.length = length; + knockout_entries[knockout_entry_cur].data.text.bg = bg; + knockout_entries[knockout_entry_cur].data.text.c = c; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_TEXT; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_disc(int x, int y, int radius, colour colour, bool filled) +{ + knockout_entries[knockout_entry_cur].data.disc.x = x; + knockout_entries[knockout_entry_cur].data.disc.y = y; + knockout_entries[knockout_entry_cur].data.disc.radius = radius; + knockout_entries[knockout_entry_cur].data.disc.colour = colour; + knockout_entries[knockout_entry_cur].data.disc.filled = filled; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_DISC; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + +bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, colour c) +{ + knockout_entries[knockout_entry_cur].data.arc.x = x; + knockout_entries[knockout_entry_cur].data.arc.y = y; + knockout_entries[knockout_entry_cur].data.arc.radius = radius; + knockout_entries[knockout_entry_cur].data.arc.angle1 = angle1; + knockout_entries[knockout_entry_cur].data.arc.angle2 = angle2; + knockout_entries[knockout_entry_cur].data.arc.c = c; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_ARC; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + +bool knockout_plot_bitmap(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg) +{ + /* opaque bitmaps knockout, but don't get knocked out */ + if (bitmap_get_opaque(bitmap)) + knockout_calculate(x, y, x + width, y + height, knockout_list); + knockout_entries[knockout_entry_cur].data.bitmap.x = x; + knockout_entries[knockout_entry_cur].data.bitmap.x = x; + knockout_entries[knockout_entry_cur].data.bitmap.y = y; + knockout_entries[knockout_entry_cur].data.bitmap.width = width; + 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].type = KNOCKOUT_PLOT_BITMAP; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + + +bool knockout_plot_bitmap_tile(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bool repeat_x, bool repeat_y) +{ + /* tiled bitmaps both knock out and get knocked out */ + if (bitmap_get_opaque(bitmap)) + knockout_calculate(clip_x0_cur, clip_y0_cur, clip_x1_cur, clip_y1_cur, + knockout_list); + knockout_boxes[knockout_box_cur].bbox.x0 = clip_x0_cur; + knockout_boxes[knockout_box_cur].bbox.y0 = clip_y0_cur; + knockout_boxes[knockout_box_cur].bbox.x1 = clip_x1_cur; + knockout_boxes[knockout_box_cur].bbox.y1 = clip_y1_cur; + knockout_boxes[knockout_box_cur].deleted = false; + knockout_boxes[knockout_box_cur].child = NULL; + knockout_boxes[knockout_box_cur].next = knockout_list; + knockout_list = &knockout_boxes[knockout_box_cur]; + knockout_entries[knockout_entry_cur].box = &knockout_boxes[knockout_box_cur]; + knockout_entries[knockout_entry_cur].data.bitmap_tile.x = x; + knockout_entries[knockout_entry_cur].data.bitmap_tile.y = y; + knockout_entries[knockout_entry_cur].data.bitmap_tile.width = width; + knockout_entries[knockout_entry_cur].data.bitmap_tile.height = height; + knockout_entries[knockout_entry_cur].data.bitmap_tile.bitmap = bitmap; + 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].type = KNOCKOUT_PLOT_BITMAP_TILE; + if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) || + (++knockout_box_cur >= KNOCKOUT_BOXES)) + knockout_plot_start(&real_plot); + return true; +} + +bool knockout_plot_group_start(const char *name) +{ + knockout_entries[knockout_entry_cur].data.group_start.name = name; + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_START; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} + +bool knockout_plot_group_end(void) +{ + knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_END; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) + knockout_plot_start(&real_plot); + return true; +} diff --git a/desktop/knockout.h b/desktop/knockout.h new file mode 100644 index 000000000..d564ee6f0 --- /dev/null +++ b/desktop/knockout.h @@ -0,0 +1,19 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson <info@tinct.net> + */ + +/** \file + * Knockout rendering (interface). + */ + +#include "netsurf/desktop/plotters.h" + + +bool knockout_plot_start(struct plotter_table *plotter); +bool knockout_plot_end(void); + + +extern const struct plotter_table knockout_plotters; diff --git a/desktop/options.c b/desktop/options.c index 1787e55a5..d01caad61 100644 --- a/desktop/options.c +++ b/desktop/options.c @@ -101,6 +101,8 @@ int option_max_fetchers_per_host = 5; * is this plus option_max_fetchers. */ int option_max_cached_fetch_handles = 6; +/** Whether to use knockout rendering */ +bool option_knockout_rendering = false; EXTRA_OPTION_DEFINE @@ -142,6 +144,7 @@ struct { OPTION_INTEGER, &option_max_fetchers_per_host }, { "max_cached_fetch_handles", OPTION_INTEGER, &option_max_cached_fetch_handles }, + { "knockout_rendering", OPTION_BOOL, &option_knockout_rendering }, EXTRA_OPTION_TABLE }; diff --git a/desktop/options.h b/desktop/options.h index 35e1d62a9..08e808b99 100644 --- a/desktop/options.h +++ b/desktop/options.h @@ -55,6 +55,7 @@ extern char *option_ca_bundle; extern char *option_cookie_file; extern char *option_cookie_jar; extern char *option_homepage_url; +extern bool option_knockout_rendering; /* Fetcher configuration. */ extern int option_max_fetchers; @@ -24,7 +24,7 @@ OBJECTS_COMMON += box.o box_construct.o box_normalise.o form.o \ table.o textplain.o # render/ OBJECTS_COMMON += filename.o messages.o talloc.o url.o utf8.o \ utils.o # utils/ -OBJECTS_COMMON += options.o tree.o # desktop/ +OBJECTS_COMMON += knockout.o options.o tree.o # desktop/ OBJECTS_IMAGE = bmp.o bmpread.o gif.o gifread.o ico.o jpeg.o \ mng.o # image/ diff --git a/render/html_redraw.c b/render/html_redraw.c index aeac805ab..3e70168c0 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -17,8 +17,10 @@ #include "netsurf/css/css.h" #include "netsurf/desktop/gui.h" #include "netsurf/desktop/plotters.h" +#include "netsurf/desktop/knockout.h" #include "netsurf/desktop/selection.h" #include "netsurf/desktop/textinput.h" +#include "netsurf/desktop/options.h" #include "netsurf/render/box.h" #include "netsurf/render/font.h" #include "netsurf/render/form.h" @@ -70,7 +72,6 @@ static bool html_redraw_scrollbars(struct box *box, float scale, bool html_redraw_debug = false; - /** * Draw a CONTENT_HTML using the current set of plotters (plot). * @@ -96,18 +97,29 @@ bool html_redraw(struct content *c, int x, int y, float scale, unsigned long background_colour) { struct box *box; + bool result; box = c->data.html.layout; assert(box); + if (option_knockout_rendering) + knockout_plot_start(&plot); + /* clear to background colour */ + plot.clip(clip_x0, clip_y0, clip_x1, clip_y1); if (c->data.html.background_colour != TRANSPARENT) background_colour = c->data.html.background_colour; plot.clg(background_colour); - return html_redraw_box(box, x, y, + result = html_redraw_box(box, x, y, clip_x0, clip_y0, clip_x1, clip_y1, scale, background_colour); + + if (option_knockout_rendering) + knockout_plot_end(); + + return result; + } diff --git a/riscos/window.c b/riscos/window.c index 0864ecf8a..9b8e3ac10 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -2031,6 +2031,11 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar) return ro_gui_menu_handle_action(g->window, BROWSER_SCALE_VIEW, false); + case wimp_KEY_CONTROL + wimp_KEY_F11: /* Toggle knockout rendering */ + option_knockout_rendering = !option_knockout_rendering; + gui_window_redraw_window(g); + return true; + case wimp_KEY_SHIFT + wimp_KEY_F11: /* Toggle display of box outlines. */ html_redraw_debug = !html_redraw_debug; gui_window_redraw_window(g); |