summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Lillqvist <tml@collabora.com>2014-04-07 17:48:22 +0300
committerTor Lillqvist <tml@collabora.com>2014-04-07 17:56:04 +0300
commit801a8cd336426327724b0157141a00c8d2a9ae96 (patch)
tree5806322eeb63c7d220b35d6f2b7aa1a9444f3786
parent57b44c3c66668794b5a180cc91f82e25a8fae92d (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.m26
-rw-r--r--vcl/quartz/salgdicommon.cxx141
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