summaryrefslogtreecommitdiff
path: root/canvas/source/cairo/cairo_spritehelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'canvas/source/cairo/cairo_spritehelper.cxx')
-rw-r--r--canvas/source/cairo/cairo_spritehelper.cxx43
1 files changed, 36 insertions, 7 deletions
diff --git a/canvas/source/cairo/cairo_spritehelper.cxx b/canvas/source/cairo/cairo_spritehelper.cxx
index 667f1ba249ba..4e536261989c 100644
--- a/canvas/source/cairo/cairo_spritehelper.cxx
+++ b/canvas/source/cairo/cairo_spritehelper.cxx
@@ -25,9 +25,10 @@
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/utils/canvastools.hxx>
#include <rtl/math.hxx>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
#include <cairo.h>
+#include <pixman.h>
#include "cairo_spritehelper.hxx"
@@ -37,8 +38,6 @@ using namespace ::com::sun::star;
namespace cairocanvas
{
SpriteHelper::SpriteHelper() :
- mpSpriteCanvas(),
- mpBufferSurface(),
mbTextureDirty(true)
{}
@@ -52,8 +51,7 @@ namespace cairocanvas
mbTextureDirty = true;
// also init base class
- CanvasCustomSpriteHelper::init( rSpriteSize,
- rSpriteCanvas.get() );
+ CanvasCustomSpriteHelper::init( rSpriteSize, rSpriteCanvas );
}
void SpriteHelper::setSurface( const SurfaceSharedPtr& pBufferSurface )
@@ -83,7 +81,7 @@ namespace cairocanvas
const double fAlpha( getAlpha() );
const ::basegfx::B2DHomMatrix aTransform( getTransformation() );
- if( !(isActive() && !::basegfx::fTools::equalZero( fAlpha )) )
+ if( !isActive() || ::basegfx::fTools::equalZero( fAlpha ) )
return;
SAL_INFO( "canvas.cairo", "CanvasCustomSprite::redraw called");
@@ -131,7 +129,7 @@ namespace cairocanvas
rClip ));
doPolyPolygonImplementation( aClipPoly, Clip, pCairo.get(),
- nullptr, SurfaceProviderRef(mpSpriteCanvas.get()),
+ nullptr, SurfaceProviderRef(mpSpriteCanvas),
rClip->getFillRule() );
}
@@ -140,6 +138,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(),