commit librsvg for openSUSE:Factory
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 - zaitor@opensuse.org + +- 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 <federico@gnome.org> +Date: Wed Mar 25 19:47:09 2015 -0600 + + Update NEWS + + NEWS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +commit 22a90daef0813f1cf2ac70a15266a8b820145b3c +Author: Federico Mena Quintero <federico@gnome.org> +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 <lrn1986@gmail.com> +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 <federico@gnome.org> +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 <federico@gnome.org> +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 <federico@gnome.org> +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... + 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 <agriff@tin.it> +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 <federico@gnome.org> +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 <federico@gnome.org> 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; }
participants (1)
-
root@hilbert.suse.de