[Libreoffice-commits] core.git: Branch 'libreoffice-7-1' - canvas/source

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Wed Apr 21 18:51:49 UTC 2021


 canvas/source/cairo/cairo_spritehelper.cxx |   32 +++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

New commits:
commit 064f3641240b380a12a88e2bd1ef8f88add2ed23
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Tue Apr 20 17:20:31 2021 +0200
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Wed Apr 21 20:51:15 2021 +0200

    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 at collabora.com>
    (cherry picked from commit 3a4bfe3e45be2d5b591ab5cae3694c9492ca9e1b)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114419
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>

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(),


More information about the Libreoffice-commits mailing list