From 9bf80f42b0d99fc1bff5461a563d9fa2b5f81082 Mon Sep 17 00:00:00 2001 From: Jasper van de Gronde Date: Wed, 4 Aug 2010 14:51:48 +0200 Subject: [PATCH] Fix to background handling that avoids both duplication and aliasing as much as possible. --- src/display/nr-arena-item.cpp | 37 ++++------ src/display/nr-arena-item.h | 2 +- src/display/nr-filter-slot.cpp | 119 ++++++++++++++------------------- src/display/nr-filter-slot.h | 18 +++-- 4 files changed, 75 insertions(+), 101 deletions(-) diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index b80df7273..3b8dceb93 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -323,8 +323,11 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area item->state); #ifdef NR_ARENA_ITEM_VERBOSE - printf ("Invoke render %p: %d %d - %d %d\n", item, area->x0, area->y0, - area->x1, area->y1); + g_message ("Invoke render %p on %p: %d %d - %d %d, %d %d - %d %d", item, pb, + area->x0, area->y0, + area->x1, area->y1, + item->drawbox.x0, item->drawbox.y0, + item->drawbox.x1, item->drawbox.y1); #endif /* If we are invisible, just return successfully */ @@ -415,8 +418,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area /* Determine, whether we need temporary buffer */ if (item->clip || item->mask || ((item->opacity != 255) && !item->render_opacity) - || (item->filter && filter) || item->background_new - || (item->parent && item->parent->background_pb)) { + || (item->filter && filter) || item->background_new) { /* Setup and render item buffer */ NRPixBlock ipb; @@ -432,8 +434,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area /* If background access is used, save the pixblock address. * This address is set to NULL at the end of this block */ - if (item->background_new || - (item->parent && item->parent->background_pb)) { + if (item->background_new) { item->background_pb = &ipb; } @@ -859,29 +860,15 @@ nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox) /** Returns a background image for use with filter effects. */ NRPixBlock * -nr_arena_item_get_background (NRArenaItem const *item, int depth) +nr_arena_item_get_background (NRArenaItem const *item) { - NRPixBlock *pb; - if (!item->background_pb) - return NULL; if (item->background_new) { - pb = new NRPixBlock (); - nr_pixblock_setup_fast (pb, item->background_pb->mode, - item->background_pb->area.x0, - item->background_pb->area.y0, - item->background_pb->area.x1, - item->background_pb->area.y1, true); - if (pb->size != NR_PIXBLOCK_SIZE_TINY && pb->data.px == NULL) // allocation failed - return NULL; + return item->background_pb; } else if (item->parent) { - pb = nr_arena_item_get_background (item->parent, depth + 1); - } else + return nr_arena_item_get_background (item->parent); + } else { return NULL; - - if (depth > 0) - nr_blit_pixblock_pixblock (pb, item->background_pb); - - return pb; + } } /* Helpers */ diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index 2faa7d2d0..e92fb1313 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -181,7 +181,7 @@ void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask); void nr_arena_item_set_order (NRArenaItem *item, int order); void nr_arena_item_set_item_bbox (NRArenaItem *item, Geom::OptRect &bbox); -NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item, int depth = 0); +NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item); /* Helpers */ diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 7df9ab979..354b31b4d 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -70,26 +70,22 @@ FilterSlot::FilterSlot(int slots, NRArenaItem const *item) blurquality(BLUR_QUALITY_BEST), _arena_item(item) { - _slot_count = ((slots > 0) ? slots : 2); - _slot = new NRPixBlock*[_slot_count]; - _slot_number = new int[_slot_count]; - - for (int i = 0 ; i < _slot_count ; i++) { - _slot[i] = NULL; - _slot_number[i] = NR_FILTER_SLOT_NOT_SET; - } + _slots.reserve((slots > 0) ? slots : 2); } FilterSlot::~FilterSlot() { - for (int i = 0 ; i < _slot_count ; i++) { - if (_slot[i]) { - nr_pixblock_release(_slot[i]); - delete _slot[i]; + for (unsigned int i = 0 ; i < _slots.size() ; i++) { + if (_slots[i].owned) { + nr_pixblock_release(_slots[i].pb); + delete _slots[i].pb; } } - delete[] _slot; - delete[] _slot_number; +} + +FilterSlot::slot_entry_t::~slot_entry_t() +{ + // It's a bad idea to destruct pixblocks here, as this will also be called upon resizing _slots } NRPixBlock *FilterSlot::get(int slot_nr) @@ -99,7 +95,7 @@ NRPixBlock *FilterSlot::get(int slot_nr) /* If we didn't have the specified image, but we could create it * from the other information we have, let's do that */ - if (_slot[index] == NULL + if (_slots[index].pb == NULL && (slot_nr == NR_FILTER_SOURCEALPHA || slot_nr == NR_FILTER_BACKGROUNDIMAGE || slot_nr == NR_FILTER_BACKGROUNDALPHA @@ -112,7 +108,7 @@ NRPixBlock *FilterSlot::get(int slot_nr) pb = nr_arena_item_get_background(_arena_item); if (pb) { pb->empty = false; - this->set(NR_FILTER_BACKGROUNDIMAGE, pb); + this->set(NR_FILTER_BACKGROUNDIMAGE, pb, false); } else { NRPixBlock *source = this->get(NR_FILTER_SOURCEGRAPHIC); pb = new NRPixBlock(); @@ -145,12 +141,12 @@ NRPixBlock *FilterSlot::get(int slot_nr) } } - if (_slot[index]) { - _slot[index]->empty = false; + if (_slots[index].pb) { + _slots[index].pb->empty = false; } - assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr); - return _slot[index]; + assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slots[index].number == slot_nr); + return _slots[index].pb; } void FilterSlot::get_final(int slot_nr, NRPixBlock *result) { @@ -175,7 +171,7 @@ void FilterSlot::get_final(int slot_nr, NRPixBlock *result) { } } -void FilterSlot::set(int slot_nr, NRPixBlock *pb) +void FilterSlot::set(int slot_nr, NRPixBlock *pb, bool takeOwnership) { /* Unnamed slot is for saving filter primitive results, when parameter * 'result' is not set. Only the filter immediately after this one @@ -189,7 +185,7 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb) assert(index >= 0); // Unnamed slot is only for Inkscape::Filters::FilterSlot internal use. assert(slot_nr != NR_FILTER_UNNAMED_SLOT); - assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr); + assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slots[index].number == slot_nr); if (slot_nr == NR_FILTER_SOURCEGRAPHIC || slot_nr == NR_FILTER_BACKGROUNDIMAGE) { Geom::Matrix trans = units.get_matrix_display2pb(); @@ -225,6 +221,10 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb) * is not too high, but can get thousands of pixels wide. * Rotate this 45 degrees -> _huge_ image */ g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (transform)"); + if (takeOwnership) { + nr_pixblock_release(pb); + delete pb; + } return; } if (filterquality == FILTER_QUALITY_BEST) { @@ -232,8 +232,11 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb) } else { NR::transform_nearest(trans_pb, pb, trans); } - nr_pixblock_release(pb); - delete pb; + if (takeOwnership) { + nr_pixblock_release(pb); + delete pb; + } + takeOwnership = true; pb = trans_pb; } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) { NRPixBlock *trans_pb = new NRPixBlock; @@ -255,31 +258,34 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb) min_x, min_y, max_x, max_y, true); if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) { g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (scaling)"); + if (takeOwnership) { + nr_pixblock_release(pb); + delete pb; + } return; } NR::scale_bicubic(trans_pb, pb, trans); - nr_pixblock_release(pb); - delete pb; + if (takeOwnership) { + nr_pixblock_release(pb); + delete pb; + } + takeOwnership = true; pb = trans_pb; } } - if(_slot[index]) { - nr_pixblock_release(_slot[index]); - delete _slot[index]; + if(_slots[index].owned) { + nr_pixblock_release(_slots[index].pb); + delete _slots[index].pb; } - _slot[index] = pb; + _slots[index].pb = pb; + _slots[index].owned = takeOwnership; _last_out = index; } int FilterSlot::get_slot_count() { - int seek = _slot_count; - do { - seek--; - } while (!_slot[seek] && _slot_number[seek] == NR_FILTER_SLOT_NOT_SET); - - return seek + 1; + return _slots.size(); } NRArenaItem const* FilterSlot::get_arenaitem() @@ -299,47 +305,22 @@ int FilterSlot::_get_index(int slot_nr) slot_nr == NR_FILTER_STROKEPAINT || slot_nr == NR_FILTER_UNNAMED_SLOT); - int index = -1; if (slot_nr == NR_FILTER_SLOT_NOT_SET) { return _last_out; } + /* Search, if the slot already exists */ - for (int i = 0 ; i < _slot_count ; i++) { - if (_slot_number[i] == slot_nr) { - index = i; - break; + for (int i = 0 ; i < (int)_slots.size() ; i++) { + if (_slots[i].number == slot_nr) { + return i; } } /* If the slot doesn't already exist, create it */ - if (index == -1) { - int seek = _slot_count; - do { - seek--; - } while ((seek >= 0) && (_slot_number[seek] == NR_FILTER_SLOT_NOT_SET)); - /* If there is no space for more slots, create more space */ - if (seek == _slot_count - 1) { - NRPixBlock **new_slot = new NRPixBlock*[_slot_count * 2]; - int *new_number = new int[_slot_count * 2]; - for (int i = 0 ; i < _slot_count ; i++) { - new_slot[i] = _slot[i]; - new_number[i] = _slot_number[i]; - } - for (int i = _slot_count ; i < _slot_count * 2 ; i++) { - new_slot[i] = NULL; - new_number[i] = NR_FILTER_SLOT_NOT_SET; - } - delete[] _slot; - delete[] _slot_number; - _slot = new_slot; - _slot_number = new_number; - _slot_count *= 2; - } - /* Now that there is space, create the slot */ - _slot_number[seek + 1] = slot_nr; - index = seek + 1; - } - return index; + slot_entry_t entry; + entry.number = slot_nr; + _slots.push_back(entry); + return (int)_slots.size()-1; } void FilterSlot::set_units(FilterUnits const &units) { diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 8d7a82d2d..a12d75a26 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -17,6 +17,7 @@ #include "libnr/nr-pixblock.h" #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" +#include struct NRArenaItem; @@ -59,11 +60,11 @@ public: * If there was a pixblock already assigned with this slot, * that pixblock is destroyed. * Pixblocks passed to this function should be considered - * managed by this FilterSlot object. + * managed by this FilterSlot object if takeOwnership==true. * Pixblocks passed to this function should be reserved with - * c++ -style new-operator. + * c++ -style new-operator (if managed by FilterSlot). */ - void set(int slot, NRPixBlock *pb); + void set(int slot, NRPixBlock *pb, bool takeOwnership=true); /** Returns the number of slots in use. */ int get_slot_count(); @@ -84,9 +85,14 @@ public: int get_blurquality(void); private: - NRPixBlock **_slot; - int *_slot_number; - int _slot_count; + struct slot_entry_t { + NRPixBlock* pb; + int number; + bool owned; + slot_entry_t() : pb(0), number(NR_FILTER_SLOT_NOT_SET), owned(false) {} + ~slot_entry_t(); + }; + std::vector _slots; int _last_out; -- 2.30.2