Fix "out of memory" when using linear gradient
Steps to reproduce
- Save the SVG example below as
example.svg
and run the following command to open it by Eye of GNOME.$ eog ./example.svg
- Resize the window of Eye of GNOME to a smaller size
- The following messages are printed in the terminal and the behavior becomes strange.
(eog:755506): Gtk-WARNING **: 22:23:43.421: drawing failure for widget 'EogWindow': out of memory (eog:755506): Gtk-WARNING **: 22:23:43.504: drawing failure for widget 'EogWindow': out of memory (eog:755506): Gtk-WARNING **: 22:23:43.530: drawing failure for widget 'EogWindow': out of memory (eog:755506): Gtk-WARNING **: 22:23:43.563: drawing failure for widget 'EogWindow': out of memory
Why this problem occurs?
This is because Cairo returns an error if the value of matrix elements that the gradient pattern has exceeds PIXMAN_MAX_INT
.
In the attached patch, this problem can be avoided by modifying the _cairo_gradient_pattern_fit_to_range()
function to check the matrix element values and modify the scale factor.
Materials
Example SVG:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="1219" height="794" viewBox="0 0 1219 794" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<defs>
<linearGradient
x1="8146"
y1="-16306"
x2="8146"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.355e-5,6.6e-6,-6.6e-6,2.355e-5,250.10396,425.55418)"
spreadMethod="pad"
id="lineargradient1">
<stop style="stop-opacity:1;stop-color:#e3e0df" offset="0" id="stop1" />
<stop style="stop-opacity:1;stop-color:#64656c" offset="1" id="stop2" />
</linearGradient>
</defs>
<g id="g10" transform="matrix(1.3333333,0,0,1.3333333,0,12.645333)">
<path
d="m 250.051,425.746 c -0.031,0.106 0.031,0.215 0.14,0.246 0.102,0.028"
style="fill:url(#lineargradient1);stroke:none" />
</g>
</svg>
Patch file
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 2c0ba31f8..f74046c96 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2767,6 +2767,12 @@ _cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient,
dim = MAX (dim, fabs (radial->cd1.center.y - radial->cd2.center.y));
dim = MAX (dim, fabs (radial->cd1.radius - radial->cd2.radius));
}
+ dim = MAX (dim, fabs (gradient->base.matrix.xx));
+ dim = MAX (dim, fabs (gradient->base.matrix.xy));
+ dim = MAX (dim, fabs (gradient->base.matrix.x0));
+ dim = MAX (dim, fabs (gradient->base.matrix.yx));
+ dim = MAX (dim, fabs (gradient->base.matrix.yy));
+ dim = MAX (dim, fabs (gradient->base.matrix.y0));
if (unlikely (dim > max_value)) {
cairo_matrix_t scale;
Related issues
Edited by Koichi Akabe