summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-07-14 19:42:57 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2011-07-14 19:42:57 +0000
commitefbf9755460d4c4b7a3d9d43dd753afcc8a28865 (patch)
tree41a259211da187e29f9983821b4cdfea221b6ad6 /src/display
parentFix crashes in print preview (diff)
parentMake cms_key in SPDesktopWidget a regular ustring rather than a pointer (diff)
downloadinkscape-efbf9755460d4c4b7a3d9d43dd753afcc8a28865.tar.gz
inkscape-efbf9755460d4c4b7a3d9d43dd753afcc8a28865.zip
Merge SPCanvasArena caching layer work
(bzr r10451)
Diffstat (limited to 'src/display')
-rw-r--r--src/display/canvas-arena.cpp154
-rw-r--r--src/display/canvas-arena.h4
-rw-r--r--src/display/canvas-axonomgrid.cpp25
-rw-r--r--src/display/canvas-grid.cpp12
-rw-r--r--src/display/guideline.cpp12
-rw-r--r--src/display/nr-arena-glyphs.cpp45
-rw-r--r--src/display/nr-arena-group.cpp12
-rw-r--r--src/display/nr-arena-image.cpp2
-rw-r--r--src/display/nr-arena-item.cpp274
-rw-r--r--src/display/nr-arena-item.h2
-rw-r--r--src/display/nr-arena-shape.cpp45
-rw-r--r--src/display/nr-arena-shape.h1
-rw-r--r--src/display/nr-arena.cpp1
-rw-r--r--src/display/nr-filter-composite.cpp1
-rw-r--r--src/display/nr-filter-displacement-map.cpp189
-rw-r--r--src/display/nr-filter-gaussian.cpp2
-rw-r--r--src/display/nr-filter-slot.cpp2
-rw-r--r--src/display/nr-filter-turbulence.cpp1
-rw-r--r--src/display/nr-filter-turbulence.h1
-rw-r--r--src/display/nr-filter-units.cpp17
-rw-r--r--src/display/nr-filter-units.h2
-rw-r--r--src/display/nr-filter.cpp10
-rw-r--r--src/display/sp-canvas-item.h4
-rw-r--r--src/display/sp-canvas.cpp67
-rw-r--r--src/display/sp-canvas.h7
25 files changed, 444 insertions, 448 deletions
diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp
index 6930e4d7c..dd4a4ed5c 100644
--- a/src/display/canvas-arena.cpp
+++ b/src/display/canvas-arena.cpp
@@ -31,7 +31,10 @@ static void sp_canvas_arena_destroy(GtkObject *object);
static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf);
+static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area);
+static void sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area);
static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
+static void sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area);
static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event);
static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event);
@@ -93,6 +96,7 @@ sp_canvas_arena_class_init (SPCanvasArenaClass *klass)
item_class->render = sp_canvas_arena_render;
item_class->point = sp_canvas_arena_point;
item_class->event = sp_canvas_arena_event;
+ item_class->visible_area_changed = sp_canvas_arena_visible_area_changed;
}
static void
@@ -106,6 +110,9 @@ sp_canvas_arena_init (SPCanvasArena *arena)
nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE);
arena->active = NULL;
+ arena->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
+ arena->cache_area = Geom::IntRect::from_xywh(0,0,1,1);
+ arena->dirty = cairo_region_create();
nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena);
}
@@ -131,6 +138,11 @@ sp_canvas_arena_destroy (GtkObject *object)
nr_object_unref ((NRObject *) arena->arena);
arena->arena = NULL;
}
+ if (arena->cache) {
+ cairo_surface_destroy(arena->cache);
+ arena->cache = NULL;
+ }
+ cairo_region_destroy(arena->dirty);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
@@ -187,33 +199,74 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
static void
sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf)
{
- gint bw, bh;
-
SPCanvasArena *arena = SP_CANVAS_ARENA (item);
//SPCanvas *canvas = item->canvas;
- nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
- NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER,
- NR_ARENA_ITEM_STATE_NONE);
+ //nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
+ // NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER,
+ // NR_ARENA_ITEM_STATE_NONE);
+
+ Geom::OptIntRect r = buf->rect;
+ if (!r || r->hasZeroArea()) return;
+
+ cairo_rectangle_int_t crect;
+ crect.x = r->left();
+ crect.y = r->top();
+ crect.width = r->width();
+ crect.height = r->height();
+ if (cairo_region_contains_rectangle(arena->dirty, &crect) != CAIRO_REGION_OVERLAP_OUT) {
+ sp_canvas_arena_render_cache(item, *r);
+ cairo_region_subtract_rectangle(arena->dirty, &crect);
+ }
- sp_canvas_prepare_buffer(buf);
+ cairo_save(buf->ct);
+ cairo_translate(buf->ct, -r->left(), -r->top());
+ //cairo_rectangle(buf->ct, r->left(), r->top(), r->width(), r->height());
+ //cairo_clip(buf->ct);
+ cairo_set_source_surface(buf->ct, arena->cache, arena->cache_area.left(), arena->cache_area.top());
+ cairo_paint(buf->ct);
+ //nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0);
+ cairo_restore(buf->ct);
+}
- bw = buf->rect.x1 - buf->rect.x0;
- bh = buf->rect.y1 - buf->rect.y0;
- if ((bw < 1) || (bh < 1)) return;
+static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area)
+{
+ SPCanvasArena *arena = SP_CANVAS_ARENA (item);
+
+ Geom::OptIntRect r = Geom::intersect(arena->cache_area, area);
+ if (!r || r->hasZeroArea()) return; // nothing to do
+
+ cairo_t *ct = cairo_create(arena->cache);
+ cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top());
+
+ // clear area to paint
+ cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height());
+ cairo_clip(ct);
+ cairo_save(ct);
+ cairo_set_source_rgba(ct, 0,0,0,0);
+ cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ct);
+ cairo_restore(ct);
+
+ NRRectL nr_area(r);
- NRRectL area;
+ nr_arena_item_invoke_update (arena->root, NULL, &arena->gc,
+ NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER,
+ NR_ARENA_ITEM_STATE_NONE);
+ nr_arena_item_invoke_render (ct, arena->root, &nr_area, NULL, 0);
- area.x0 = buf->rect.x0;
- area.y0 = buf->rect.y0;
- area.x1 = buf->rect.x1;
- area.y1 = buf->rect.y1;
+ cairo_destroy(ct);
+}
- sp_canvas_prepare_buffer(buf);
- cairo_save(buf->ct);
- cairo_translate(buf->ct, -area.x0, -area.y0);
- nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0);
- cairo_restore(buf->ct);
+static void
+sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area)
+{
+ cairo_rectangle_int_t rect;
+ rect.x = area->x0;
+ rect.y = area->y0;
+ rect.width = area->x1 - area->x0;
+ rect.height = area->y1 - area->y0;
+ cairo_region_union_rectangle(arena->dirty, &rect);
}
static double
@@ -237,6 +290,67 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_
return 1e18;
}
+static void
+sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area)
+{
+ SPCanvasArena *arena = SP_CANVAS_ARENA(item);
+
+ cairo_surface_t *new_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ new_area.width(), new_area.height());
+ cairo_t *ct = cairo_create(new_cache);
+ cairo_set_source_surface(ct, arena->cache, old_area.left() - new_area.left(), old_area.top() - new_area.top());
+ cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ct);
+ cairo_destroy(ct);
+ cairo_surface_destroy(arena->cache);
+ arena->cache = new_cache;
+ arena->cache_area = new_area;
+
+ cairo_rectangle_int_t crect;
+ crect.x = new_area.left();
+ crect.y = new_area.top();
+ crect.width = new_area.width();
+ crect.height = new_area.height();
+ cairo_region_intersect_rectangle(arena->dirty, &crect);
+
+ // invalidate newly exposed areas
+ /*
+ * +----------------------+
+ * | top strip |
+ * +-------+------+-------+
+ * | | | |
+ * | left | old | right |
+ * | strip | area | strip |
+ * | | | |
+ * +-------+------+-------+
+ * | bottom strip |
+ * +----------------------+
+ */
+
+ // top strip
+ if (new_area.top() < old_area.top()) {
+ NRRectL top_strip(new_area.left(), new_area.top(), new_area.right(), old_area.top());
+ sp_canvas_arena_dirty_cache(arena, &top_strip);
+ }
+ // left strip
+ if (new_area.left() < old_area.left()) {
+ NRRectL left_strip(new_area.left(), std::max(new_area.top(), old_area.top()),
+ old_area.left(), std::min(new_area.bottom(), old_area.bottom()));
+ sp_canvas_arena_dirty_cache(arena, &left_strip);
+ }
+ // right strip
+ if (new_area.right() > old_area.right()) {
+ NRRectL right_strip(old_area.right(), std::max(new_area.top(), old_area.top()),
+ new_area.right(), std::min(new_area.bottom(), old_area.bottom()));
+ sp_canvas_arena_dirty_cache(arena, &right_strip);
+ }
+ // bottom strip
+ if (new_area.bottom() > old_area.bottom()) {
+ NRRectL bottom_strip(new_area.left(), old_area.bottom(), new_area.right(), new_area.bottom());
+ sp_canvas_arena_dirty_cache(arena, &bottom_strip);
+ }
+}
+
static gint
sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event)
{
@@ -336,6 +450,8 @@ sp_canvas_arena_request_update (NRArena */*arena*/, NRArenaItem */*item*/, void
static void
sp_canvas_arena_request_render (NRArena */*arena*/, NRRectL *area, void *data)
{
+ if (!area) return;
+ sp_canvas_arena_dirty_cache (SP_CANVAS_ARENA(data), area);
sp_canvas_request_redraw (SP_CANVAS_ITEM (data)->canvas, area->x0, area->y0, area->x1, area->y1);
}
diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h
index 4cfeccb5a..220976da0 100644
--- a/src/display/canvas-arena.h
+++ b/src/display/canvas-arena.h
@@ -45,6 +45,10 @@ struct _SPCanvasArena {
/* fixme: */
NRArenaItem *picked;
gdouble delta;
+
+ Geom::IntRect cache_area;
+ cairo_surface_t *cache;
+ cairo_region_t *dirty;
};
struct _SPCanvasArenaClass {
diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp
index dbf7b424d..ec2d35f69 100644
--- a/src/display/canvas-axonomgrid.cpp
+++ b/src/display/canvas-axonomgrid.cpp
@@ -33,6 +33,7 @@
#include "svg/svg-color.h"
#include "util/mathfns.h"
#include "xml/node-event-vector.h"
+#include "round.h"
#define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params
@@ -549,13 +550,13 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
// x-axis always goes from topleft to bottomright. (0,0) - (1,1)
gdouble const xintercept_y_bc = (buf_tl_gc[Geom::X] * tan_angle[X]) - buf_tl_gc[Geom::Y] ;
gdouble const xstart_y_sc = ( xintercept_y_bc - floor(xintercept_y_bc/lyw)*lyw ) + buf->rect.y0;
- gint const xlinestart = (gint) Inkscape::round( (xstart_y_sc - buf->rect.x0*tan_angle[X] -ow[Geom::Y]) / lyw );
+ gint const xlinestart = round( (xstart_y_sc - buf->rect.x0*tan_angle[X] -ow[Geom::Y]) / lyw );
gint xlinenum = xlinestart;
// lines starting on left side.
for (y = xstart_y_sc; y < buf->rect.y1; y += lyw, xlinenum++) {
gint const x0 = buf->rect.x0;
- gint const y0 = (gint) Inkscape::round(y);
- gint const x1 = x0 + (gint) Inkscape::round( (buf->rect.y1 - y) / tan_angle[X] );
+ gint const y0 = round(y);
+ gint const x1 = x0 + round( (buf->rect.y1 - y) / tan_angle[X] );
gint const y1 = buf->rect.y1;
if (!scaled && (xlinenum % empspacing) != 0) {
@@ -570,8 +571,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
for (x = xstart_x_sc; x < buf->rect.x1; x += lxw_x, xlinenum--) {
gint const y0 = buf->rect.y0;
gint const y1 = buf->rect.y1;
- gint const x0 = (gint) Inkscape::round(x);
- gint const x1 = x0 + (gint) Inkscape::round( (y1 - y0) / tan_angle[X] );
+ gint const x0 = round(x);
+ gint const x1 = x0 + round( (y1 - y0) / tan_angle[X] );
if (!scaled && (xlinenum % empspacing) != 0) {
sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
@@ -582,10 +583,10 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
// y-axis lines (vertical)
gdouble const ystart_x_sc = floor (buf_tl_gc[Geom::X] / spacing_ylines) * spacing_ylines + ow[Geom::X];
- gint const ylinestart = (gint) Inkscape::round((ystart_x_sc - ow[Geom::X]) / spacing_ylines);
+ gint const ylinestart = round((ystart_x_sc - ow[Geom::X]) / spacing_ylines);
gint ylinenum = ylinestart;
for (x = ystart_x_sc; x < buf->rect.x1; x += spacing_ylines, ylinenum++) {
- gint const x0 = (gint) Inkscape::round(x);
+ gint const x0 = round(x);
if (!scaled && (ylinenum % empspacing) != 0) {
sp_grid_vline (buf, x0, buf->rect.y0, buf->rect.y1 - 1, color);
@@ -597,13 +598,13 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
// z-axis always goes from bottomleft to topright. (0,1) - (1,0)
gdouble const zintercept_y_bc = (buf_tl_gc[Geom::X] * -tan_angle[Z]) - buf_tl_gc[Geom::Y] ;
gdouble const zstart_y_sc = ( zintercept_y_bc - floor(zintercept_y_bc/lyw)*lyw ) + buf->rect.y0;
- gint const zlinestart = (gint) Inkscape::round( (zstart_y_sc + buf->rect.x0*tan_angle[Z] - ow[Geom::Y]) / lyw );
+ gint const zlinestart = round( (zstart_y_sc + buf->rect.x0*tan_angle[Z] - ow[Geom::Y]) / lyw );
gint zlinenum = zlinestart;
// lines starting from left side
for (y = zstart_y_sc; y < buf->rect.y1; y += lyw, zlinenum++) {
gint const x0 = buf->rect.x0;
- gint const y0 = (gint) Inkscape::round(y);
- gint const x1 = x0 + (gint) Inkscape::round( (y - buf->rect.y0 ) / tan_angle[Z] );
+ gint const y0 = round(y);
+ gint const x1 = x0 + round( (y - buf->rect.y0 ) / tan_angle[Z] );
gint const y1 = buf->rect.y0;
if (!scaled && (zlinenum % empspacing) != 0) {
@@ -617,8 +618,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
for (x = zstart_x_sc; x < buf->rect.x1; x += lxw_z, zlinenum++) {
gint const y0 = buf->rect.y1;
gint const y1 = buf->rect.y0;
- gint const x0 = (gint) Inkscape::round(x);
- gint const x1 = x0 + (gint) Inkscape::round( (buf->rect.y1 - buf->rect.y0) / tan_angle[Z] );
+ gint const x0 = round(x);
+ gint const x1 = x0 + round( (buf->rect.y1 - buf->rect.y0) / tan_angle[Z] );
if (!scaled && (zlinenum % empspacing) != 0) {
sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color);
diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp
index e1673c8ef..aa38a14c9 100644
--- a/src/display/canvas-grid.cpp
+++ b/src/display/canvas-grid.cpp
@@ -920,9 +920,9 @@ void
CanvasXYGrid::Render (SPCanvasBuf *buf)
{
gdouble const sxg = floor ((buf->rect.x0 - ow[Geom::X]) / sw[Geom::X]) * sw[Geom::X] + ow[Geom::X];
- gint const xlinestart = (gint) Inkscape::round((sxg - ow[Geom::X]) / sw[Geom::X]);
+ gint const xlinestart = round((sxg - ow[Geom::X]) / sw[Geom::X]);
gdouble const syg = floor ((buf->rect.y0 - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y];
- gint const ylinestart = (gint) Inkscape::round((syg - ow[Geom::Y]) / sw[Geom::Y]);
+ gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]);
//set correct coloring, depending preference (when zoomed out, always major coloring or minor coloring)
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -943,7 +943,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf)
gint ylinenum;
gdouble y;
for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[Geom::Y], ylinenum++) {
- gint const y0 = (gint) Inkscape::round(y);
+ gint const y0 = round(y);
if (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) {
grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, color);
} else {
@@ -954,7 +954,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf)
gint xlinenum;
gdouble x;
for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[Geom::X], xlinenum++) {
- gint const ix = (gint) Inkscape::round(x);
+ gint const ix = round(x);
if (!scaled[Geom::X] && (xlinenum % empspacing) != 0) {
grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, color);
} else {
@@ -965,12 +965,12 @@ CanvasXYGrid::Render (SPCanvasBuf *buf)
gint ylinenum;
gdouble y;
for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[Geom::Y], ylinenum++) {
- gint const iy = (gint) Inkscape::round(y);
+ gint const iy = round(y);
gint xlinenum;
gdouble x;
for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[Geom::X], xlinenum++) {
- gint const ix = (gint) Inkscape::round(x);
+ gint const ix = round(x);
if ( (!scaled[Geom::X] && (xlinenum % empspacing) != 0)
|| (!scaled[Geom::Y] && (ylinenum % empspacing) != 0)
|| ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) )
diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp
index c761fa74e..c1c3e7740 100644
--- a/src/display/guideline.cpp
+++ b/src/display/guideline.cpp
@@ -112,8 +112,8 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf)
cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE);
cairo_set_font_size(buf->ct, 10);
- int px = (int) Inkscape::round(gl->point_on_line[Geom::X]);
- int py = (int) Inkscape::round(gl->point_on_line[Geom::Y]);
+ int px = round(gl->point_on_line[Geom::X]);
+ int py = round(gl->point_on_line[Geom::Y]);
if (gl->label) {
cairo_save(buf->ct);
@@ -126,12 +126,12 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf)
}
if (gl->is_vertical()) {
- int position = (int) Inkscape::round(gl->point_on_line[Geom::X]);
+ int position = round(gl->point_on_line[Geom::X]);
cairo_move_to(buf->ct, position + 0.5, buf->rect.y0 + 0.5);
cairo_line_to(buf->ct, position + 0.5, buf->rect.y1 - 0.5);
cairo_stroke(buf->ct);
} else if (gl->is_horizontal()) {
- int position = (int) Inkscape::round(gl->point_on_line[Geom::Y]);
+ int position = round(gl->point_on_line[Geom::Y]);
cairo_move_to(buf->ct, buf->rect.x0 + 0.5, position + 0.5);
cairo_line_to(buf->ct, buf->rect.x1 - 0.5, position + 0.5);
cairo_stroke(buf->ct);
@@ -193,9 +193,9 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine,
sp_canvas_item_request_update(SP_CANVAS_ITEM (gl->origin));
if (gl->is_horizontal()) {
- sp_canvas_update_bbox (item, -1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] - 16), 1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] + 1));
+ sp_canvas_update_bbox (item, -1000000, round(gl->point_on_line[Geom::Y] - 16), 1000000, round(gl->point_on_line[Geom::Y] + 1));
} else if (gl->is_vertical()) {
- sp_canvas_update_bbox (item, (int) Inkscape::round(gl->point_on_line[Geom::X]), -1000000, (int) Inkscape::round(gl->point_on_line[Geom::X] + 16), 1000000);
+ sp_canvas_update_bbox (item, round(gl->point_on_line[Geom::X]), -1000000, round(gl->point_on_line[Geom::X] + 16), 1000000);
} else {
//TODO: labels in angled guidelines are not showing up for some reason.
sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000);
diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp
index 089d6de40..d09f66a2f 100644
--- a/src/display/nr-arena-glyphs.cpp
+++ b/src/display/nr-arena-glyphs.cpp
@@ -135,10 +135,10 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s
}
if (b) {
- item->bbox.x0 = static_cast<NR::ICoord>(floor(b->left()));
- item->bbox.y0 = static_cast<NR::ICoord>(floor(b->top()));
- item->bbox.x1 = static_cast<NR::ICoord>(ceil (b->right()));
- item->bbox.y1 = static_cast<NR::ICoord>(ceil (b->bottom()));
+ item->bbox.x0 = floor(b->left());
+ item->bbox.y0 = floor(b->top());
+ item->bbox.x1 = ceil (b->right());
+ item->bbox.y1 = ceil (b->bottom());
} else {
item->bbox.x0 = 0;
item->bbox.y0 = 0;
@@ -282,7 +282,8 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s
}
-static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/)
+static unsigned int
+nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/)
{
NRArenaItem *child = 0;
@@ -352,20 +353,34 @@ static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item,
return item->state;
}
-static unsigned int nr_arena_glyphs_group_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/)
+static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/)
{
- //NRArenaGroup *group = NR_ARENA_GROUP(item);
+ NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item);
- guint ret = item->state;
+ cairo_save(ct);
+ // handle clip-rule
+ if (ggroup->style) {
+ if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
+ cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD);
+ } else {
+ cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING);
+ }
+ }
+ ink_cairo_transform(ct, ggroup->ctm);
+
+ for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) {
+ NRArenaGlyphs *g = NR_ARENA_GLYPHS(child);
+ Geom::PathVector const &pathv = *g->font->PathVector(g->glyph);
- // Render children fill mask
- /*
- for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
- ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb);
- if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret;
- }*/
+ cairo_save(ct);
+ ink_cairo_transform(ct, g->g_transform);
+ feed_pathvector_to_cairo(ct, pathv);
+ cairo_restore(ct);
+ }
+ cairo_fill(ct);
+ cairo_restore(ct);
- return ret;
+ return item->state;
}
static NRArenaItem *
diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp
index 97f92d02d..1d552fbc2 100644
--- a/src/display/nr-arena-group.cpp
+++ b/src/display/nr-arena-group.cpp
@@ -12,9 +12,12 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include "display/canvas-bpath.h"
+#include "display/nr-arena.h"
#include "display/nr-arena-group.h"
#include "display/nr-filter.h"
#include "display/nr-filter-types.h"
+#include "display/rendermode.h"
#include "style.h"
#include "sp-filter.h"
#include "sp-filter-reference.h"
@@ -163,10 +166,9 @@ static unsigned int
nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset)
{
unsigned int newstate;
-
NRArenaGroup *group = NR_ARENA_GROUP (item);
-
unsigned int beststate = NR_ARENA_ITEM_STATE_ALL;
+ bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
NRGC cgc(gc);
@@ -176,10 +178,10 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int
}
if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
- nr_rect_l_set_empty (&item->bbox);
+ item->bbox = NR_RECT_L_EMPTY;
for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
if (child->visible)
- nr_rect_l_union (&item->bbox, &item->bbox, &child->drawbox);
+ nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox);
}
}
@@ -234,10 +236,8 @@ static unsigned int
nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
{
NRArenaGroup *group = NR_ARENA_GROUP (item);
-
unsigned int ret = item->state;
- /* Just compose children into parent buffer */
for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
ret = nr_arena_item_invoke_clip (ct, child, area);
if (ret & NR_ARENA_ITEM_STATE_INVALID) break;
diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp
index 36d733eb8..a943a6214 100644
--- a/src/display/nr-arena-image.cpp
+++ b/src/display/nr-arena-image.cpp
@@ -301,7 +301,7 @@ nr_arena_image_rect (NRArenaImage *image)
Geom::Point p(image->ox, image->oy);
Geom::Point wh(vw, vh);
Geom::Rect view(p, p+wh);
- Geom::OptRect res = Geom::intersect(r, view);
+ Geom::OptRect res = r & view;
r = res ? *res : r;
}
diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp
index 526882921..9ca5a7463 100644
--- a/src/display/nr-arena-item.cpp
+++ b/src/display/nr-arena-item.cpp
@@ -21,6 +21,7 @@
#include "display/cairo-utils.h"
#include "display/cairo-templates.h"
+#include "display/canvas-arena.h"
#include "nr-arena.h"
#include "nr-arena-item.h"
#include "gc-core.h"
@@ -214,6 +215,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
{
NRGC childgc (gc);
bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL);
+ bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
@@ -242,7 +244,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
return item->state;
/* Test whether to return immediately */
if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) {
- if (!nr_rect_l_test_intersect_ptr(area, &item->drawbox))
+ if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox))
return item->state;
}
@@ -275,8 +277,6 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
} else {
memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox));
}
- // fixme: to fix the display glitches, in outline mode bbox must be a combination of
- // full item bbox and its clip and mask (after we have the API to get these)
/* Clipping */
if (item->clip) {
@@ -288,8 +288,12 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
item->state |= NR_ARENA_ITEM_STATE_INVALID;
return item->state;
}
- // for clipping, we need geometric bbox
- nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox);
+ if (outline) {
+ nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox);
+ } else {
+ // for clipping, we need geometric bbox
+ nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox);
+ }
}
/* Masking */
if (item->mask) {
@@ -298,8 +302,12 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
item->state |= NR_ARENA_ITEM_STATE_INVALID;
return item->state;
}
- // for masking, we need full drawbox of mask
- nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox);
+ if (outline) {
+ nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox);
+ } else {
+ // for masking, we need full drawbox of mask
+ nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox);
+ }
}
// now that we know drawbox, dirty the corresponding rect on canvas:
@@ -349,18 +357,14 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
if (!item->visible)
return item->state | NR_ARENA_ITEM_STATE_RENDER;
- // carea is the bounding box for intermediate rendering.
- // NOTE: carea might be larger than area, because of filter effects.
- NRRectL carea;
- nr_rect_l_intersect (&carea, area, &item->drawbox);
- if (nr_rect_l_test_empty(carea))
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
- if (item->filter && filter) {
- item->filter->area_enlarge (carea, item);
- nr_rect_l_intersect (&carea, &carea, &item->drawbox);
- }
-
if (outline) {
+ // intersect with bbox rather than drawbox, as we want to render things outside
+ // of the clipping path as well
+ NRRectL carea;
+ nr_rect_l_intersect (&carea, area, &item->bbox);
+ if (nr_rect_l_test_empty(carea))
+ return item->state | NR_ARENA_ITEM_STATE_RENDER;
+
// No caching in outline mode for now; investigate if it really gives any advantage with cairo.
// Also no attempts to clip anything; just render everything: item, clip, mask
// First, render the object itself
@@ -388,121 +392,143 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area
return item->state | NR_ARENA_ITEM_STATE_RENDER;
}
+
+ // carea is the bounding box for intermediate rendering.
+ // NOTE: carea might be larger than area, because of filter effects.
+ NRRectL carea;
+ nr_rect_l_intersect (&carea, area, &item->drawbox);
+ if (nr_rect_l_test_empty(carea))
+ return item->state | NR_ARENA_ITEM_STATE_RENDER;
+ if (item->filter && filter) {
+ item->filter->area_enlarge (carea, item);
+ nr_rect_l_intersect (&carea, &carea, &item->drawbox);
+ }
using namespace Inkscape;
- // clipping and masks
- unsigned int state;
-
- cairo_t *this_ct = ct;
- NRRectL *this_area = const_cast<NRRectL*>(area);
+ unsigned state;
+ unsigned retstate;
+ // determine whether this shape needs intermediate rendering.
bool needs_intermediate_rendering = false;
bool &nir = needs_intermediate_rendering;
bool needs_opacity = (item->opacity != 255 && !item->render_opacity);
// this item needs an intermediate rendering if:
- nir |= (item->mask != NULL); // 1. it has a mask
- nir |= (item->filter != NULL && filter); // 2. it has a filter
- nir |= needs_opacity; // 3. it is non-opaque
+ nir |= (item->clip != NULL); // 1. it has a clipping path
+ nir |= (item->mask != NULL); // 2. it has a mask
+ nir |= (item->filter != NULL && filter); // 3. it has a filter
+ nir |= needs_opacity; // 4. it is non-opaque
double opacity = static_cast<double>(item->opacity) / 255.0;
- if (needs_intermediate_rendering) {
- cairo_surface_t *intermediate = cairo_surface_create_similar(
- cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA,
- carea.x1 - carea.x0, carea.y1 - carea.y0);
- this_ct = cairo_create(intermediate);
- cairo_translate(this_ct, -carea.x0, -carea.y0);
- this_area = &carea;
- cairo_surface_destroy(intermediate); // the surface will be held in memory by this_ct
- } else {
- cairo_reference(this_ct);
- }
+ /* How the rendering is done.
+ *
+ * Clipping, masking and opacity are done by rendering them to a surface
+ * and then compositing the object's rendering onto it with the IN operator.
+ * The object itself is rendered to a group.
+ *
+ * Opacity is done by rendering the clipping path with an alpha
+ * value corresponding to the opacity. If there is no clipping path,
+ * the entire intermediate surface is painted with alpha corresponding
+ * to the opacity value.
+ */
- // The pipeline needs to be different for filters.
- // First we render the item into an intermediate surface. Then the filter rotates
- // the surface to user coordinates (if necessary) and runs the rendering.
- // Once that's done we retrieve the result, rotating it back to screen coords.
- // Clipping and masking happens after the filter result is ready.
- if (item->filter && filter) {
+ // short-circuit the simple case.
+ if (!needs_intermediate_rendering) {
+ state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags);
+ if (state & NR_ARENA_ITEM_STATE_INVALID) {
+ item->state |= NR_ARENA_ITEM_STATE_INVALID;
+ return item->state;
+ }
+ return item->state | NR_ARENA_ITEM_STATE_RENDER;
}
- Cairo::Context cct(this_ct, true);
- Cairo::Context base_ct(ct);
- Cairo::RefPtr<Cairo::Pattern> mask;
- CairoSave clipsave(ct); // RAII for save / restore
- CairoGroup maskgroup(this_ct); // RAII for push_group / pop_group
- CairoGroup drawgroup(this_ct);
- CairoGroup maskopacitygroup(this_ct);
-
- // always clip the base context, not the one on the intermediate surface
- // this is because filters must be done before clipping
+ cairo_surface_t *intermediate = cairo_surface_create_similar(
+ cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA,
+ carea.x1 - carea.x0, carea.y1 - carea.y0);
+ cairo_t *ict = cairo_create(intermediate);
+ cairo_translate(ict, -carea.x0, -carea.y0);
+
+ // 1. Render clipping path with alpha = opacity.
+ cairo_set_source_rgba(ict, 0,0,0,opacity);
+ // Since clip can be combined with opacity, the result could be incorrect
+ // for overlapping clip children. To fix this we use the SOURCE operator
+ // instead of the default OVER.
+ cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE);
if (item->clip) {
- clipsave.save();
- state = nr_arena_item_invoke_clip(ct, item->clip, const_cast<NRRectL*>(area));
+ state = nr_arena_item_invoke_clip(ict, item->clip, const_cast<NRRectL*>(area));
if (state & NR_ARENA_ITEM_STATE_INVALID) {
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
+ retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID);
+ goto cleanup;
}
- base_ct.clip();
+ } else {
+ // if there is no clipping path, fill the entire surface with alpha = opacity.
+ cairo_paint(ict);
}
+ // reset back to default
+ cairo_set_operator(ict, CAIRO_OPERATOR_OVER);
- // render mask on the intermediate context and store it
+ // 2. Render the mask if present and compose it with the clipping path + opacity.
if (item->mask) {
- maskgroup.push_with_content(CAIRO_CONTENT_COLOR_ALPHA);
- // handle opacity of a masked object by composing it with the mask
- if (needs_opacity) {
- maskopacitygroup.push();
- }
- state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (this_ct, item->mask, this_area, pb, flags);
+ cairo_push_group(ict);
+ state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags);
if (state & NR_ARENA_ITEM_STATE_INVALID) {
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
- }
- if (needs_opacity) {
- maskopacitygroup.pop_to_source();
- cct.paint_with_alpha(opacity);
+ retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID);
+ goto cleanup;
}
- mask = maskgroup.popmm();
- // convert luminance to alpha
- cairo_pattern_t *p = mask->cobj();
- cairo_surface_t *s;
- cairo_pattern_get_surface(p, &s);
- ink_cairo_surface_filter(s, s, MaskLuminanceToAlpha());
+ cairo_surface_t *mask_s = cairo_get_group_target(ict);
+ // Convert mask's luminance to alpha
+ ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha());
+ cairo_pop_group_to_source(ict);
+ cairo_set_operator(ict, CAIRO_OPERATOR_IN);
+ cairo_paint(ict);
+ cairo_set_operator(ict, CAIRO_OPERATOR_OVER);
}
- // render the object (possibly to the intermediate surface)
- state = NR_ARENA_ITEM_VIRTUAL (item, render) (this_ct, item, this_area, pb, flags);
+ // 3. Render object itself.
+ cairo_push_group(ict);
+ state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags);
if (state & NR_ARENA_ITEM_STATE_INVALID) {
- /* Clean up and return error */
- item->state |= NR_ARENA_ITEM_STATE_INVALID;
- return item->state;
+ retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID);
+ goto cleanup;
}
- // apply filter
+ // 4. Apply filter.
if (item->filter && filter) {
- item->filter->render(item, ct, area, this_ct, &carea);
- }
-
- if (needs_intermediate_rendering) {
- cairo_surface_t *intermediate = cairo_get_target(this_ct);
- cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0);
- if (mask) {
- cairo_mask(ct, mask->cobj());
- // opacity of masked objects is handled by premultiplying the mask
+ // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering
+ // Proper fix: call this function with a drawing context class
+ // that contains information about the surface's bounds
+ NRRectL bgarea;
+ if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) {
+ bgarea = carea;
} else {
- // opacity of non-masked objects must be rendered explicitly
- if (needs_opacity) {
- cairo_paint_with_alpha(ct, opacity);
- } else {
- cairo_paint(ct);
- }
+ bgarea = NRRectL(item->arena->canvasarena->cache_area);
}
- cairo_set_source_rgba(ct,0,0,0,0);
+ item->filter->render(item, ct, &bgarea, ict, &carea);
+ // Note that because the object was rendered to a group,
+ // the internals of the filter need to use cairo_get_group_target()
+ // instead of cairo_get_target().
}
- return item->state | NR_ARENA_ITEM_STATE_RENDER;
+ // 5. Render object inside the composited mask + clip
+ cairo_pop_group_to_source(ict);
+ cairo_set_operator(ict, CAIRO_OPERATOR_IN);
+ cairo_paint(ict);
+
+ // 6. Paint the completed rendering onto the base context
+ cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0);
+ cairo_paint(ct);
+ cairo_set_source_rgba(ct, 0,0,0,0);
+ // the call above is to clear a ref on the intermediate surface held by ct
+
+ retstate = item->state | NR_ARENA_ITEM_STATE_RENDER;
+
+ cleanup:
+ cairo_destroy(ict);
+ cairo_surface_destroy(intermediate);
+
+ return retstate;
}
unsigned int
@@ -511,16 +537,6 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
NR_ARENA_ITEM_STATE_INVALID);
- /* we originally short-circuited if the object state included
- * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console);
- * anyone know why we stopped doing so?
- */
- /*nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >=
- (area->x1 - area->x0),
- NR_ARENA_ITEM_STATE_INVALID);
- nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >=
- (area->y1 - area->y0),
- NR_ARENA_ITEM_STATE_INVALID);*/
#ifdef NR_ARENA_ITEM_VERBOSE
printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n",
@@ -528,15 +544,40 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
(&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1);
#endif
+ unsigned retstate = 0;
+
+ // don't bother if the object does not implement clipping (e.g. NRArenaImage)
+ if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip)
+ return retstate;
+
if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) {
- /* Need render that item */
- if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) {
- return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
- clip (ct, item, area);
+ // The item used as the clipping path itself has a clipping path.
+ // Render this item's clipping path onto a temporary surface, then composite it with the item
+ // using the IN operator
+ if (item->clip) {
+ cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA);
+ cairo_save(ct);
+ cairo_set_source_rgba(ct, 0,0,0,1);
+ nr_arena_item_invoke_clip(ct, item->clip, area);
+ cairo_restore(ct);
+ cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA);
+ }
+
+ // rasterize the clipping path
+ retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
+ clip (ct, item, area);
+
+ if (item->clip) {
+ cairo_pop_group_to_source(ct);
+ cairo_set_operator(ct, CAIRO_OPERATOR_IN);
+ cairo_paint(ct);
+ cairo_pop_group_to_source(ct);
+ cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ct);
}
}
- return item->state;
+ return retstate;
}
NRArenaItem *
@@ -597,7 +638,8 @@ nr_arena_item_request_render (NRArenaItem *item)
nr_return_if_fail (item != NULL);
nr_return_if_fail (NR_IS_ARENA_ITEM (item));
- nr_arena_request_render_rect (item->arena, &item->drawbox);
+ bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
+ nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox);
}
/* Public */
diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h
index 0fc4cbe48..d65a75ed8 100644
--- a/src/display/nr-arena-item.h
+++ b/src/display/nr-arena-item.h
@@ -15,6 +15,8 @@
#include <cairo.h>
#include <2geom/affine.h>
+#include <2geom/rect.h>
+#include "libnr/nr-forward.h"
#include "libnr/nr-rect-l.h"
#include "libnr/nr-object.h"
#include "gc-soft-ptr.h"
diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp
index eb7a30e58..6d65611bf 100644
--- a/src/display/nr-arena-shape.cpp
+++ b/src/display/nr-arena-shape.cpp
@@ -21,6 +21,7 @@
#include <2geom/svg-path-parser.h>
#include "display/cairo-utils.h"
#include "display/canvas-arena.h"
+#include "display/canvas-bpath.h"
#include "display/curve.h"
#include "display/nr-arena.h"
#include "display/nr-arena-shape.h"
@@ -223,10 +224,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g
if (shape->curve) {
boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform);
if (boundingbox) {
- item->bbox.x0 = static_cast<NR::ICoord>(floor((*boundingbox)[0][0])); // Floor gives the coordinate in which the point resides
- item->bbox.y0 = static_cast<NR::ICoord>(floor((*boundingbox)[1][0]));
- item->bbox.x1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[0][1])); // Ceil gives the first coordinate beyond the point
- item->bbox.y1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[1][1]));
+ item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides
+ item->bbox.y0 = floor((*boundingbox)[1][0]);
+ item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point
+ item->bbox.y1 = ceil ((*boundingbox)[1][1]);
} else {
item->bbox = NR_RECT_L_EMPTY;
}
@@ -274,10 +275,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g
/// \todo just write item->bbox = boundingbox
if (boundingbox) {
- shape->approx_bbox.x0 = static_cast<NR::ICoord>(floor((*boundingbox)[0][0]));
- shape->approx_bbox.y0 = static_cast<NR::ICoord>(floor((*boundingbox)[1][0]));
- shape->approx_bbox.x1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[0][1]));
- shape->approx_bbox.y1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[1][1]));
+ shape->approx_bbox.x0 = floor(boundingbox->left());
+ shape->approx_bbox.y0 = floor(boundingbox->top());
+ shape->approx_bbox.x1 = ceil (boundingbox->right());
+ shape->approx_bbox.y1 = ceil (boundingbox->bottom());
} else {
shape->approx_bbox = NR_RECT_L_EMPTY;
}
@@ -396,22 +397,26 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock
static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/)
{
- guint result = 0;
-
- // NOTE: for now this is incorrect, because it doesn't honor clip-rule,
- // and will be incorrect for nested clipping paths.
NRArenaShape *shape = NR_ARENA_SHAPE(item);
if (!shape->curve) {
- result = item->state;
- } else {
- cairo_save(ct);
- ink_cairo_transform(ct, shape->ctm);
- feed_pathvector_to_cairo(ct, shape->curve->get_pathvector());
- cairo_restore(ct);
+ return item->state;
+ }
- result = item->state;
+ cairo_save(ct);
+ // handle clip-rule
+ if (shape->style) {
+ if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) {
+ cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD);
+ } else {
+ cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING);
+ }
}
- return result;
+ ink_cairo_transform(ct, shape->ctm);
+ feed_pathvector_to_cairo(ct, shape->curve->get_pathvector());
+ cairo_fill(ct);
+ cairo_restore(ct);
+
+ return item->state;
}
static NRArenaItem *
diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h
index 2ee0d24c8..7b86f7f59 100644
--- a/src/display/nr-arena-shape.h
+++ b/src/display/nr-arena-shape.h
@@ -22,6 +22,7 @@
#include "forward.h"
#include "nr-arena-item.h"
#include "nr-style.h"
+#include "libnr/nr-rect.h"
NRType nr_arena_shape_get_type (void);
diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp
index 43edb6918..ce62a81dc 100644
--- a/src/display/nr-arena.cpp
+++ b/src/display/nr-arena.cpp
@@ -18,6 +18,7 @@
#include "nr-filter-types.h"
#include "preferences.h"
#include "color.h"
+#include "libnr/nr-rect.h"
static void nr_arena_class_init (NRArenaClass *klass);
static void nr_arena_init (NRArena *arena);
diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp
index d4cf47af4..694ccaec5 100644
--- a/src/display/nr-filter-composite.cpp
+++ b/src/display/nr-filter-composite.cpp
@@ -11,7 +11,6 @@
#include <cmath>
-#include "2geom/isnan.h"
#include "display/cairo-templates.h"
#include "display/cairo-utils.h"
#include "display/nr-filter-composite.h"
diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp
index fdaf2c887..15200223b 100644
--- a/src/display/nr-filter-displacement-map.cpp
+++ b/src/display/nr-filter-displacement-map.cpp
@@ -28,128 +28,6 @@ FilterPrimitive * FilterDisplacementMap::create() {
FilterDisplacementMap::~FilterDisplacementMap()
{}
-#if 0
-struct pixel_t {
- unsigned char channels[4];
- inline unsigned char operator[](int c) const { return channels[c]; }
- inline unsigned char& operator[](int c) { return channels[c]; }
- static inline pixel_t blank() {
- pixel_t p;
- for(unsigned int i=0; i<4; i++) {
- p[i] = 0;
- }
- return p;
- }
-};
-
-static inline pixel_t pixelValue(NRPixBlock const* pb, int x, int y) {
- if ( x < pb->area.x0 || x >= pb->area.x1 || y < pb->area.y0 || y >= pb->area.y1 ) return pixel_t::blank(); // This assumes anything outside the defined range is (0,0,0,0)
- pixel_t const* rowData = reinterpret_cast<pixel_t const*>(NR_PIXBLOCK_PX(pb) + (y-pb->area.y0)*pb->rs);
- return rowData[x-pb->area.x0];
-}
-
-template<bool PREMULTIPLIED>
-static pixel_t interpolatePixels(NRPixBlock const* pb, double x, double y) {
- // NOTE: The values of x and y are shifted by -0.5 (the "true" values would be x+0.5 and y+0.5).
- // This is done because otherwise the pixel values first have to be shifted by +0.5 and then by -0.5 again...
- unsigned int const sfl = 8u;
- unsigned int const sf = 1u<<sfl;
- unsigned int const sf2h = 1u<<(2u*sfl-1);
- int xi = (int)floor(x), yi = (int)floor(y);
- unsigned int xf = static_cast<unsigned int>(round(sf * (x - xi))),
- yf = static_cast<unsigned int>(round(sf * (y - yi)));
- pixel_t p00 = pixelValue(pb, xi+0, yi+0);
- pixel_t p01 = pixelValue(pb, xi+1, yi+0);
- pixel_t p10 = pixelValue(pb, xi+0, yi+1);
- pixel_t p11 = pixelValue(pb, xi+1, yi+1);
-
- /* It's a good idea to interpolate premultiplied colors:
- *
- * Consider two pixels, one being rgba(255,0,0,0), which is fully transparent,
- * and the other being rgba(0,0,255,255), or blue (fully opaque).
- * If these two colors are interpolated the expected result would be bluish pixels
- * containing no red.
- *
- * However, if our final alpha value is zero, then the RGB values aren't really determinate.
- * We might as well avoid premultiplication in this case, which still gives us a fully
- * transparent result, but with interpolated RGB parts. */
-
- pixel_t r;
- if (PREMULTIPLIED) {
- /* Premultiplied, so do simple interpolation. */
- for (unsigned i = 0; i != 4; ++i) {
- // y0,y1 have range [0,a*sf]
- unsigned const y0 = sf*p00[i] + xf*((unsigned int)p01[i]-(unsigned int)p00[i]);
- unsigned const y1 = sf*p10[i] + xf*((unsigned int)p11[i]-(unsigned int)p10[i]);
-
- unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,a*sf*sf]
- r[i] = (ri + sf2h)>>(2*sfl); // range [0,a]
- }
- } else {
- /* First calculate interpolated alpha value. */
- unsigned const y0 = sf*p00[3] + xf*((unsigned int)p01[3]-(unsigned int)p00[3]); // range [0,a*sf]
- unsigned const y1 = sf*p10[3] + xf*((unsigned int)p11[3]-(unsigned int)p10[3]);
- unsigned const ra = sf*y0 + yf*(y1-y0); // range [0,a*sf*sf]
-
- if (ra==0) {
- /* Fully transparent, so do simple interpolation. */
- for (unsigned i = 0; i != 3; ++i) {
- // y0,y1 have range [0,255*sf]
- unsigned const y0 = sf*p00[i] + xf*((unsigned int)p01[i]-(unsigned int)p00[i]);
- unsigned const y1 = sf*p10[i] + xf*((unsigned int)p11[i]-(unsigned int)p10[i]);
-
- unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,255*sf*sf]
- r[i] = (ri + sf2h)>>(2*sfl); // range [0,255]
- }
- r[3] = 0;
- } else {
- /* Do premultiplication ourselves. */
- for (unsigned i = 0; i != 3; ++i) {
- // Premultiplied versions. Range [0,255*a].
- unsigned const c00 = p00[i]*p00[3];
- unsigned const c01 = p01[i]*p01[3];
- unsigned const c10 = p10[i]*p10[3];
- unsigned const c11 = p11[i]*p11[3];
-
- // Interpolation.
- unsigned const y0 = sf*c00 + xf*(c01-c00); // range [0,255*a*sf]
- unsigned const y1 = sf*c10 + xf*(c11-c10); // range [0,255*a*sf]
- unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,255*a*sf*sf]
- r[i] = (ri + ra/2) / ra; // range [0,255]
- }
- r[3] = (ra + sf2h)>>(2*sfl); // range [0,a]
- }
- }
-
- return r;
-}
-
-template<bool MAP_PREMULTIPLIED, bool DATA_PREMULTIPLIED>
-static void performDisplacement(NRPixBlock const* texture, NRPixBlock const* map, int Xchannel, int Ychannel, NRPixBlock* out, double scalex, double scaley) {
- bool Xneedsdemul = MAP_PREMULTIPLIED && Xchannel<3;
- bool Yneedsdemul = MAP_PREMULTIPLIED && Ychannel<3;
- if (!Xneedsdemul) scalex /= 255.0;
- if (!Yneedsdemul) scaley /= 255.0;
-
- for (int yout=out->area.y0; yout < out->area.y1; yout++){
- pixel_t const* mapRowData = reinterpret_cast<pixel_t const*>(NR_PIXBLOCK_PX(map) + (yout-map->area.y0)*map->rs);
- pixel_t* outRowData = reinterpret_cast<pixel_t*>(NR_PIXBLOCK_PX(out) + (yout-out->area.y0)*out->rs);
- for (int xout=out->area.x0; xout < out->area.x1; xout++){
- pixel_t const mapValue = mapRowData[xout-map->area.x0];
-
- double xtex = xout + (Xneedsdemul ? // Although the value of the pixel corresponds to the MIDDLE of the pixel, no +0.5 is needed because we're interpolating pixels anyway (so to get the actual pixel locations 0.5 would have to be subtracted again).
- (mapValue[3]==0?0:(scalex * (mapValue[Xchannel] - mapValue[3]*0.5) / mapValue[3])) :
- (scalex * (mapValue[Xchannel] - 127.5)));
- double ytex = yout + (Yneedsdemul ?
- (mapValue[3]==0?0:(scaley * (mapValue[Ychannel] - mapValue[3]*0.5) / mapValue[3])) :
- (scaley * (mapValue[Ychannel] - 127.5)));
-
- outRowData[xout-out->area.x0] = interpolatePixels<DATA_PREMULTIPLIED>(texture, xtex, ytex);
- }
- }
-}
-#endif
-
struct Displace {
Displace(cairo_surface_t *texture, cairo_surface_t *map,
unsigned xch, unsigned ych, double scalex, double scaley)
@@ -206,73 +84,6 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot)
cairo_surface_destroy(out);
}
-/*
-int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) {
- NRPixBlock *texture = slot.get(_input);
- NRPixBlock *map = slot.get(_input2);
-
- // Bail out if either one of source images is missing
- if (!map || !texture) {
- g_warning("Missing source image for feDisplacementMap (map=%d texture=%d)", _input, _input2);
- return 1;
- }
-
- NR::IRect area = units.get_pixblock_filterarea_paraller();
- int x0 = std::max(map->area.x0,area.min()[NR::X]);
- int y0 = std::max(map->area.y0,area.min()[NR::Y]);
- int x1 = std::min(map->area.x1,area.max()[NR::X]);
- int y1 = std::min(map->area.y1,area.max()[NR::Y]);
-
- //TODO: check whether we really need this check:
- if (x1 <= x0 || y1 <= y0) return 0; //nothing to do!
-
- if (texture->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && texture->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
- g_warning("Source images without an alpha channel are not supported by feDisplacementMap at the moment.");
- return 1;
- }
-
- NRPixBlock *out = new NRPixBlock;
- nr_pixblock_setup_fast(out, texture->mode, x0, y0, x1, y1, true);
-
- // convert to a suitable format
- bool free_map_on_exit = false;
- if (map->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && map->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
- NRPixBlock *original_map = map;
- map = new NRPixBlock;
- nr_pixblock_setup_fast(map, NR_PIXBLOCK_MODE_R8G8B8A8N,
- original_map->area.x0, original_map->area.y0,
- original_map->area.x1, original_map->area.y1,
- false);
- nr_blit_pixblock_pixblock(map, original_map);
- free_map_on_exit = true;
- }
- bool map_premultiplied = (map->mode == NR_PIXBLOCK_MODE_R8G8B8A8P);
- bool data_premultiplied = (out->mode == NR_PIXBLOCK_MODE_R8G8B8A8P);
-
- Geom::Affine trans = units.get_matrix_primitiveunits2pb();
- double scalex = scale * trans.expansionX();
- double scaley = scale * trans.expansionY();
-
- if (map_premultiplied && data_premultiplied) {
- performDisplacement<true,true>(texture, map, Xchannel, Ychannel, out, scalex, scaley);
- } else if (map_premultiplied && !data_premultiplied) {
- performDisplacement<true,false>(texture, map, Xchannel, Ychannel, out, scalex, scaley);
- } else if (data_premultiplied) {
- performDisplacement<false,true>(texture, map, Xchannel, Ychannel, out, scalex, scaley);
- } else {
- performDisplacement<false,false>(texture, map, Xchannel, Ychannel, out, scalex, scaley);
- }
-
- if (free_map_on_exit) {
- nr_pixblock_release(map);
- delete map;
- }
-
- out->empty = FALSE;
- slot.set(_output, out);
- return 0;
-}*/
-
void FilterDisplacementMap::set_input(int slot) {
_input = slot;
}
diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp
index fca066ad4..3a6b425e1 100644
--- a/src/display/nr-filter-gaussian.cpp
+++ b/src/display/nr-filter-gaussian.cpp
@@ -23,8 +23,6 @@
#include <omp.h>
#endif //HAVE_OPENMP
-#include "2geom/isnan.h"
-
#include "display/cairo-utils.h"
#include "display/nr-filter-primitive.h"
#include "display/nr-filter-gaussian.h"
diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp
index ce07ff086..3464fda66 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -156,7 +156,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background()
{
Geom::Affine trans = _units.get_matrix_display2pb();
- cairo_surface_t *bg = cairo_get_target(_background_ct);
+ cairo_surface_t *bg = cairo_get_group_target(_background_ct);
cairo_surface_t *tbg = cairo_surface_create_similar(
bg, cairo_surface_get_content(bg),
_slot_w, _slot_h);
diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp
index f3b03c024..60d5ce872 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -299,7 +299,6 @@ FilterTurbulence::FilterTurbulence()
, numOctaves(1)
, seed(0)
, updated(false)
- , updated_area(NR::IPoint(), NR::IPoint())
, fTileWidth(10) //guessed
, fTileHeight(10) //guessed
, fTileX(1) //guessed
diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h
index 50161b6be..8d3639543 100644
--- a/src/display/nr-filter-turbulence.h
+++ b/src/display/nr-filter-turbulence.h
@@ -64,7 +64,6 @@ private:
bool stitchTiles;
FilterTurbulenceType type;
bool updated;
- NR::IRect updated_area;
unsigned char *pix_data;
double fTileWidth;
diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp
index b1c475c41..a8686545a 100644
--- a/src/display/nr-filter-units.cpp
+++ b/src/display/nr-filter-units.cpp
@@ -158,22 +158,13 @@ Geom::Affine FilterUnits::get_matrix_user2primitiveunits() const {
return get_matrix_user2units(primitiveUnits);
}
-NR::IRect FilterUnits::get_pixblock_filterarea_paraller() const {
+Geom::IntRect FilterUnits::get_pixblock_filterarea_paraller() const {
g_assert(filter_area);
- int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
Geom::Affine u2pb = get_matrix_user2pb();
-
- for (int i = 0 ; i < 4 ; i++) {
- Geom::Point p = filter_area->corner(i);
- p *= u2pb;
- if (p[X] < min_x) min_x = (int)std::floor(p[X]);
- if (p[X] > max_x) max_x = (int)std::ceil(p[X]);
- if (p[Y] < min_y) min_y = (int)std::floor(p[Y]);
- if (p[Y] > max_y) max_y = (int)std::ceil(p[Y]);
- }
- NR::IRect ret(NR::IPoint(min_x, min_y), NR::IPoint(max_x, max_y));
- return ret;
+ Geom::Rect r = *filter_area * u2pb;
+ Geom::IntRect ir = r.roundOutwards();
+ return ir;
}
FilterUnits& FilterUnits::operator=(FilterUnits const &other) {
diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h
index 2fc3e5533..1cb4fdbce 100644
--- a/src/display/nr-filter-units.h
+++ b/src/display/nr-filter-units.h
@@ -133,7 +133,7 @@ public:
* NOTE: use only in filters, that define TRAIT_PARALLER in
* get_input_traits. The filter effects area may not be representable
* by simple rectangle otherwise. */
- NR::IRect get_pixblock_filterarea_paraller() const;
+ Geom::IntRect get_pixblock_filterarea_paraller() const;
FilterUnits& operator=(FilterUnits const &other);
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index 6e0aa1a42..963d98654 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -160,7 +160,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea
}
}
- FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_target(graphic), area, units);
+ FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_group_target(graphic), area, units);
slot.set_quality(filterquality);
slot.set_blurquality(blurquality);
@@ -236,10 +236,10 @@ void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) {
Geom::Rect enlarged = filter_effect_area(tmp_bbox);
enlarged = enlarged * item->ctm;
- item_bbox.x0 = (NR::ICoord) floor(enlarged.min()[X]);
- item_bbox.y0 = (NR::ICoord) floor(enlarged.min()[Y]);
- item_bbox.x1 = (NR::ICoord) ceil(enlarged.max()[X]);
- item_bbox.y1 = (NR::ICoord) ceil(enlarged.max()[Y]);
+ item_bbox.x0 = floor(enlarged.min()[X]);
+ item_bbox.y0 = floor(enlarged.min()[Y]);
+ item_bbox.x1 = ceil(enlarged.max()[X]);
+ item_bbox.y1 = ceil(enlarged.max()[Y]);
}
Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox)
diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h
index 9dbec547e..4c731e56b 100644
--- a/src/display/sp-canvas-item.h
+++ b/src/display/sp-canvas-item.h
@@ -24,8 +24,7 @@
#include <glib-object.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
-
-#include "2geom/rect.h"
+#include <2geom/rect.h>
G_BEGIN_DECLS
@@ -65,6 +64,7 @@ struct _SPCanvasItemClass : public GtkObjectClass {
double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
int (* event) (SPCanvasItem *item, GdkEvent *event);
+ void (* visible_area_changed) (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area);
};
SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GType type, const gchar *first_arg_name, ...);
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 37998437d..d7f34969f 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -689,6 +689,7 @@ static void sp_canvas_group_destroy (GtkObject *object);
static void sp_canvas_group_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
static double sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item);
static void sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf);
+static void sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area);
static SPCanvasItemClass *group_parent_class;
@@ -732,6 +733,7 @@ sp_canvas_group_class_init (SPCanvasGroupClass *klass)
item_class->update = sp_canvas_group_update;
item_class->render = sp_canvas_group_render;
item_class->point = sp_canvas_group_point;
+ item_class->visible_area_changed = sp_canvas_group_visible_area_changed;
}
/**
@@ -875,6 +877,20 @@ sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf)
}
}
+static void
+sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area)
+{
+ SPCanvasGroup *group = SP_CANVAS_GROUP (item);
+
+ for (GList *list = group->items; list; list = list->next) {
+ SPCanvasItem *child = (SPCanvasItem *)list->data;
+ if (child->flags & SP_CANVAS_ITEM_VISIBLE) {
+ if (SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed)
+ SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed (child, old_area, new_area);
+ }
+ }
+}
+
/**
* Adds an item to a canvas group.
*/
@@ -1045,7 +1061,7 @@ sp_canvas_init (SPCanvas *canvas)
#if ENABLE_LCMS
canvas->enable_cms_display_adj = false;
- canvas->cms_key = new Glib::ustring("");
+ new (&canvas->cms_key) Glib::ustring("");
#endif // ENABLE_LCMS
canvas->is_scrolling = false;
@@ -1105,6 +1121,8 @@ sp_canvas_destroy (GtkObject *object)
shutdown_transients (canvas);
+ canvas->cms_key.~ustring();
+
if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy)
(* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object);
}
@@ -1134,8 +1152,6 @@ sp_canvas_new_aa (void)
static void
sp_canvas_realize (GtkWidget *widget)
{
- SPCanvas *canvas = SP_CANVAS (widget);
-
GdkWindowAttr attributes;
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = widget->allocation.x;
@@ -1171,8 +1187,6 @@ sp_canvas_realize (GtkWidget *widget)
widget->style = gtk_style_attach (widget->style, widget->window);
gtk_widget_set_realized (widget, TRUE);
-
- canvas->pixmap_gc = gdk_gc_new (SP_CANVAS_WINDOW (canvas));
}
/**
@@ -1189,9 +1203,6 @@ sp_canvas_unrealize (GtkWidget *widget)
shutdown_transients (canvas);
- gdk_gc_destroy (canvas->pixmap_gc);
- canvas->pixmap_gc = NULL;
-
if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize)
(* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget);
}
@@ -1216,8 +1227,16 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
SPCanvas *canvas = SP_CANVAS (widget);
+ Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0,
+ widget->allocation.width, widget->allocation.height);
+ Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0,
+ allocation->width, allocation->height);
+
/* Schedule redraw of new region */
sp_canvas_resize_tiles(canvas,canvas->x0,canvas->y0,canvas->x0+allocation->width,canvas->y0+allocation->height);
+ if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed)
+ SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area);
+
if (allocation->width > widget->allocation.width) {
sp_canvas_request_redraw (canvas,
canvas->x0 + widget->allocation.width,
@@ -1602,7 +1621,7 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
if (event->window != SP_CANVAS_WINDOW (canvas))
return FALSE;
- if (canvas->pixmap_gc == NULL) // canvas being deleted
+ if (canvas->root == NULL) // canvas being deleted
return FALSE;
canvas->state = event->state;
@@ -1670,7 +1689,7 @@ static void sp_canvas_paint_single_buffer(SPCanvas *canvas, int x0, int y0, int
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display");
if ( fromDisplay ) {
- transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key ? *(canvas->cms_key) : "" );
+ transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key );
} else {
transf = Inkscape::CMSSystem::getDisplayTransform();
}
@@ -1857,16 +1876,6 @@ sp_canvas_paint_rect (SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1)
rect.x1 = MIN (rect.x1, canvas->x0/*draw_x1*/ + GTK_WIDGET (canvas)->allocation.width);
rect.y1 = MIN (rect.y1, canvas->y0/*draw_y1*/ + GTK_WIDGET (canvas)->allocation.height);
-#ifdef DEBUG_REDRAW
- // paint the area to redraw yellow
- gdk_rgb_gc_set_foreground (canvas->pixmap_gc, 0xFFFF00);
- gdk_draw_rectangle (SP_CANVAS_WINDOW (canvas),
- canvas->pixmap_gc,
- TRUE,
- rect.x0 - canvas->x0, rect.y0 - canvas->y0,
- rect.x1 - rect.x0, rect.y1 - rect.y0);
-#endif
-
PaintRectSetup setup;
setup.canvas = canvas;
@@ -2064,7 +2073,7 @@ paint (SPCanvas *canvas)
static int
do_update (SPCanvas *canvas)
{
- if (!canvas->root || !canvas->pixmap_gc) // canvas may have already be destroyed by closing desktop during interrupted display!
+ if (!canvas->root) // canvas may have already be destroyed by closing desktop during interrupted display!
return TRUE;
if (canvas->drawing_disabled)
@@ -2150,12 +2159,17 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear,
int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the
int dy = iy - canvas->y0; // canvas w.r.t its previous position
+ Geom::IntRect old_area = canvas->getViewboxIntegers();
+ Geom::IntRect new_area = old_area + Geom::IntPoint(dx, dy);
+
canvas->dx0 = cx; // here the 'd' stands for double, not delta!
canvas->dy0 = cy;
canvas->x0 = ix;
canvas->y0 = iy;
sp_canvas_resize_tiles (canvas, canvas->x0, canvas->y0, canvas->x0+canvas->widget.allocation.width, canvas->y0+canvas->widget.allocation.height);
+ if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed)
+ SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area);
if (!clear) {
// scrolling without zoom; redraw only the newly exposed areas
@@ -2168,7 +2182,6 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear,
} else {
// scrolling as part of zoom; do nothing here - the next do_update will perform full redraw
}
-
}
/**
@@ -2301,13 +2314,15 @@ Geom::Rect SPCanvas::getViewbox() const
}
/**
- * Return canvas window coordinates as IRect (a rectangle defined by integers).
+ * Return canvas window coordinates as integer rectangle.
*/
-NR::IRect SPCanvas::getViewboxIntegers() const
+Geom::IntRect SPCanvas::getViewboxIntegers() const
{
GtkWidget const *w = GTK_WIDGET(this);
- return NR::IRect(NR::IPoint(x0, y0),
- NR::IPoint(x0 + w->allocation.width, y0 + w->allocation.height));
+ Geom::IntRect ret;
+ ret.setMin(Geom::IntPoint(x0, y0));
+ ret.setMax(Geom::IntPoint(x0 + w->allocation.width, y0 + w->allocation.height));
+ return ret;
}
inline int sp_canvas_tile_floor(int x)
diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h
index 7a6b3295e..f284afdf2 100644
--- a/src/display/sp-canvas.h
+++ b/src/display/sp-canvas.h
@@ -112,9 +112,6 @@ struct SPCanvas {
int close_enough;
- /* GC for temporary draw pixmap */
- GdkGC *pixmap_gc;
-
unsigned int need_update : 1;
unsigned int need_redraw : 1;
unsigned int need_repick : 1;
@@ -143,13 +140,13 @@ struct SPCanvas {
#if ENABLE_LCMS
bool enable_cms_display_adj;
- Glib::ustring* cms_key;
+ Glib::ustring cms_key;
#endif // ENABLE_LCMS
bool is_scrolling;
Geom::Rect getViewbox() const;
- NR::IRect getViewboxIntegers() const;
+ Geom::IntRect getViewboxIntegers() const;
};
GtkWidget *sp_canvas_new_aa();