summaryrefslogtreecommitdiffstats
path: root/canvas
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-04-20 17:20:31 +0200
committerAndras Timar <andras.timar@collabora.com>2021-04-21 21:08:16 +0200
commitb8ebcf1c35ad99322c7eea5061f232fb14235560 (patch)
tree69919be1c48f3e3f30aadf5e69e3068c2106d700 /canvas
parentResolves: tdf#141765 set 'color' GtkToolbar to small-button size (diff)
downloadcore-b8ebcf1c35ad99322c7eea5061f232fb14235560.tar.gz
core-b8ebcf1c35ad99322c7eea5061f232fb14235560.zip
prevent cairo from breaking because of a large matrix (tdf#125949)
Some presentation animations temporarily cause extensive zoom matrix and Cairo doesn't take that well. Change-Id: I1eb6d63fc2dcde6553bc8cc7ab967532d085a579 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114344 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com> (cherry picked from commit 3a4bfe3e45be2d5b591ab5cae3694c9492ca9e1b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114419 Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'canvas')
-rw-r--r--canvas/source/cairo/cairo_spritehelper.cxx32
1 files changed, 32 insertions, 0 deletions
diff --git a/canvas/source/cairo/cairo_spritehelper.cxx b/canvas/source/cairo/cairo_spritehelper.cxx
index 1fe9eb9152e0..b0eb7e9b7e44 100644
--- a/canvas/source/cairo/cairo_spritehelper.cxx
+++ b/canvas/source/cairo/cairo_spritehelper.cxx
@@ -28,6 +28,7 @@
#include <tools/diagnose_ex.h>
#include <cairo.h>
+#include <pixman.h>
#include "cairo_spritehelper.hxx"
@@ -140,6 +141,37 @@ namespace cairocanvas
cairo_clip( pCairo.get() );
cairo_set_matrix( pCairo.get(), &aOrigMatrix );
+ cairo_matrix_t aInverseMatrix = aOrigMatrix;
+ bool matrixProblem = false;
+ // tdf#125949: Cairo internally uses the pixman library, and _cairo_matrix_to_pixman_matrix()
+ // checks all matrix components to fix PIXMAN_MAX_INT, which is about 32k. Which means that
+ // if our transformation is large, such as an initial step of some zooming animations,
+ // the conversion will fail. To make things worse, once something in cairo fails, it's treated
+ // as a fatal error, the error status of that cairo_t gets set, and there's no way to reset it
+ // besides recreating the whole cairo_t
+ // (https://lists.cairographics.org/archives/cairo/2006-September/007892.html).
+ // So copy&paste PIXMAN_MAX_INT here, and if our matrix could fail, bail out.
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+ if(cairo_matrix_invert(&aInverseMatrix) == CAIRO_STATUS_SUCCESS)
+ {
+ if(abs(aOrigMatrix.xx) > PIXMAN_MAX_INT || abs(aOrigMatrix.xx) > PIXMAN_MAX_INT
+ || abs(aOrigMatrix.xy) > PIXMAN_MAX_INT || abs(aOrigMatrix.yx) > PIXMAN_MAX_INT
+ || abs(aOrigMatrix.x0) > PIXMAN_MAX_INT || abs(aOrigMatrix.y0) > PIXMAN_MAX_INT
+ || abs(aInverseMatrix.xx) > PIXMAN_MAX_INT || abs(aInverseMatrix.xx) > PIXMAN_MAX_INT
+ || abs(aInverseMatrix.xy) > PIXMAN_MAX_INT || abs(aInverseMatrix.yx) > PIXMAN_MAX_INT
+ || abs(aInverseMatrix.x0) > PIXMAN_MAX_INT || abs(aInverseMatrix.y0) > PIXMAN_MAX_INT)
+ matrixProblem = true;
+#undef PIXMAN_MAX_INT
+ }
+ else
+ matrixProblem = true;
+ if(matrixProblem)
+ {
+ SAL_WARN( "canvas.cairo", "matrix would overflow PIXMAN_MAX_INT, avoiding drawing" );
+ cairo_restore( pCairo.get() );
+ return;
+ }
+
if( isContentFullyOpaque() )
cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE );
cairo_set_source_surface( pCairo.get(),