Code

Fix snapping regression introduced by rev. #9118
[inkscape.git] / src / display / nr-filter-gaussian.cpp
index 5d071be8c0aafdb62ba5b6091dc69365f8b735e5..9509eaef7f2e4b02e3aeb19c25c5aac57d6252c5 100644 (file)
@@ -345,7 +345,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2,
 
 // Filters over 1st dimension
 // Assumes kernel is symmetric
-// scr_len should be size of kernel - 1
+// Kernel should have scr_len+1 elements
 template<typename PT, unsigned int PC>
 static void
 filter2D_FIR(PT *const dst, int const dstr1, int const dstr2,
@@ -377,7 +377,7 @@ filter2D_FIR(PT *const dst, int const dstr1, int const dstr2,
         for ( int c1 = 0 ; c1 < n1 ; c1++ ) {
 
             int const src_disp = src_line + c1 * sstr1;
-            int const dst_disp = dst_line + c1 * sstr1;
+            int const dst_disp = dst_line + c1 * dstr1;
 
             // update history
             for(int i=scr_len; i>0; i--) copy_n(history[i-1], PC, history[i]);
@@ -433,7 +433,7 @@ filter2D_FIR(PT *const dst, int const dstr1, int const dstr2,
                 // optimization: if there was no variation within this point's neighborhood,
                 // skip ahead while we keep seeing the same last_in byte:
                 // blurring flat color would not change it anyway
-                if (different_count <= 1) {
+                if (different_count <= 1) { // note that different_count is at least 1, because last_in is initialized to -1
                     int pos = c1 + 1;
                     int nb_src_disp = src_disp + (1+scr_len)*sstr1 + byte; // src_line + (pos+scr_len) * sstr1 + byte
                     int nb_dst_disp = dst_disp + (1)        *dstr1 + byte; // dst_line + (pos) * sstr1 + byte
@@ -441,7 +441,7 @@ filter2D_FIR(PT *const dst, int const dstr1, int const dstr2,
                         dst[nb_dst_disp] = last_in;
                         pos++;
                         nb_src_disp += sstr1;
-                        nb_dst_disp += sstr1;
+                        nb_dst_disp += dstr1;
                     }
                     skipbuf[byte] = pos;
                 }
@@ -585,19 +585,18 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
     Geom::Matrix trans = units.get_matrix_primitiveunits2pb();
 
     // Some common constants
-    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
     int const width_org = in->area.x1-in->area.x0, height_org = in->area.y1-in->area.y0;
     double const deviation_x_org = _deviation_x * trans.expansionX();
     double const deviation_y_org = _deviation_y * trans.expansionY();
     int const PC = NR_PIXBLOCK_BPP(in);
 #if HAVE_OPENMP
-    int const NTHREADS = std::max(1,std::min(8,prefs->getInt("/options/threading/numthreads",omp_get_num_procs())));
+    int const NTHREADS = std::max(1,std::min(8, Inkscape::Preferences::get()->getInt("/options/threading/numthreads", omp_get_num_procs())));
 #else
     int const NTHREADS = 1;
 #endif // HAVE_OPENMP
 
     // Subsampling constants
-    int const quality = prefs->getInt("/options/blurquality/value");
+    int const quality = slot.get_blurquality();
     int const x_step_l2 = _effect_subsample_step_log2(deviation_x_org, quality);
     int const y_step_l2 = _effect_subsample_step_log2(deviation_y_org, quality);
     int const x_step = 1<<x_step_l2;
@@ -646,6 +645,8 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
             }
         }
     }
+
+    // Resampling (if necessary), goes from in -> out (setting ssin to out if used)
     NRPixBlock *ssin = in;
     if ( resampling ) {
         ssin = out;
@@ -668,6 +669,7 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
         };
     }
 
+    // Horizontal filtering, goes from ssin -> out (ssin might be equal to out, but these algorithms can be used in-place)
     if (use_IIR_x) {
         // Filter variables
         IIRValue b[N+1];  // scaling coefficient + filter coefficients (can be 10.21 fixed point)
@@ -703,9 +705,9 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
         default:
             assert(false);
         };
-    } else if ( scr_len_x > 1 ) { // !use_IIR_x
+    } else if ( scr_len_x > 0 ) { // !use_IIR_x
         // Filter kernel for x direction
-        FIRValue kernel[scr_len_x];
+        FIRValue kernel[scr_len_x+1];
         _make_kernel(kernel, deviation_x);
 
         // Filter (x)
@@ -729,6 +731,7 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
         nr_blit_pixblock_pixblock(out, ssin);
     }
 
+    // Vertical filtering, goes from out -> out
     if (use_IIR_y) {
         // Filter variables
         IIRValue b[N+1];  // scaling coefficient + filter coefficients (can be 10.21 fixed point)
@@ -764,9 +767,9 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
         default:
             assert(false);
         };
-    } else if ( scr_len_y > 1 ) { // !use_IIR_y
+    } else if ( scr_len_y > 0 ) { // !use_IIR_y
         // Filter kernel for y direction
-        FIRValue kernel[scr_len_y];
+        FIRValue kernel[scr_len_y+1];
         _make_kernel(kernel, deviation_y);
 
         // Filter (y)
@@ -792,6 +795,7 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
         delete[] tmpdata[i]; // deleting a nullptr has no effect, so this is safe
     }
 
+    // Upsampling, stores (the upsampled) out using slot.set(_output, ...)
     if ( !resampling ) {
         // No upsampling needed
         out->empty = FALSE;
@@ -836,6 +840,7 @@ int FilterGaussian::render(FilterSlot &slot, FilterUnits const &units)
         slot.set(_output, finalout);
     }
 
+    // If we downsampled the input, clean up the downsampled data
     if (in != original_in) nr_pixblock_free(in);
 
     return 0;