Code

Fix to background handling that avoids both duplication and aliasing as much as possible.
authorJasper van de Gronde <th.v.d.gronde@hccnet.nl>
Wed, 4 Aug 2010 12:51:48 +0000 (14:51 +0200)
committerJasper van de Gronde <th.v.d.gronde@hccnet.nl>
Wed, 4 Aug 2010 12:51:48 +0000 (14:51 +0200)
src/display/nr-arena-item.cpp
src/display/nr-arena-item.h
src/display/nr-filter-slot.cpp
src/display/nr-filter-slot.h

index b80df727340113407243f4f3424d698645115135..3b8dceb93aa1ad017a1c0b5711083d380652cba6 100644 (file)
@@ -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 */
index 2faa7d2d05557de7ccb2413a0b30388b235a86c5..e92fb1313d36f05091e9c1ffe615057bf3e5d605 100644 (file)
@@ -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 */
 
index 7df9ab97931a7ce68ac1a92f3a012ca1fe3bdc4c..354b31b4da65964bc1a4d4992869844d394b44b0 100644 (file)
@@ -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) {
index 8d7a82d2d80bed1411df86af66fcc7d59f1afa4c..a12d75a26475189a409fca84abc2d3b907261096 100644 (file)
@@ -17,6 +17,7 @@
 #include "libnr/nr-pixblock.h"
 #include "display/nr-filter-types.h"
 #include "display/nr-filter-units.h"
+#include <vector>
 
 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<slot_entry_t> _slots;
 
     int _last_out;