summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-07-12 01:18:44 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2011-07-12 01:18:44 +0000
commitd776f783e99f70029d1ec8d6c938468d7e220de0 (patch)
treebfe0ee9098f07986a22fa01d09b0226bd79a7a70 /src
parentSimplify rendering of masked / clipped / translucent items. (diff)
downloadinkscape-d776f783e99f70029d1ec8d6c938468d7e220de0.tar.gz
inkscape-d776f783e99f70029d1ec8d6c938468d7e220de0.zip
Compute different bounding boxes in outline mode to fix partial
rendering of objects where the clipping path is much larger than the base object or vice versa. Fixes LP #177687. Fixed bugs: - https://launchpad.net/bugs/177687 (bzr r10347.1.11)
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-arena-group.cpp7
-rw-r--r--src/display/nr-arena-item.cpp115
2 files changed, 65 insertions, 57 deletions
diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp
index 1a67a8404..1d552fbc2 100644
--- a/src/display/nr-arena-group.cpp
+++ b/src/display/nr-arena-group.cpp
@@ -13,9 +13,11 @@
*/
#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"
@@ -164,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);
@@ -180,7 +181,7 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int
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);
}
}
diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp
index f3de7a66a..7e19b9f52 100644
--- a/src/display/nr-arena-item.cpp
+++ b/src/display/nr-arena-item.cpp
@@ -215,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),
@@ -243,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;
}
@@ -276,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) {
@@ -289,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) {
@@ -299,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:
@@ -350,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
@@ -389,6 +392,17 @@ 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;
@@ -515,16 +529,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",
@@ -533,34 +537,36 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area)
#endif
unsigned retstate = 0;
-
- // 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);
- }
+
+ // 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) {
- retstate = ((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);
}
- }
-
- 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 retstate;
@@ -624,7 +630,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 */