diff options
Diffstat (limited to 'canvas/source/cairo/cairo_spritehelper.cxx')
-rw-r--r-- | canvas/source/cairo/cairo_spritehelper.cxx | 43 |
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(), |