From 65eae2322034eb4dd4fe9789e3531736a238c30c Mon Sep 17 00:00:00 2001 From: buliabyak Date: Mon, 9 Mar 2009 01:13:55 +0000 Subject: [PATCH] separate bbox (calculated by subclasses) and drawbox, which includes filters margin and clip/mask cropping; this fixes runaway enlargement when dragging a blurred group. also, move request to dirty canvas rectangle from subclasses to NRArenaItem, which uses drawbox for this, fixing numerous rendering glitches with filters --- src/display/nr-arena-glyphs.cpp | 1 - src/display/nr-arena-group.cpp | 2 +- src/display/nr-arena-image.cpp | 5 --- src/display/nr-arena-item.cpp | 56 ++++++++++++++++++++------------- src/display/nr-arena-item.h | 2 ++ src/display/nr-arena-shape.cpp | 1 - 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 802fe448c..429f1ed32 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -215,7 +215,6 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s item->bbox.y0 = (gint32)(bbox.y0 - 1.0); item->bbox.x1 = (gint32)(bbox.x1 + 1.0); item->bbox.y1 = (gint32)(bbox.y1 + 1.0); - nr_arena_request_render_rect(item->arena, &item->bbox); return NR_ARENA_ITEM_STATE_ALL; } diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index d73a0ecbf..38d37c233 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -181,7 +181,7 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int nr_rect_l_set_empty (&item->bbox); for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) - nr_rect_l_union (&item->bbox, &item->bbox, &child->bbox); + nr_rect_l_union (&item->bbox, &item->bbox, &child->drawbox); } } diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index da2f5ce7e..07533aadc 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -111,9 +111,6 @@ nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned NRArenaImage *image = NR_ARENA_IMAGE (item); - /* Request render old */ - nr_arena_item_request_render (item); - /* Copy affine */ grid2px = gc->transform.inverse(); double hscale, vscale; // todo: replace with Geom::Scale @@ -162,8 +159,6 @@ nr_arena_image_update( NRArenaItem *item, NRRectL */*area*/, NRGC *gc, unsigned item->bbox.y1 = item->bbox.y0 - 1; } - nr_arena_item_request_render (item); - return NR_ARENA_ITEM_STATE_ALL; } diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 04b814cfb..bdab5b479 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -81,6 +81,7 @@ nr_arena_item_init (NRArenaItem *item) item->visible = TRUE; memset (&item->bbox, 0, sizeof (item->bbox)); + memset (&item->drawbox, 0, sizeof (item->drawbox)); item->transform = NULL; item->opacity = 255; item->render_opacity = FALSE; @@ -234,7 +235,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->bbox)) + if (!nr_rect_l_test_intersect_ptr(area, &item->drawbox)) return item->state; } @@ -252,12 +253,17 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->ctm = childgc.transform; /* Invoke the real method */ + // that will update bbox item->state = NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state, reset); if (item->state & NR_ARENA_ITEM_STATE_INVALID) return item->state; - /* Enlarge the bounding box to contain filter effects */ + + // get a copy of bbox + memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); + + /* Enlarge the drawbox to contain filter effects */ if (item->filter && filter) { - item->filter->bbox_enlarge (item->bbox); + item->filter->bbox_enlarge (item->drawbox); } // 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) @@ -272,7 +278,8 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - nr_rect_l_intersect (&item->bbox, &item->bbox, &item->clip->bbox); + // for clipping, we need geometric bbox + nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); } /* Masking */ if (item->mask) { @@ -281,7 +288,14 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - nr_rect_l_intersect (&item->bbox, &item->bbox, &item->mask->bbox); + // 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: + if (!NR_IS_ARENA_GROUP(item) || (item->filter && filter)) { + // unless filtered, groups do not need to render by themselves, only their members + nr_arena_item_request_render (item); } return item->state; @@ -311,17 +325,17 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area area->x1, area->y1); #endif - /* If we are outside bbox just return successfully */ + /* If we are invisible, just return successfully */ if (!item->visible) return item->state | NR_ARENA_ITEM_STATE_RENDER; NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->bbox); + 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->bbox); + nr_rect_l_intersect (&carea, &carea, &item->drawbox); } if (outline) { @@ -360,10 +374,10 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area /* fixme: This probably cannot overflow, because we render only if visible */ /* fixme: and pixel cache is there only for small items */ /* fixme: But this still needs extra check (Lauris) */ - item->bbox.x0, item->bbox.y0, - item->bbox.x1, item->bbox.y1, + item->drawbox.x0, item->drawbox.y0, + item->drawbox.x1, item->drawbox.y1, item->px, - 4 * (item->bbox.x1 - item->bbox.x0), FALSE, + 4 * (item->drawbox.x1 - item->drawbox.x0), FALSE, FALSE); nr_blit_pixblock_pixblock (pb, &cpb); nr_pixblock_release (&cpb); @@ -375,15 +389,15 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area /* Setup cache if we can */ if ((!(flags & NR_ARENA_ITEM_RENDER_NO_CACHE)) && - (carea.x0 <= item->bbox.x0) && (carea.y0 <= item->bbox.y0) && - (carea.x1 >= item->bbox.x1) && (carea.y1 >= item->bbox.y1) && - (((item->bbox.x1 - item->bbox.x0) * (item->bbox.y1 - - item->bbox.y0)) <= 4096)) { - // Item bbox is fully in renderable area and size is acceptable - carea.x0 = item->bbox.x0; - carea.y0 = item->bbox.y0; - carea.x1 = item->bbox.x1; - carea.y1 = item->bbox.y1; + (carea.x0 <= item->drawbox.x0) && (carea.y0 <= item->drawbox.y0) && + (carea.x1 >= item->drawbox.x1) && (carea.y1 >= item->drawbox.y1) && + (((item->drawbox.x1 - item->drawbox.x0) * (item->drawbox.y1 - + item->drawbox.y0)) <= 4096)) { + // Item drawbox is fully in renderable area and size is acceptable + carea.x0 = item->drawbox.x0; + carea.y0 = item->drawbox.y0; + carea.x1 = item->drawbox.x1; + carea.y1 = item->drawbox.y1; item->px = new (GC::ATOMIC) unsigned char[4 * (carea.x1 - carea.x0) * (carea.y1 - carea.y0)]; @@ -672,7 +686,7 @@ 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->bbox); + nr_arena_request_render_rect (item->arena, &item->drawbox); } /* Public */ diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index 17a223b31..2faa7d2d0 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -89,6 +89,8 @@ struct NRArenaItem : public NRObject { /* BBox in grid coordinates */ NRRectL bbox; + /* Redraw area in grid coordinates = bbox filter-enlarged and clipped/masked */ + NRRectL drawbox; /* BBox in item coordinates - this should be a bounding box as * specified in SVG standard. Required by filters. */ Geom::OptRect item_bbox; diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index aafdc37d6..96ea76cbe 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -365,7 +365,6 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g item->bbox.y0 = (gint32)((*boundingbox)[1][0] - 1.0F); item->bbox.x1 = (gint32)((*boundingbox)[0][1] + 1.0F); item->bbox.y1 = (gint32)((*boundingbox)[1][1] + 1.0F); - nr_arena_request_render_rect(item->arena, &item->bbox); item->render_opacity = TRUE; if ( shape->_fill.paint.type() == NRArenaShape::Paint::SERVER ) { -- 2.30.2