diff options
author | Tor Lillqvist <tml@collabora.com> | 2014-04-07 17:48:22 +0300 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2014-04-07 17:56:04 +0300 |
commit | 801a8cd336426327724b0157141a00c8d2a9ae96 (patch) | |
tree | 5806322eeb63c7d220b35d6f2b7aa1a9444f3786 | |
parent | 57b44c3c66668794b5a180cc91f82e25a8fae92d (diff) |
Add somewhat ridiculous debug hacks for CoreGrahics drawing debugging on iOS
When the environment variable DRAW_INCREMENTALLY_FROM is set to a
number, we want TiledLibreOffice to loop, initially performing only
that number of drawing operations in AquaSalGraphics, then wait for
some seconds, and redraw. Next time perform one operation
more. Repeat.
Implemented in vcl by surrounding the entry and exit(s) of the drawing
functions in AquaSalGraphics with macros.
All this is active only for iOS and in a dbgutil build.
-rw-r--r-- | ios/experimental/TiledLibreOffice/TiledLibreOffice/TiledView.m | 26 | ||||
-rw-r--r-- | vcl/quartz/salgdicommon.cxx | 141 |
2 files changed, 165 insertions, 2 deletions
diff --git a/ios/experimental/TiledLibreOffice/TiledLibreOffice/TiledView.m b/ios/experimental/TiledLibreOffice/TiledLibreOffice/TiledView.m index 80680dd52269..aafbd430682e 100644 --- a/ios/experimental/TiledLibreOffice/TiledLibreOffice/TiledView.m +++ b/ios/experimental/TiledLibreOffice/TiledLibreOffice/TiledView.m @@ -82,6 +82,20 @@ static void updateTilesPerSecond(UILabel *label) } } +static int DBG_DRAW_DELAY = 10; +int DBG_DRAW_ROUNDS = -1; +int DBG_DRAW_COUNTER = 0; +int DBG_DRAW_ROUNDS_MAX = INT_MAX; + +- (void)redraw +{ + DBG_DRAW_ROUNDS++; + DBG_DRAW_COUNTER = 0; + [self setNeedsDisplay]; + if (DBG_DRAW_ROUNDS < DBG_DRAW_ROUNDS_MAX) + [NSTimer scheduledTimerWithTimeInterval:DBG_DRAW_DELAY target:self selector:@selector(redraw) userInfo:nil repeats:NO]; +} + - (id)initWithFrame:(CGRect)frame scale:(CGFloat)scale maxZoom:(int)maxZoom { self = [super initWithFrame:frame]; @@ -93,6 +107,13 @@ static void updateTilesPerSecond(UILabel *label) catl.levelsOfDetailBias = catl.levelsOfDetail - 1; [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTilesPerSecond) userInfo:nil repeats:YES]; + if (getenv("DRAW_INCREMENTALLY_FROM")) { + DBG_DRAW_ROUNDS = atoi(getenv("DRAW_INCREMENTALLY_FROM")); + if (getenv("DRAW_INCREMENTALLY_DELAY") && + atoi(getenv("DRAW_INCREMENTALLY_DELAY")) > 1) + DBG_DRAW_DELAY = atoi(getenv("DRAW_INCREMENTALLY_DELAY")); + [NSTimer scheduledTimerWithTimeInterval:DBG_DRAW_DELAY target:self selector:@selector(redraw) userInfo:nil repeats:NO]; + } } return self; } @@ -138,12 +159,13 @@ static bool tileMatches(const char *spec, CGRect bb) // as needed at the current zoom levels. I keep thinking about // "pixels" incorrectly. - if (!getenv("DRAW_ONLY_TILE") || tileMatches(getenv("DRAW_ONLY_TILE"), bb)) + if (!getenv("DRAW_ONLY_TILE") || tileMatches(getenv("DRAW_ONLY_TILE"), bb)) { + fprintf(stderr, "+++ rendering to context %p\n", ctx); touch_lo_draw_tile(ctx, tileSize.width, tileSize.height, CGPointMake(bb.origin.x/self.scale, bb.origin.y/self.scale), CGSizeMake(bb.size.width/self.scale, bb.size.height/self.scale)); - else { + } else { CGContextSetRGBFillColor(ctx, 1, 1, 1, 1); CGContextFillRect(ctx, CGRectMake(0, 0, bb.size.width, bb.size.height)); } diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index 873f18851b8a..8591b633d5c4 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -40,6 +40,33 @@ #include <basegfx/range/b2ibox.hxx> #endif +#if defined(IOS) && defined(DBG_UTIL) + +// Variables in TiledView.m +extern int DBG_DRAW_ROUNDS, DBG_DRAW_COUNTER, DBG_DRAW_DEPTH; + +#define DBG_DRAW_OPERATION(s,v) \ + do { \ + if (DBG_DRAW_ROUNDS >= 0) { \ + if (DBG_DRAW_COUNTER++ > DBG_DRAW_ROUNDS) \ + return v; \ + SAL_DEBUG("===> " << s << " " << DBG_DRAW_COUNTER); \ + } \ + } while (false) + +#define DBG_DRAW_OPERATION_EXIT(s) \ + do { \ + if (DBG_DRAW_ROUNDS >= 0) \ + SAL_DEBUG("<=== " << s << " " << DBG_DRAW_COUNTER); \ + } while (false) + +#else + +#define DBG_DRAW_OPERATION(s) /* empty */ +#define DBG_DRAW_OPERATION_EXIT(s) /* empty */ + +#endif + using namespace vcl; typedef std::vector<unsigned char> ByteVector; @@ -539,15 +566,20 @@ bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) { + DBG_DRAW_OPERATION("drawAlphaBitmap", true); + // An image mask can't have a depth > 8 bits (should be 1 to 8 bits) if( rAlphaBmp.GetBitCount() > 8 ) { + DBG_DRAW_OPERATION_EXIT("drawAlphaBitmap"); return false; } + // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx) // horizontal/vertical mirroring not implemented yet if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 ) { + DBG_DRAW_OPERATION_EXIT("drawAlphaBitmap"); return false; } @@ -558,8 +590,10 @@ bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, rTR.mnSrcHeight ); if( !xMaskedImage ) { + DBG_DRAW_OPERATION_EXIT("drawAlphaBitmap"); return false; } + if ( CheckContext() ) { const CGRect aDstRect = CGRectMake( rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight); @@ -570,6 +604,8 @@ bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, CG_TRACE("CGImageRelease(" << xMaskedImage << ")"); CGImageRelease(xMaskedImage); + + DBG_DRAW_OPERATION_EXIT("drawAlphaBitmap"); return true; } @@ -577,8 +613,13 @@ bool AquaSalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSrcBitmap, const SalBitmap* pAlphaBmp ) { + DBG_DRAW_OPERATION("drawTransformedBitmap", true); + if( !CheckContext() ) + { + DBG_DRAW_OPERATION_EXIT("drawTransformedBitmap"); return true; + } // get the Quartz image CGImageRef xImage = NULL; @@ -590,7 +631,10 @@ bool AquaSalGraphics::drawTransformedBitmap( else xImage = rSrcSalBmp.CreateWithMask( *pMaskSalBmp, 0, 0, (int)aSize.Width(), (int)aSize.Height() ); if( !xImage ) + { + DBG_DRAW_OPERATION_EXIT("drawTransformedBitmap"); return false; + } // setup the image transformation // using the rNull,rX,rY points as destinations for the (0,0),(0,Width),(Height,0) source points @@ -618,16 +662,22 @@ bool AquaSalGraphics::drawTransformedBitmap( // mark the destination as painted const CGRect aDstRect = CGRectApplyAffineTransform( aSrcRect, aCGMat ); RefreshRect( aDstRect ); + + DBG_DRAW_OPERATION_EXIT("drawTransformedBitmap"); return true; } bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) { + DBG_DRAW_OPERATION("drawAlphaRect", true); + if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawAlphaRect"); return true; } + // save the current state CG_TRACE( "CGContextSaveGState(" << mrContext << ") " << ++mnContextStackDepth ); CGContextSaveGState( mrContext ); @@ -652,20 +702,27 @@ bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, CG_TRACE("CGContextRestoreGState(" << mrContext << ") " << mnContextStackDepth--); CGContextRestoreGState(mrContext); RefreshRect( aRect ); + + DBG_DRAW_OPERATION_EXIT("drawAlphaRect"); return true; } void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) { + DBG_DRAW_OPERATION("drawBitmap",); + if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawBitmap"); return; } + const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap); CGImageRef xImage = rBitmap.CreateCroppedImage( (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight ); if( !xImage ) { + DBG_DRAW_OPERATION_EXIT("drawBitmap"); return; } @@ -675,6 +732,8 @@ void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rS CG_TRACE( "CGImageRelease(" << xImage << ")" ); CGImageRelease( xImage ); RefreshRect( aDstRect ); + + DBG_DRAW_OPERATION_EXIT("drawBitmap"); } void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,SalColor ) @@ -686,16 +745,21 @@ void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rS void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap ) { + DBG_DRAW_OPERATION("drawBitmap",); + if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawBitmap"); return; } + const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap); const QuartzSalBitmap& rMask = static_cast<const QuartzSalBitmap&>(rTransparentBitmap); CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight ) ); if( !xMaskedImage ) { + DBG_DRAW_OPERATION_EXIT("drawBitmap"); return; } @@ -705,6 +769,8 @@ void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rS CG_TRACE( "CGImageRelease(" << xMaskedImage << ")" ); CGImageRelease( xMaskedImage ); RefreshRect( aDstRect ); + + DBG_DRAW_OPERATION_EXIT("drawBitmap"); } #ifndef IOS @@ -761,17 +827,23 @@ bool AquaSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void AquaSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) { + DBG_DRAW_OPERATION("drawLine",); + if( nX1 == nX2 && nY1 == nY2 ) { // #i109453# platform independent code expects at least one pixel to be drawn drawPixel( nX1, nY1 ); + + DBG_DRAW_OPERATION_EXIT("drawLine"); return; } if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawLine"); return; } + CG_TRACE( "CGContextBeginPath(" << mrContext << ")" ); CGContextBeginPath( mrContext ); CG_TRACE( "CGContextMoveToPoint(" << mrContext << "," << static_cast<float>(nX1)+0.5 << "," << static_cast<float>(nY1)+0.5 << ")" ); @@ -784,20 +856,27 @@ void AquaSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) Rectangle aRefreshRect( nX1, nY1, nX2, nY2 ); (void) aRefreshRect; // Is a call to RefreshRect( aRefreshRect ) missing here? + + DBG_DRAW_OPERATION_EXIT("drawLine"); } void AquaSalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, SalColor nMaskColor ) { + DBG_DRAW_OPERATION("drawMask",); + if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawMask"); return; } + const QuartzSalBitmap& rBitmap = static_cast<const QuartzSalBitmap&>(rSalBitmap); CGImageRef xImage = rBitmap.CreateColorMask( rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, nMaskColor ); if( !xImage ) { + DBG_DRAW_OPERATION_EXIT("drawMask"); return; } @@ -807,6 +886,8 @@ void AquaSalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap& rSal CG_TRACE( "CGImageRelease(" << xImage << ")" ); CGImageRelease( xImage ); RefreshRect( aDstRect ); + + DBG_DRAW_OPERATION_EXIT("drawMask"); } void AquaSalGraphics::drawPixel( long nX, long nY ) @@ -828,31 +909,41 @@ bool AquaSalGraphics::drawPolyLine( basegfx::B2DLineJoin eLineJoin, com::sun::star::drawing::LineCap eLineCap) { + DBG_DRAW_OPERATION("drawPolyLine", true); + // short circuit if there is nothing to do const int nPointCount = rPolyLine.count(); if( nPointCount <= 0 ) { + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return true; } + // reject requests that cannot be handled yet if( rLineWidths.getX() != rLineWidths.getY() ) { + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return false; } + #ifdef IOS if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return false; } #endif + // #i101491# Aqua does not support B2DLINEJOIN_NONE; return false to use // the fallback (own geometry preparation) // #i104886# linejoin-mode and thus the above only applies to "fat" lines if( (basegfx::B2DLINEJOIN_NONE == eLineJoin) && (rLineWidths.getX() > 1.3) ) { + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return false; } + // setup line attributes CGLineJoin aCGLineJoin = kCGLineJoinMiter; switch( eLineJoin ) @@ -922,6 +1013,7 @@ bool AquaSalGraphics::drawPolyLine( CG_TRACE( "CGPathRelease(" << xPath << ")" ); CGPathRelease( xPath ); + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return true; } @@ -933,17 +1025,23 @@ bool AquaSalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const sal bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency ) { + DBG_DRAW_OPERATION("drawPolyPolygon", true); + // short circuit if there is nothing to do const int nPolyCount = rPolyPoly.count(); if( nPolyCount <= 0 ) { + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return true; } + // ignore invisible polygons if( (fTransparency >= 1.0) || (fTransparency < 0) ) { + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return true; } + // setup poly-polygon path CGMutablePathRef xPath = CGPathCreateMutable(); CG_TRACE( "CGPathCreateMutable() = " << xPath ); @@ -954,6 +1052,7 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol } const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); + CG_TRACE( "CGPathGetBoundingBox(" << xPath << ") = " << aRefreshRect ); // #i97317# workaround for Quartz having problems with drawing small polygons if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) { @@ -976,6 +1075,7 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" ); CG_TRACE( "CGPathRelease(" << xPath << ")" ); CGPathRelease( xPath ); + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return true; } @@ -1003,15 +1103,25 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol CG_TRACE( "CGPathRelease(" << xPath << ")" ); CGPathRelease( xPath ); + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return true; } void AquaSalGraphics::drawPolyPolygon( sal_uInt32 nPolyCount, const sal_uInt32 *pPoints, PCONSTSALPOINT *ppPtAry ) { + DBG_DRAW_OPERATION("drawPolyPolygon",); + if( nPolyCount <= 0 ) + { + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return; + } + if( !CheckContext() ) + { + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return; + } // find bound rect long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0; @@ -1056,8 +1166,11 @@ void AquaSalGraphics::drawPolyPolygon( sal_uInt32 nPolyCount, const sal_uInt32 * } else { + SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" ); + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); return; } + // convert to CGPath CG_TRACE( "CGContextBeginPath(" << mrContext << ")" ); CGContextBeginPath( mrContext ); @@ -1117,14 +1230,25 @@ void AquaSalGraphics::drawPolyPolygon( sal_uInt32 nPolyCount, const sal_uInt32 * CGContextDrawPath( mrContext, eMode ); RefreshRect( leftX, topY, maxWidth, maxHeight ); + + DBG_DRAW_OPERATION_EXIT("drawPolyPolygon"); } void AquaSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint *pPtAry ) { + DBG_DRAW_OPERATION("drawPolygon",); + if( nPoints <= 1 ) + { + DBG_DRAW_OPERATION_EXIT("drawPolygon"); return; + } + if( !CheckContext() ) + { + DBG_DRAW_OPERATION_EXIT("drawPolygon"); return; + } long nX = 0, nY = 0, nWidth = 0, nHeight = 0; getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); @@ -1144,8 +1268,10 @@ void AquaSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint *pPtAry ) } else { + SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" ); return; } + CG_TRACE( "CGContextBeginPath(" << mrContext << ")" ); CGContextBeginPath( mrContext ); @@ -1180,6 +1306,8 @@ void AquaSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint *pPtAry ) CG_TRACE( "CGContextDrawPath(" << mrContext << "," << eMode << ")" ); CGContextDrawPath( mrContext, eMode ); RefreshRect( nX, nY, nWidth, nHeight ); + + DBG_DRAW_OPERATION_EXIT("drawPolygon"); } bool AquaSalGraphics::drawPolygonBezier( sal_uInt32, const SalPoint*, const sal_uInt8* ) @@ -1195,10 +1323,14 @@ bool AquaSalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*, void AquaSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) { + DBG_DRAW_OPERATION("drawRect",); + if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawRect"); return; } + CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) ); if( IsPenVisible() ) { @@ -1219,16 +1351,23 @@ void AquaSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) CGContextStrokeRect( mrContext, aRect ); } RefreshRect( nX, nY, nWidth, nHeight ); + + DBG_DRAW_OPERATION_EXIT("drawRect"); } void AquaSalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry ) { + DBG_DRAW_OPERATION("drawPolyLine",); + if( nPoints < 1 ) { + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return; } + if( !CheckContext() ) { + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); return; } @@ -1252,6 +1391,8 @@ void AquaSalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry ) CGContextDrawPath( mrContext, kCGPathStroke ); RefreshRect( nX, nY, nWidth, nHeight ); + + DBG_DRAW_OPERATION_EXIT("drawPolyLine"); } sal_uInt16 AquaSalGraphics::GetBitCount() const |