Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / display / nr-filter-slot.cpp
index 432598b7cfe323c39f4356484a81f3aba0aa2873..96e2a92e915e53ea4bbe2ea180443419d2247ce6 100644 (file)
@@ -1,5 +1,3 @@
-#define __NR_FILTER_SLOT_CPP__
-
 /*
  * A container class for filter slots. Allows for simple getting and
  * setting images in filter slots without having to bother with
  */
 
 #include <assert.h>
+#include <string.h>
 
 #include "display/nr-arena-item.h"
 #include "display/nr-filter-types.h"
+#include "display/nr-filter-gaussian.h"
 #include "display/nr-filter-slot.h"
 #include "display/nr-filter-getalpha.h"
 #include "display/nr-filter-units.h"
@@ -61,34 +61,31 @@ inline static int _min2(const double a, const double b) {
         return (int)round(a);
 }
 
-namespace NR {
+namespace Inkscape {
+namespace Filters {
 
 FilterSlot::FilterSlot(int slots, NRArenaItem const *item)
+    : _last_out(-1),
+      filterquality(FILTER_QUALITY_BEST),
+      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;
-    }
-
-    _last_out = -1;
-
-    _arena_item = item;
+    _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)
@@ -98,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
@@ -111,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();
@@ -144,17 +141,17 @@ 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) {
     NRPixBlock *final_usr = get(slot_nr);
-    Matrix trans = units.get_matrix_pb2display();
+    Geom::Matrix trans = units.get_matrix_pb2display();
 
     int size = (result->area.x1 - result->area.x0)
         * (result->area.y1 - result->area.y0)
@@ -162,22 +159,36 @@ void FilterSlot::get_final(int slot_nr, NRPixBlock *result) {
     memset(NR_PIXBLOCK_PX(result), 0, size);
 
     if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
-        transform_nearest(result, final_usr, trans);
+        if (filterquality == FILTER_QUALITY_BEST) {
+            NR::transform_bicubic(result, final_usr, trans);
+        } else {
+            NR::transform_nearest(result, final_usr, trans);
+        }
     } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) {
-        scale_bicubic(result, final_usr);
+        NR::scale_bicubic(result, final_usr, trans);
     } else {
         nr_blit_pixblock_pixblock(result, final_usr);
     }
 }
 
-void FilterSlot::set(int slot_nr, NRPixBlock *pb)
+void FilterSlot::set(int slot_nr, NRPixBlock *pb, bool takeOwnership)
 {
-    int index = _get_index(slot_nr);
+    /* Unnamed slot is for saving filter primitive results, when parameter
+     * 'result' is not set. Only the filter immediately after this one
+     * can access unnamed results, so we don't have to worry about overwriting
+     * previous results in filter chain. On the other hand, we may not
+     * overwrite any other image with this one, because they might be
+     * accessed later on. */
+    int index = ((slot_nr != NR_FILTER_SLOT_NOT_SET)
+                 ? _get_index(slot_nr)
+                 : _get_index(NR_FILTER_UNNAMED_SLOT));
     assert(index >= 0);
-    assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
+    // 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 ||_slots[index].number == slot_nr);
 
     if (slot_nr == NR_FILTER_SOURCEGRAPHIC || slot_nr == NR_FILTER_BACKGROUNDIMAGE) {
-        Matrix trans = units.get_matrix_display2pb();
+        Geom::Matrix trans = units.get_matrix_display2pb();
         if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
             NRPixBlock *trans_pb = new NRPixBlock;
             int x0 = pb->area.x0;
@@ -200,7 +211,7 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb)
                               trans[1] * x0 + trans[3] * y1 + trans[5],
                               trans[1] * x1 + trans[3] * y0 + trans[5],
                               trans[1] * x1 + trans[3] * y1 + trans[5]);
-            
+
             nr_pixblock_setup_fast(trans_pb, pb->mode,
                                    min_x, min_y,
                                    max_x, max_y, true);
@@ -209,12 +220,23 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb)
                  * images are exported in horizontal stripes. One stripe
                  * is not too high, but can get thousands of pixels wide.
                  * Rotate this 45 degrees -> _huge_ image */
-                g_warning("Memory allocation failed in NR::FilterSlot::set (transform)");
+                g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (transform)");
+                if (takeOwnership) {
+                    nr_pixblock_release(pb);
+                    delete pb;
+                }
                 return;
             }
-            transform_nearest(trans_pb, pb, trans);
-            nr_pixblock_release(pb);
-            delete pb;
+            if (filterquality == FILTER_QUALITY_BEST) {
+                NR::transform_bicubic(trans_pb, pb, trans);
+            } else {
+                NR::transform_nearest(trans_pb, pb, trans);
+            }
+            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;
@@ -235,32 +257,35 @@ void FilterSlot::set(int slot_nr, NRPixBlock *pb)
             nr_pixblock_setup_fast(trans_pb, pb->mode,
                                    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 NR::FilterSlot::set (scaling)");
+                g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (scaling)");
+                if (takeOwnership) {
+                    nr_pixblock_release(pb);
+                    delete pb;
+                }
                 return;
             }
-            scale_bicubic(trans_pb, pb);
-            nr_pixblock_release(pb);
-            delete pb;
+            NR::scale_bicubic(trans_pb, pb, trans);
+            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()
@@ -277,57 +302,46 @@ int FilterSlot::_get_index(int slot_nr)
            slot_nr == NR_FILTER_BACKGROUNDIMAGE ||
            slot_nr == NR_FILTER_BACKGROUNDALPHA ||
            slot_nr == NR_FILTER_FILLPAINT ||
-           slot_nr == NR_FILTER_STROKEPAINT);
+           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 (_slot_number[seek] == NR_FILTER_SLOT_NOT_SET && seek >= 0);
-        /* 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) {
     this->units = units;
 }
 
+void FilterSlot::set_quality(FilterQuality const q) {
+    filterquality = q;
+}
+
+void FilterSlot::set_blurquality(int const q) {
+    blurquality = q;
 }
 
+int FilterSlot::get_blurquality(void) {
+    return blurquality;
+}
+
+} /* namespace Filters */
+} /* namespace Inkscape */
+
 /*
   Local Variables:
   mode:c++
@@ -337,4 +351,4 @@ void FilterSlot::set_units(FilterUnits const &units) {
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :