Hello community,

here is the log from the commit of package librsvg for openSUSE:Factory checked 
in at 2015-04-03 14:33:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/librsvg (Old)
 and      /work/SRC/openSUSE:Factory/.librsvg.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "librsvg"

Changes:
--------
--- /work/SRC/openSUSE:Factory/librsvg/librsvg.changes  2015-03-03 
11:13:15.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.librsvg.new/librsvg.changes     2015-04-03 
14:33:51.000000000 +0200
@@ -1,0 +2,9 @@
+Fri Mar 27 09:22:06 UTC 2015 - [email protected]
+
+- Update to version 2.40.9:
+  + bgo#738367: V/v/H/h commands in path elements were not working.
+  + bgo#605875: Gaussian-blurred objects were sometimes missing.
+  + bgo#710163: Use _wfullpath() on Windows when canonicalizing
+    filenames.
+
+-------------------------------------------------------------------

Old:
----
  librsvg-2.40.8.tar.xz

New:
----
  librsvg-2.40.9.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ librsvg.spec ++++++
--- /var/tmp/diff_new_pack.ZO2Tc0/_old  2015-04-03 14:33:52.000000000 +0200
+++ /var/tmp/diff_new_pack.ZO2Tc0/_new  2015-04-03 14:33:52.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           librsvg
-Version:        2.40.8
+Version:        2.40.9
 Release:        0
 Summary:        A Library for Rendering SVG Data
 License:        LGPL-2.0+ and GPL-2.0+

++++++ librsvg-2.40.8.tar.xz -> librsvg-2.40.9.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/ChangeLog new/librsvg-2.40.9/ChangeLog
--- old/librsvg-2.40.8/ChangeLog        2015-02-27 17:37:39.000000000 +0100
+++ new/librsvg-2.40.9/ChangeLog        2015-03-27 00:50:34.000000000 +0100
@@ -1,3 +1,94 @@
+commit 19bb11837877538382cd11f7243f9875e082268f
+Author: Federico Mena Quintero <[email protected]>
+Date:   Wed Mar 25 19:47:09 2015 -0600
+
+    Update NEWS
+
+ NEWS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+commit 22a90daef0813f1cf2ac70a15266a8b820145b3c
+Author: Federico Mena Quintero <[email protected]>
+Date:   Wed Mar 25 19:44:31 2015 -0600
+
+    Bump version
+
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 28694c791067f0321ae21d44734b1ef88b45d742
+Author: LRN <[email protected]>
+Date:   Tue Mar 24 18:14:23 2015 -0600
+
+    bgo#710163 - Use _wfullpath() on Windows instead of _fullpath()
+
+ rsvg-base.c | 32 ++++++++++++++++++++++++++------
+ 1 file changed, 26 insertions(+), 6 deletions(-)
+
+commit 7fc95d9571c7d25e548a590aae482f9707f290d2
+Author: Federico Mena Quintero <[email protected]>
+Date:   Tue Mar 24 15:25:19 2015 -0600
+
+    Gaussian blur: clip the blurred image to the filter effects region
+
+ rsvg-filter.c | 29 ++++++++++++++++++++++++-----
+ 1 file changed, 24 insertions(+), 5 deletions(-)
+
+commit 054807726db76558728e7a7513aabc4698b3dc95
+Author: Federico Mena Quintero <[email protected]>
+Date:   Fri Mar 13 12:23:11 2015 -0600
+
+    bgo#605875 - Gaussian blurred objects are sometimes missing
+    
+    This replaces the blurring machinery with a real gaussian blur for small 
radiuses,
+    and fixes box blurs for large radiuses.
+    
+    Based on a patch by Eduard Braun.
+
+ rsvg-filter.c | 598 ++++++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 494 insertions(+), 104 deletions(-)
+
+commit 86589fb2046d0d8996ed024c3036f3c0ed48d695
+Author: Federico Mena Quintero <[email protected]>
+Date:   Tue Mar 10 17:48:12 2015 -0600
+
+    Add test for bgo#605875 - Incorrect rendering of feGaussianBlur
+    
+    This test image comes from
+    
https://commons.wikimedia.org/wiki/File:Kaliningrad_Oblast_Coat_of_Arms_2006.svg
+    The topmost jewel in the center of the crown was not getting
+    rendered at all.
+
+ tests/bugs/605875-ref.png | Bin 0 -> 156652 bytes
+ tests/bugs/605875.svg     | 681 ++++++++++++++++++++++++++++++++++++++++++++++
+ tests/rsvg-test.txt       |   1 +
+ 3 files changed, 682 insertions(+)
+
+commit 9628f3da0023bfd3e919e2bfb4c2dc10ad45d9ab
+Author: Andrea Griffini <[email protected]>
+Date:   Fri Mar 13 12:36:24 2015 -0600
+
+    bgo#738367 - Fix handling of V/v/H/h commands in path
+    
+    These were not setting one of the x/y components for the reflection point
+    to be used in smooth curves.
+    
+    https://bugzilla.gnome.org/show_bug.cgi?id=738367
+
+ rsvg-path.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+commit f8d37dfb240f0ecb90a91ce534829ec7ac279071
+Author: Federico Mena Quintero <[email protected]>
+Date:   Fri Mar 13 12:44:53 2015 -0600
+
+    Add test for bgo#738367 - incorrect handling of V/v/H/h commands in path
+
+ tests/bugs/738367-ref.png | Bin 0 -> 4184 bytes
+ tests/bugs/738367.svg     |   7 +++++++
+ tests/rsvg-test.txt       |   1 +
+ 3 files changed, 8 insertions(+)
+
 commit 8eb0392f2041080f32830949ae22cd463bf219b7
 Author: Federico Mena Quintero <[email protected]>
 Date:   Thu Feb 26 16:03:52 2015 -0600
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/NEWS new/librsvg-2.40.9/NEWS
--- old/librsvg-2.40.8/NEWS     2015-02-26 23:03:06.000000000 +0100
+++ new/librsvg-2.40.9/NEWS     2015-03-26 02:47:02.000000000 +0100
@@ -1,3 +1,11 @@
+Version 2.40.9
+- Fixed bgo#738367 - V/v/H/h commands in path elements were not
+  working.  Patch by Andrea Griffini.
+- Fixed bgo#605875 - Gaussian-blurred objects were sometimes missing.
+  Based on a patch by Eduard Braun.
+- Fixed bgo#710163 - use _wfullpath() on Windows when canonicalizing
+  filenames.  Patch by LRN.
+
 Version 2.40.8
 - Bugs fixed from fuzz testing: #744688 - possible double g_free()
   when processing stroke-dasharray
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/configure new/librsvg-2.40.9/configure
--- old/librsvg-2.40.8/configure        2015-02-27 17:36:55.000000000 +0100
+++ new/librsvg-2.40.9/configure        2015-03-27 00:48:49.000000000 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for RSVG 2.40.8.
+# Generated by GNU Autoconf 2.69 for RSVG 2.40.9.
 #
 # Report bugs to <https://bugzilla.gnome.org/enter_bug.cgi?product=librsvg>.
 #
@@ -591,8 +591,8 @@
 # Identity of this package.
 PACKAGE_NAME='RSVG'
 PACKAGE_TARNAME='librsvg'
-PACKAGE_VERSION='2.40.8'
-PACKAGE_STRING='RSVG 2.40.8'
+PACKAGE_VERSION='2.40.9'
+PACKAGE_STRING='RSVG 2.40.9'
 PACKAGE_BUGREPORT='https://bugzilla.gnome.org/enter_bug.cgi?product=librsvg'
 PACKAGE_URL=''
 
@@ -1422,7 +1422,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures RSVG 2.40.8 to adapt to many kinds of systems.
+\`configure' configures RSVG 2.40.9 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1492,7 +1492,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of RSVG 2.40.8:";;
+     short | recursive ) echo "Configuration of RSVG 2.40.9:";;
    esac
   cat <<\_ACEOF
 
@@ -1642,7 +1642,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-RSVG configure 2.40.8
+RSVG configure 2.40.9
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2011,7 +2011,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by RSVG $as_me 2.40.8, which was
+It was created by RSVG $as_me 2.40.9, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2880,7 +2880,7 @@
 
 # Define the identity of the package.
  PACKAGE='librsvg'
- VERSION='2.40.8'
+ VERSION='2.40.9'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3018,13 +3018,13 @@
 
 # ===========================================================================
 
-RSVG_LT_VERSION_INFO=42:8:40
+RSVG_LT_VERSION_INFO=42:9:40
 
 LIBRSVG_MAJOR_VERSION=2
 
 LIBRSVG_MINOR_VERSION=40
 
-LIBRSVG_MICRO_VERSION=8
+LIBRSVG_MICRO_VERSION=9
 
 
 
@@ -15547,7 +15547,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by RSVG $as_me 2.40.8, which was
+This file was extended by RSVG $as_me 2.40.9, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -15613,7 +15613,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-RSVG config.status 2.40.8
+RSVG config.status 2.40.9
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/configure.ac 
new/librsvg-2.40.9/configure.ac
--- old/librsvg-2.40.8/configure.ac     2015-02-13 23:47:01.000000000 +0100
+++ new/librsvg-2.40.9/configure.ac     2015-03-26 02:44:03.000000000 +0100
@@ -1,6 +1,6 @@
 m4_define([rsvg_major_version],[2])
 m4_define([rsvg_minor_version],[40])
-m4_define([rsvg_micro_version],[8])
+m4_define([rsvg_micro_version],[9])
 m4_define([rsvg_extra_version],[])
 
m4_define([rsvg_version],[rsvg_major_version.rsvg_minor_version.rsvg_micro_version()rsvg_extra_version])
 m4_define([rsvg_lt_version_info],m4_eval(rsvg_major_version + 
rsvg_minor_version):rsvg_micro_version:rsvg_minor_version)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/doc/html/annotation-glossary.html 
new/librsvg-2.40.9/doc/html/annotation-glossary.html
--- old/librsvg-2.40.8/doc/html/annotation-glossary.html        2015-02-27 
17:37:39.000000000 +0100
+++ new/librsvg-2.40.9/doc/html/annotation-glossary.html        2015-03-27 
00:50:34.000000000 +0100
@@ -21,35 +21,35 @@
 <td><a accesskey="n" href="licence.html"><img src="right.png" width="24" 
height="24" border="0" alt="Next"></a></td>
 </tr>
 <tr><td colspan="5" class="shortcuts">
-<a class="shortcut" href="#glsO">O</a>
+<a class="shortcut" href="#glsT">T</a>
                       | 
                    <a class="shortcut" href="#glsA">A</a>
                       | 
-                   <a class="shortcut" href="#glsT">T</a>
-                      | 
-                   <a class="shortcut" href="#glsE">E</a>
+                   <a class="shortcut" href="#glsO">O</a>
                       | 
                    <a class="shortcut" href="#glsA">A</a>
+                      | 
+                   <a class="shortcut" href="#glsE">E</a>
 </td></tr>
 </table>
 <div class="glossary">
 <div class="titlepage"><div><div><h1 class="title">
 <a name="annotation-glossary"></a>Annotation Glossary</h1></div></div></div>
+<a name="glsT"></a><h3 class="title">T</h3>
+<dt><span class="glossterm"><a 
name="annotation-glossterm-transfer%20full"></a>transfer full</span></dt>
+<dd class="glossdef"><p>Free data after the code is done.</p></dd>
+<a name="glsA"></a><h3 class="title">A</h3>
+<dt><span class="glossterm"><a 
name="annotation-glossterm-array"></a>array</span></dt>
+<dd class="glossdef"><p>Parameter points to an array of items.</p></dd>
 <a name="glsO"></a><h3 class="title">O</h3>
 <dt><span class="glossterm"><a 
name="annotation-glossterm-out"></a>out</span></dt>
 <dd class="glossdef"><p>Parameter for returning results. Default is <acronym 
title="Free data after the code is done."><span class="acronym">transfer 
full</span></acronym>.</p></dd>
 <a name="glsA"></a><h3 class="title">A</h3>
-<dt><span class="glossterm"><a 
name="annotation-glossterm-array"></a>array</span></dt>
-<dd class="glossdef"><p>Parameter points to an array of items.</p></dd>
-<a name="glsT"></a><h3 class="title">T</h3>
-<dt><span class="glossterm"><a 
name="annotation-glossterm-transfer%20full"></a>transfer full</span></dt>
-<dd class="glossdef"><p>Free data after the code is done.</p></dd>
+<dt><span class="glossterm"><a 
name="annotation-glossterm-allow-none"></a>allow-none</span></dt>
+<dd class="glossdef"><p>NULL is ok, both for passing and for 
returning.</p></dd>
 <a name="glsE"></a><h3 class="title">E</h3>
 <dt><span class="glossterm"><a 
name="annotation-glossterm-element-type"></a>element-type</span></dt>
 <dd class="glossdef"><p>Generics and defining elements of containers and 
arrays.</p></dd>
-<a name="glsA"></a><h3 class="title">A</h3>
-<dt><span class="glossterm"><a 
name="annotation-glossterm-allow-none"></a>allow-none</span></dt>
-<dd class="glossdef"><p>NULL is ok, both for passing and for 
returning.</p></dd>
 </div>
 <div class="footer">
 <hr>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/doc/html/index.html 
new/librsvg-2.40.9/doc/html/index.html
--- old/librsvg-2.40.8/doc/html/index.html      2015-02-27 17:37:39.000000000 
+0100
+++ new/librsvg-2.40.9/doc/html/index.html      2015-03-27 00:50:34.000000000 
+0100
@@ -15,7 +15,7 @@
 <div>
 <div><table class="navigation" id="top" width="100%" cellpadding="2" 
cellspacing="0"><tr><th valign="middle"><p class="title">RSVG Libary Reference 
Manual</p></th></tr></table></div>
 <div><p class="releaseinfo">
-      For RSVG version 2.40.8
+      For RSVG version 2.40.9
 .
       The latest version of this documentation can be found on-line at the
       <a class="ulink" href="http://library.gnome.org/devel/rsvg/index.html"; 
target="_top">GNOME Library</a>.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/doc/html/index.sgml 
new/librsvg-2.40.9/doc/html/index.sgml
--- old/librsvg-2.40.8/doc/html/index.sgml      2015-02-27 17:37:39.000000000 
+0100
+++ new/librsvg-2.40.9/doc/html/index.sgml      2015-03-27 00:50:34.000000000 
+0100
@@ -96,8 +96,8 @@
 <ANCHOR id="LIBRSVG-HAVE-SVGZ:CAPS" 
href="rsvg/rsvg-Version-check-and-feature-tests.html#LIBRSVG-HAVE-SVGZ:CAPS">
 <ANCHOR id="LIBRSVG-HAVE-CSS:CAPS" 
href="rsvg/rsvg-Version-check-and-feature-tests.html#LIBRSVG-HAVE-CSS:CAPS">
 <ANCHOR id="LIBRSVG-CHECK-FEATURE:CAPS" 
href="rsvg/rsvg-Version-check-and-feature-tests.html#LIBRSVG-CHECK-FEATURE:CAPS">
-<ANCHOR id="annotation-glossterm-out" 
href="rsvg/annotation-glossary.html#annotation-glossterm-out">
-<ANCHOR id="annotation-glossterm-array" 
href="rsvg/annotation-glossary.html#annotation-glossterm-array">
 <ANCHOR id="annotation-glossterm-transfer full" 
href="rsvg/annotation-glossary.html#annotation-glossterm-transfer full">
-<ANCHOR id="annotation-glossterm-element-type" 
href="rsvg/annotation-glossary.html#annotation-glossterm-element-type">
+<ANCHOR id="annotation-glossterm-array" 
href="rsvg/annotation-glossary.html#annotation-glossterm-array">
+<ANCHOR id="annotation-glossterm-out" 
href="rsvg/annotation-glossary.html#annotation-glossterm-out">
 <ANCHOR id="annotation-glossterm-allow-none" 
href="rsvg/annotation-glossary.html#annotation-glossterm-allow-none">
+<ANCHOR id="annotation-glossterm-element-type" 
href="rsvg/annotation-glossary.html#annotation-glossterm-element-type">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/doc/version.xml 
new/librsvg-2.40.9/doc/version.xml
--- old/librsvg-2.40.8/doc/version.xml  2015-02-27 17:36:59.000000000 +0100
+++ new/librsvg-2.40.9/doc/version.xml  2015-03-27 00:48:51.000000000 +0100
@@ -1 +1 @@
-2.40.8
+2.40.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/librsvg-features.h 
new/librsvg-2.40.9/librsvg-features.h
--- old/librsvg-2.40.8/librsvg-features.h       2015-02-27 17:36:59.000000000 
+0100
+++ new/librsvg-2.40.9/librsvg-features.h       2015-03-27 00:48:51.000000000 
+0100
@@ -7,8 +7,8 @@
 
 #define LIBRSVG_MAJOR_VERSION (2)
 #define LIBRSVG_MINOR_VERSION (40)
-#define LIBRSVG_MICRO_VERSION (8)
-#define LIBRSVG_VERSION "2.40.8"
+#define LIBRSVG_MICRO_VERSION (9)
+#define LIBRSVG_VERSION "2.40.9"
 
 #define LIBRSVG_CHECK_VERSION(major,minor,micro) \
   (LIBRSVG_MAJOR_VERSION > (major) || \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/rsvg-base.c 
new/librsvg-2.40.9/rsvg-base.c
--- old/librsvg-2.40.8/rsvg-base.c      2015-02-12 21:08:09.000000000 +0100
+++ new/librsvg-2.40.9/rsvg-base.c      2015-03-25 01:12:48.000000000 +0100
@@ -57,13 +57,33 @@
 #include "rsvg-paint-server.h"
 #include "rsvg-xml.h"
 
-/*
- * XXX: Perhaps do a GIO-based implementation for
- * realpath() or use gnulib implementation for this
- * https://bugzilla.gnome.org/show_bug.cgi?id=710163
- */
 #ifdef G_OS_WIN32
-#define realpath(a,b) _fullpath(b,a,_MAX_PATH)
+static char *
+rsvg_realpath_utf8 (const char *filename, const char *unused)
+{
+    wchar_t *wfilename;
+    wchar_t *wfull;
+    char *full;
+
+    wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+    if (!wfilename)
+        return NULL;
+
+    wfull = _wfullpath (NULL, wfilename, 0);
+    g_free (wfilename);
+    if (!wfull)
+        return NULL;
+
+    full = g_utf16_to_utf8 (wfull, -1, NULL, NULL, NULL);
+    free (wfull);
+
+    if (!full)
+        return NULL;
+
+    return full;
+}
+
+#define realpath(a,b) rsvg_realpath_utf8 (a, b)
 #endif
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/rsvg-filter.c 
new/librsvg-2.40.9/rsvg-filter.c
--- old/librsvg-2.40.8/rsvg-filter.c    2015-02-20 01:18:08.000000000 +0100
+++ new/librsvg-2.40.9/rsvg-filter.c    2015-03-24 22:22:07.000000000 +0100
@@ -1327,154 +1327,545 @@
 };
 
 static void
-box_blur (cairo_surface_t *in, 
-          cairo_surface_t *output, 
-          guchar *intermediate, 
-          gint kw,
-          gint kh, 
-          RsvgIRect boundarys, 
-          RsvgFilterPrimitiveOutput op)
+box_blur_line (gint box_width, gint even_offset,
+               guchar *src, guchar *dest,
+               gint len, gint bpp)
 {
-    gint ch;
-    gint x, y;
-    gint rowstride;
-    guchar *in_pixels;
-    guchar *output_pixels;
-    gint sum;
+    gint  i;
+    gint  lead;    /* This marks the leading edge of the kernel              */
+    gint  output;  /* This marks the center of the kernel                    */
+    gint  trail;   /* This marks the pixel BEHIND the last 1 in the
+                      kernel; it's the pixel to remove from the accumulator. */
+    gint  ac[bpp]; /* Accumulator for each channel                           */
+
+
+    /* The algorithm differs for even and odd-sized kernels.
+     * With the output at the center,
+     * If odd, the kernel might look like this: 0011100
+     * If even, the kernel will either be centered on the boundary between
+     * the output and its left neighbor, or on the boundary between the
+     * output and its right neighbor, depending on even_lr.
+     * So it might be 0111100 or 0011110, where output is on the center
+     * of these arrays.
+     */
+    lead = 0;
+
+    if (box_width % 2 != 0) {
+        /* Odd-width kernel */
+        output = lead - (box_width - 1) / 2;
+        trail  = lead - box_width;
+    } else {
+        /* Even-width kernel. */
+        if (even_offset == 1) {
+            /* Right offset */
+            output = lead + 1 - box_width / 2;
+            trail  = lead - box_width;
+        } else if (even_offset == -1) {
+            /* Left offset */
+            output = lead - box_width / 2;
+            trail  = lead - box_width;
+        } else {
+            /* If even_offset isn't 1 or -1, there's some error. */
+            g_assert_not_reached ();
+        }
+    }
 
-    in_pixels = cairo_image_surface_get_data (in);
-    output_pixels = cairo_image_surface_get_data (output);
+    /* Initialize accumulator */
+    for (i = 0; i < bpp; i++)
+        ac[i] = 0;
+
+    /* As the kernel moves across the image, it has a leading edge and a
+     * trailing edge, and the output is in the middle. */
+    while (output < len) {
+        /* The number of pixels that are both in the image and
+         * currently covered by the kernel. This is necessary to
+         * handle edge cases. */
+        guint coverage = (lead < len ? lead : len - 1) - (trail >= 0 ? trail : 
-1);
+
+#ifdef READABLE_BOXBLUR_CODE
+/* The code here does the same as the code below, but the code below
+ * has been optimized by moving the if statements out of the tight for
+ * loop, and is harder to understand.
+ * Don't use both this code and the code below. */
+        for (i = 0; i < bpp; i++) {
+            /* If the leading edge of the kernel is still on the image,
+             * add the value there to the accumulator. */
+            if (lead < len)
+                ac[i] += src[bpp * lead + i];
+
+            /* If the trailing edge of the kernel is on the image,
+             * subtract the value there from the accumulator. */
+            if (trail >= 0)
+                ac[i] -= src[bpp * trail + i];
+
+            /* Take the averaged value in the accumulator and store
+             * that value in the output. The number of pixels currently
+             * stored in the accumulator can be less than the nominal
+             * width of the kernel because the kernel can go "over the edge"
+             * of the image. */
+            if (output >= 0)
+                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
+        }
+#endif
 
-    rowstride = cairo_image_surface_get_stride (in);
+        /* If the leading edge of the kernel is still on the image... */
+        if (lead < len) {
+            if (trail >= 0) {
+                /* If the trailing edge of the kernel is on the image. (Since
+                 * the output is in between the lead and trail, it must be on
+                 * the image. */
+                for (i = 0; i < bpp; i++) {
+                    ac[i] += src[bpp * lead + i];
+                    ac[i] -= src[bpp * trail + i];
+                    dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / 
coverage;
+                }
+            } else if (output >= 0) {
+                /* If the output is on the image, but the trailing edge isn't 
yet
+                 * on the image. */
+            
+                for (i = 0; i < bpp; i++) {
+                    ac[i] += src[bpp * lead + i];
+                    dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / 
coverage;
+                }
+            } else {
+                /* If leading edge is on the image, but the output and trailing
+                 * edge aren't yet on the image. */
+                for (i = 0; i < bpp; i++)
+                    ac[i] += src[bpp * lead + i];
+            }
+        } else if (trail >= 0) {
+            /* If the leading edge has gone off the image, but the output and
+             * trailing edge are on the image. (The big loop exits when the
+             * output goes off the image. */
+            for (i = 0; i < bpp; i++) {
+                ac[i] -= src[bpp * trail + i];
+                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
+            }
+        } else if (output >= 0) {
+            /* Leading has gone off the image and trailing isn't yet in it
+             * (small image) */
+            for (i = 0; i < bpp; i++)
+                dest[bpp * output + i] = (ac[i] + (coverage >> 1)) / coverage;
+        }
 
-    if (kw > boundarys.x1 - boundarys.x0)
-        kw = boundarys.x1 - boundarys.x0;
+        lead++;
+        output++;
+        trail++;
+    }
+}
 
-    if (kh > boundarys.y1 - boundarys.y0)
-        kh = boundarys.y1 - boundarys.y0;
+static gint
+compute_box_blur_width (double radius)
+{
+    double width;
+
+    width = radius * 3 * sqrt (2 * G_PI) / 4;
+    return (gint) (width + 0.5);
+}
+
+#define SQR(x) ((x) * (x))
+
+static void
+make_gaussian_convolution_matrix (gdouble radius, gdouble **out_matrix, gint 
*out_matrix_len)
+{
+    gdouble *matrix;
+    gdouble std_dev;
+    gdouble sum;
+    gint matrix_len;
+    gint i, j;
+
+    std_dev = radius + 1.0;
+    radius = std_dev * 2;
+
+    matrix_len = 2 * ceil (radius - 0.5) + 1;
+    if (matrix_len <= 0)
+        matrix_len = 1;
+
+    matrix = g_new (gdouble, matrix_len);
+
+    /* Fill the matrix by doing numerical integration approximation
+     * from -2*std_dev to 2*std_dev, sampling 50 points per pixel.
+     * We do the bottom half, mirror it to the top half, then compute the
+     * center point.  Otherwise asymmetric quantization errors will occur.
+     * The formula to integrate is e^-(x^2/2s^2).
+     */
+
+    for (i = matrix_len / 2 + 1; i < matrix_len; i++)
+    {
+        gdouble base_x = i - (matrix_len / 2) - 0.5;
+
+        sum = 0;
+        for (j = 1; j <= 50; j++)
+        {
+            gdouble r = base_x + 0.02 * j;
+
+            if (r <= radius)
+                sum += exp (- SQR (r) / (2 * SQR (std_dev)));
+        }
+
+        matrix[i] = sum / 50;
+    }
 
+    /* mirror to the bottom half */
+    for (i = 0; i <= matrix_len / 2; i++)
+        matrix[i] = matrix[matrix_len - 1 - i];
+
+    /* find center val -- calculate an odd number of quanta to make it
+     * symmetric, even if the center point is weighted slightly higher
+     * than others.
+     */
+    sum = 0;
+    for (j = 0; j <= 50; j++)
+        sum += exp (- SQR (- 0.5 + 0.02 * j) / (2 * SQR (std_dev)));
+
+    matrix[matrix_len / 2] = sum / 51;
+
+    /* normalize the distribution by scaling the total sum to one */
+    sum = 0;
+    for (i = 0; i < matrix_len; i++)
+        sum += matrix[i];
 
-    if (kw >= 1) {
-        for (ch = 0; ch < 4; ch++) {
-            switch (ch) {
-            case 0:
-                if (!op.Rused)
-                    continue;
-            case 1:
-                if (!op.Gused)
-                    continue;
-            case 2:
-                if (!op.Bused)
-                    continue;
-            case 3:
-                if (!op.Aused)
-                    continue;
+    for (i = 0; i < matrix_len; i++)
+        matrix[i] = matrix[i] / sum;
+
+    *out_matrix = matrix;
+    *out_matrix_len = matrix_len;
+}
+
+static void
+gaussian_blur_line (gdouble *matrix,
+                    gint matrix_len,
+                    guchar *src,
+                    guchar *dest,
+                    gint len,
+                    gint bpp)
+{
+    guchar *src_p;
+    guchar *src_p1;
+    gint matrix_middle;
+    gint row;
+    gint i, j;
+
+    matrix_middle = matrix_len / 2;
+
+    /* picture smaller than the matrix? */
+    if (matrix_len > len) {
+        for (row = 0; row < len; row++) {
+            /* find the scale factor */
+            gdouble scale = 0;
+
+            for (j = 0; j < len; j++) {
+                /* if the index is in bounds, add it to the scale counter */
+                if (j + matrix_middle - row >= 0 &&
+                    j + matrix_middle - row < matrix_len)
+                    scale += matrix[j];
             }
-            for (y = boundarys.y0; y < boundarys.y1; y++) {
-                sum = 0;
-                for (x = boundarys.x0; x < boundarys.x0 + kw; x++) {
-                    sum += (intermediate[x % kw] = in_pixels[4 * x + y * 
rowstride + ch]);
 
-                    if (x - kw / 2 >= 0 && x - kw / 2 < boundarys.x1)
-                        output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = 
sum / kw;
-                }
-                for (x = boundarys.x0 + kw; x < boundarys.x1; x++) {
-                    sum -= intermediate[x % kw];
-                    sum += (intermediate[x % kw] = in_pixels[4 * x + y * 
rowstride + ch]);
-                    output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = sum 
/ kw;
-                }
-                for (x = boundarys.x1; x < boundarys.x1 + kw; x++) {
-                    sum -= intermediate[x % kw];
+            src_p = src;
+
+            for (i = 0; i < bpp; i++) {
+                gdouble sum = 0;
+
+                src_p1 = src_p++;
+
+                for (j = 0; j < len; j++) {
+                    if (j + matrix_middle - row >= 0 &&
+                        j + matrix_middle - row < matrix_len)
+                        sum += *src_p1 * matrix[j];
 
-                    if (x - kw / 2 >= 0 && x - kw / 2 < boundarys.x1)
-                        output_pixels[4 * (x - kw / 2) + y * rowstride + ch] = 
sum / kw;
+                    src_p1 += bpp;
                 }
+
+                *dest++ = (guchar) (sum / scale + 0.5);
             }
         }
-        in_pixels = output_pixels;
-    }
+    } else {
+        /* left edge */
 
-    if (kh >= 1) {
-        for (ch = 0; ch < 4; ch++) {
-            switch (ch) {
-            case 0:
-                if (!op.Rused)
-                    continue;
-            case 1:
-                if (!op.Gused)
-                    continue;
-            case 2:
-                if (!op.Bused)
-                    continue;
-            case 3:
-                if (!op.Aused)
-                    continue;
-            }
+        for (row = 0; row < matrix_middle; row++) {
+            /* find scale factor */
+            gdouble scale = 0;
 
+            for (j = matrix_middle - row; j < matrix_len; j++)
+                scale += matrix[j];
 
-            for (x = boundarys.x0; x < boundarys.x1; x++) {
-                sum = 0;
+            src_p = src;
 
-                for (y = boundarys.y0; y < boundarys.y0 + kh; y++) {
-                    sum += (intermediate[y % kh] = in_pixels[4 * x + y * 
rowstride + ch]);
+            for (i = 0; i < bpp; i++) {
+                gdouble sum = 0;
 
-                    if (y - kh / 2 >= 0 && y - kh / 2 < boundarys.y1)
-                        output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = 
sum / kh;
+                src_p1 = src_p++;
+
+                for (j = matrix_middle - row; j < matrix_len; j++) {
+                    sum += *src_p1 * matrix[j];
+                    src_p1 += bpp;
                 }
-                for (y = boundarys.y0 + kh; y < boundarys.y1; y++) {
-                    sum -= intermediate[y % kh];
-                    sum += (intermediate[y % kh] = in_pixels[4 * x + y * 
rowstride + ch]);
-                    output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = sum 
/ kh;
+
+                *dest++ = (guchar) (sum / scale + 0.5);
+            }
+        }
+
+        /* go through each pixel in each col */
+        for (; row < len - matrix_middle; row++) {
+            src_p = src + (row - matrix_middle) * bpp;
+
+            for (i = 0; i < bpp; i++) {
+                gdouble sum = 0;
+
+                src_p1 = src_p++;
+
+                for (j = 0; j < matrix_len; j++) {
+                    sum += matrix[j] * *src_p1;
+                    src_p1 += bpp;
                 }
-                for (y = boundarys.y1; y < boundarys.y1 + kh; y++) {
-                    sum -= intermediate[y % kh];
 
-                    if (y - kh / 2 >= 0 && y - kh / 2 < boundarys.y1)
-                        output_pixels[4 * x + (y - kh / 2) * rowstride + ch] = 
sum / kh;
+                *dest++ = (guchar) (sum + 0.5);
+            }
+        }
+
+        /* for the edge condition, we only use available info and scale to one 
*/
+        for (; row < len; row++) {
+            /* find scale factor */
+            gdouble scale = 0;
+
+            for (j = 0; j < len - row + matrix_middle; j++)
+                scale += matrix[j];
+
+            src_p = src + (row - matrix_middle) * bpp;
+
+            for (i = 0; i < bpp; i++) {
+                gdouble sum = 0;
+
+                src_p1 = src_p++;
+
+                for (j = 0; j < len - row + matrix_middle; j++) {
+                    sum += *src_p1 * matrix[j];
+                    src_p1 += bpp;
                 }
+
+                *dest++ = (guchar) (sum / scale + 0.5);
             }
         }
     }
 }
 
 static void
-fast_blur (cairo_surface_t *in, 
-           cairo_surface_t *output, 
-           gfloat sx,
-           gfloat sy, 
-           RsvgIRect boundarys, 
-           RsvgFilterPrimitiveOutput op)
+get_column (guchar *column_data,
+            guchar *src_data,
+            gint src_stride,
+            gint bpp,
+            gint height,
+            gint x)
 {
-    gint kx, ky;
-    guchar *intermediate;
+    gint y;
+    gint c;
+
+    for (y = 0; y < height; y++) {
+        guchar *src = src_data + y * src_stride + x * bpp;
+
+        for (c = 0; c < bpp; c++)
+            column_data[c] = src[c];
 
+        column_data += bpp;
+    }
+}
+
+static void
+put_column (guchar *column_data, guchar *dest_data, gint dest_stride, gint 
bpp, gint height, gint x)
+{
+    gint y;
+    gint c;
+
+    for (y = 0; y < height; y++) {
+        guchar *dst = dest_data + y * dest_stride + x * bpp;
+
+        for (c = 0; c < bpp; c++)
+            dst[c] = column_data[c];
+
+        column_data += bpp;
+    }
+}
+
+static void
+gaussian_blur_surface (cairo_surface_t *in,
+                       cairo_surface_t *out,
+                       gdouble sx,
+                       gdouble sy)
+{
+    gboolean use_box_blur;
+    gint width, height;
+    cairo_format_t in_format, out_format;
+    gint in_stride;
+    gint out_stride;
+    guchar *in_data, *out_data;
+    gint bpp;
+    gboolean out_has_data;
+    
     cairo_surface_flush (in);
 
-    kx = floor (sx * 3 * sqrt (2 * M_PI) / 4 + 0.5);
-    ky = floor (sy * 3 * sqrt (2 * M_PI) / 4 + 0.5);
+    width = cairo_image_surface_get_width (in);
+    height = cairo_image_surface_get_height (in);
+
+    g_assert (width == cairo_image_surface_get_width (out)
+              && height == cairo_image_surface_get_height (out));
+
+    in_format = cairo_image_surface_get_format (in);
+    out_format = cairo_image_surface_get_format (out);
+    g_assert (in_format == out_format);
+    g_assert (in_format == CAIRO_FORMAT_ARGB32
+              || in_format == CAIRO_FORMAT_A8);
+
+    if (in_format == CAIRO_FORMAT_ARGB32)
+        bpp = 4;
+    else if (in_format == CAIRO_FORMAT_A8)
+        bpp = 1;
+    else {
+        g_assert_not_reached ();
+        return;
+    }
+
+    in_stride = cairo_image_surface_get_stride (in);
+    out_stride = cairo_image_surface_get_stride (out);
+
+    in_data = cairo_image_surface_get_data (in);
+    out_data = cairo_image_surface_get_data (out);
+
+    if (sx < 0.0)
+        sx = 0.0;
 
-    if (kx < 1 && ky < 1)
+    if (sy < 0.0)
+        sy = 0.0;
+
+    /* For small radiuses, use a true gaussian kernel; otherwise use three box 
blurs with
+     * clever offsets.
+     */
+    if (sx < 10.0 && sy < 10.0)
+        use_box_blur = FALSE;
+    else
+        use_box_blur = TRUE;
+
+    /* Bail out by just copying? */
+    if ((sx == 0.0 && sy == 0.0)
+        || sx > 1000 || sy > 1000) {
+        cairo_t *cr;
+
+        cr = cairo_create (out);
+        cairo_set_source_surface (cr, in, 0, 0);
+        cairo_paint (cr);
         return;
+    }
+
+    if (sx != 0.0) {
+        gint box_width;
+        gdouble *gaussian_matrix;
+        gint gaussian_matrix_len;
+        int y;
+        guchar *row_buffer;
+        guchar *row1, *row2;
+
+        if (use_box_blur) {
+            box_width = compute_box_blur_width (sx);
+
+            /* twice the size so we can have "two" scratch rows */
+            row_buffer = g_new (guchar, width * bpp * 2);
+            row1 = row_buffer;
+            row2 = row_buffer + width * bpp;
+        } else
+            make_gaussian_convolution_matrix (sx, &gaussian_matrix, 
&gaussian_matrix_len);
+
+        for (y = 0; y < height; y++) {
+            guchar *in_row, *out_row;
+
+            in_row = in_data + in_stride * y;
+            out_row = out_data + out_stride * y;
+
+            if (use_box_blur) {
+                if (box_width % 2 != 0) {
+                    /* Odd-width box blur: repeat 3 times, centered on output 
pixel */
+
+                    box_blur_line (box_width, 0, in_row, row1,    width, bpp);
+                    box_blur_line (box_width, 0, row1,   row2,    width, bpp);
+                    box_blur_line (box_width, 0, row2,   out_row, width, bpp);
+                } else {
+                    /* Even-width box blur:
+                     * This method is suggested by the specification for SVG.
+                     * One pass with width n, centered between output and 
right pixel
+                     * One pass with width n, centered between output and left 
pixel
+                     * One pass with width n+1, centered on output pixel
+                     */
+                    box_blur_line (box_width,     -1, in_row, row1,    width, 
bpp);
+                    box_blur_line (box_width,      1, row1,   row2,    width, 
bpp);
+                    box_blur_line (box_width + 1,  0, row2,   out_row, width, 
bpp);
+                }
+            } else
+                gaussian_blur_line (gaussian_matrix, gaussian_matrix_len, 
in_row, out_row, width, bpp);
+        }
 
-    intermediate = g_new (guchar, MAX (kx, ky));
+        if (!use_box_blur)
+            g_free (gaussian_matrix);
 
-    box_blur (in, output, intermediate, kx, ky, boundarys, op);
-    box_blur (output, output, intermediate, kx, ky, boundarys, op);
-    box_blur (output, output, intermediate, kx, ky, boundarys, op);
+        out_has_data = TRUE;
+    } else
+        out_has_data = FALSE;
+
+    if (sy != 0.0) {
+        gint box_height;
+        gdouble *gaussian_matrix;
+        gint gaussian_matrix_len;
+        guchar *col_buffer;
+        guchar *col1, *col2;
+        int x;
+
+        /* twice the size so we can have the source pixels and the blurred 
pixels */
+        col_buffer = g_new (guchar, height * bpp * 2);
+        col1 = col_buffer;
+        col2 = col_buffer + height * bpp;
+
+        if (use_box_blur) {
+            box_height = compute_box_blur_width (sy);
+        } else
+            make_gaussian_convolution_matrix (sy, &gaussian_matrix, 
&gaussian_matrix_len);
+
+        for (x = 0; x < width; x++) {
+            if (out_has_data)
+                get_column (col1, out_data, out_stride, bpp, height, x);
+            else
+                get_column (col1, in_data, in_stride, bpp, height, x);
+
+            if (use_box_blur) {
+                if (box_height % 2 != 0) {
+                    /* Odd-width box blur */
+                    box_blur_line (box_height, 0, col1, col2, height, bpp);
+                    box_blur_line (box_height, 0, col2, col1, height, bpp);
+                    box_blur_line (box_height, 0, col1, col2, height, bpp);
+                } else {
+                    /* Even-width box blur */
+                    box_blur_line (box_height,     -1, col1, col2, height, 
bpp);
+                    box_blur_line (box_height,      1, col2, col1, height, 
bpp);
+                    box_blur_line (box_height + 1,  0, col1, col2, height, 
bpp);
+                }
+            } else
+                gaussian_blur_line (gaussian_matrix, gaussian_matrix_len, 
col1, col2, height, bpp);
+
+            put_column (col2, out_data, out_stride, bpp, height, x);
+        }
 
-    g_free (intermediate);
+        g_free (col_buffer);
+    }
 
-    cairo_surface_mark_dirty (output);
+    cairo_surface_mark_dirty (out);
 }
 
 static void
 rsvg_filter_primitive_gaussian_blur_render (RsvgFilterPrimitive * self, 
RsvgFilterContext * ctx)
 {
     RsvgFilterPrimitiveGaussianBlur *upself;
+    int width, height;
     cairo_surface_t *output, *in;
     RsvgIRect boundarys;
     gfloat sdx, sdy;
     RsvgFilterPrimitiveOutput op;
+    cairo_t *cr;
 
     upself = (RsvgFilterPrimitiveGaussianBlur *) self;
     boundarys = rsvg_filter_primitive_get_bounds (self, ctx);
@@ -1482,8 +1873,11 @@
     op = rsvg_filter_get_result (self->in, ctx);
     in = op.surface;
 
-    output = _rsvg_image_surface_new (cairo_image_surface_get_width (in), 
-                                      cairo_image_surface_get_height (in));
+    width = cairo_image_surface_get_width (in);
+    height = cairo_image_surface_get_height (in);
+
+    output = _rsvg_image_surface_new (width, height);
+
     if (output == NULL) {
         cairo_surface_destroy (in);
         return;
@@ -1493,7 +1887,22 @@
     sdx = upself->sdx * ctx->paffine.xx;
     sdy = upself->sdy * ctx->paffine.yy;
 
-    fast_blur (in, output, sdx, sdy, boundarys, op);
+    gaussian_blur_surface (in, output, sdx, sdy);
+
+    /* Hard-clip to the filter area */
+    if (!(boundarys.x0 == 0
+          && boundarys.y0 == 0
+          && boundarys.x1 == width
+          && boundarys.y1 == height)) {
+        cr = cairo_create (output);
+        cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+        cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+        cairo_rectangle (cr, 0, 0, width, height);
+        cairo_rectangle (cr,
+                         boundarys.x0, boundarys.y0,
+                         boundarys.x1 - boundarys.x0, boundarys.y1 - 
boundarys.y0);
+        cairo_fill (cr);
+    }
 
     op.surface = output;
     op.bounds = boundarys;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/librsvg-2.40.8/rsvg-path.c 
new/librsvg-2.40.9/rsvg-path.c
--- old/librsvg-2.40.8/rsvg-path.c      2015-02-26 22:38:38.000000000 +0100
+++ new/librsvg-2.40.9/rsvg-path.c      2015-03-13 20:36:05.000000000 +0100
@@ -429,6 +429,7 @@
         if (ctx->param == 1) {
             rsvg_path_builder_line_to (&ctx->builder, ctx->params[0], 
ctx->cp.point.y);
             ctx->cp.point.x = ctx->rp.point.x = ctx->params[0];
+            ctx->rp.point.y = ctx->cp.point.y;
             ctx->param = 0;
         }
         break;
@@ -436,6 +437,7 @@
         /* vertical lineto */
         if (ctx->param == 1) {
             rsvg_path_builder_line_to (&ctx->builder, ctx->cp.point.x, 
ctx->params[0]);
+            ctx->rp.point.x = ctx->cp.point.x;
             ctx->cp.point.y = ctx->rp.point.y = ctx->params[0];
             ctx->param = 0;
         }


Reply via email to