fix rendering issues in iOS with aqua
This commit is contained in:
parent
2646b1594d
commit
a5351434fb
@ -47,7 +47,7 @@ namespace
|
||||
VDevBuffer();
|
||||
virtual ~VDevBuffer();
|
||||
|
||||
VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono);
|
||||
VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits);
|
||||
void free(VirtualDevice& rDevice);
|
||||
|
||||
// Timer virtuals
|
||||
@ -80,7 +80,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono)
|
||||
VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
|
||||
{
|
||||
::osl::MutexGuard aGuard(m_aMutex);
|
||||
VirtualDevice* pRetval = 0;
|
||||
@ -94,7 +94,7 @@ namespace
|
||||
{
|
||||
OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");
|
||||
|
||||
if((bMono && 1 == (*a)->GetBitCount()) || (!bMono && (*a)->GetBitCount() > 1))
|
||||
if(nBits == (*a)->GetBitCount())
|
||||
{
|
||||
// candidate is valid due to bit depth
|
||||
if(aFound != maFreeBuffers.end())
|
||||
@ -160,7 +160,7 @@ namespace
|
||||
// no success yet, create new buffer
|
||||
if(!pRetval)
|
||||
{
|
||||
pRetval = (bMono) ? new VirtualDevice(rOutDev, 1) : new VirtualDevice(rOutDev);
|
||||
pRetval = new VirtualDevice(rOutDev, nBits);
|
||||
pRetval->SetOutputSizePixel(rSizePixel, bClear);
|
||||
}
|
||||
else
|
||||
@ -233,7 +233,7 @@ namespace drawinglayer
|
||||
|
||||
if(isVisible())
|
||||
{
|
||||
mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false);
|
||||
mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
|
||||
|
||||
// #i93485# assert when copying from window to VDev is used
|
||||
OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
|
||||
@ -348,7 +348,7 @@ namespace drawinglayer
|
||||
OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
|
||||
if(!mpMask)
|
||||
{
|
||||
mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true);
|
||||
mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
|
||||
mpMask->SetMapMode(mpContent->GetMapMode());
|
||||
|
||||
// do NOT copy AA flag for mask!
|
||||
@ -362,7 +362,7 @@ namespace drawinglayer
|
||||
OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
|
||||
if(!mpAlpha)
|
||||
{
|
||||
mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false);
|
||||
mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 8);
|
||||
mpAlpha->SetMapMode(mpContent->GetMapMode());
|
||||
|
||||
// copy AA flag for new target; masking needs to be smooth
|
||||
|
@ -55,6 +55,7 @@ public:
|
||||
int mnWidth;
|
||||
int mnHeight;
|
||||
sal_uInt32 mnBytesPerRow;
|
||||
void* maExternalData;
|
||||
|
||||
public:
|
||||
QuartzSalBitmap();
|
||||
@ -70,6 +71,8 @@ public:
|
||||
virtual bool Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > xBitmapCanvas,
|
||||
Size& rSize,
|
||||
bool bMask = false );
|
||||
// creating quartz wrapper from existing buffer
|
||||
bool Create( BitmapBuffer& buffer);
|
||||
|
||||
void Destroy();
|
||||
|
||||
@ -93,6 +96,7 @@ private:
|
||||
|
||||
public:
|
||||
bool Create( CGLayerRef xLayer, int nBitCount, int nX, int nY, int nWidth, int nHeight );
|
||||
bool Create( CGImageRef xImage, int nBitCount, int nX, int nY, int nWidth, int nHeight );
|
||||
|
||||
public:
|
||||
CGImageRef CreateWithMask( const QuartzSalBitmap& rMask, int nX, int nY, int nWidth, int nHeight ) const;
|
||||
|
@ -62,6 +62,7 @@ QuartzSalBitmap::QuartzSalBitmap()
|
||||
, mnWidth(0)
|
||||
, mnHeight(0)
|
||||
, mnBytesPerRow(0)
|
||||
, maExternalData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -102,7 +103,63 @@ bool QuartzSalBitmap::Create( CGLayerRef xLayer, int nBitmapBits,
|
||||
|
||||
// copy layer content into the bitmap buffer
|
||||
const CGPoint aSrcPoint = { static_cast<CGFloat>(-nX), static_cast<CGFloat>(-nY) };
|
||||
CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
|
||||
if(mxGraphicContext) // remove warning
|
||||
CGContextDrawLayerAtPoint( mxGraphicContext, aSrcPoint, xLayer );
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
bool QuartzSalBitmap::Create( CGImageRef xImage, int nBitmapBits,
|
||||
int nX, int nY, int nWidth, int nHeight )
|
||||
{
|
||||
DBG_ASSERT( xImage, "QuartzSalBitmap::Create() from null image" );
|
||||
|
||||
// sanitize input parameters
|
||||
if( nX < 0 )
|
||||
nWidth += nX, nX = 0;
|
||||
if( nY < 0 )
|
||||
nHeight += nY, nY = 0;
|
||||
const CGSize aLayerSize = CGSizeMake(CGImageGetWidth(xImage), CGImageGetHeight(xImage));
|
||||
if( nWidth >= (int)aLayerSize.width - nX )
|
||||
nWidth = (int)aLayerSize.width - nX;
|
||||
if( nHeight >= (int)aLayerSize.height - nY )
|
||||
nHeight = (int)aLayerSize.height - nY;
|
||||
if( (nWidth < 0) || (nHeight < 0) )
|
||||
nWidth = nHeight = 0;
|
||||
|
||||
// initialize properties
|
||||
mnWidth = nWidth;
|
||||
mnHeight = nHeight;
|
||||
mnBits = nBitmapBits ? nBitmapBits : 32;
|
||||
|
||||
// initialize drawing context
|
||||
CreateContext();
|
||||
|
||||
// copy layer content into the bitmap buffer
|
||||
if(mxGraphicContext) // remove warning
|
||||
CGContextDrawImage( mxGraphicContext,
|
||||
CGRectMake(static_cast<CGFloat>(-nX),
|
||||
static_cast<CGFloat>(-nY),
|
||||
aLayerSize.width,
|
||||
aLayerSize.height),
|
||||
xImage );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuartzSalBitmap::Create( BitmapBuffer& buffer)
|
||||
{
|
||||
// initialize properties
|
||||
mnWidth = buffer.mnWidth;
|
||||
mnHeight = buffer.mnHeight;
|
||||
mnBits = buffer.mnBitCount;
|
||||
mnBytesPerRow = buffer.mnScanlineSize;
|
||||
maExternalData = buffer.mpBits;
|
||||
maPalette = buffer.maPalette;
|
||||
|
||||
// initialize drawing context
|
||||
CreateContext();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -168,6 +225,7 @@ void QuartzSalBitmap::Destroy()
|
||||
{
|
||||
DestroyContext();
|
||||
maUserBuffer.reset();
|
||||
maExternalData = NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -193,12 +251,16 @@ bool QuartzSalBitmap::CreateContext()
|
||||
|
||||
// prepare graphics context
|
||||
// convert image from user input if available
|
||||
const bool bSkipConversion = !maUserBuffer;
|
||||
const bool bSkipConversion = !maUserBuffer && !maExternalData;
|
||||
if( bSkipConversion )
|
||||
AllocateUserData();
|
||||
|
||||
// default to RGBA color space
|
||||
#ifdef IOS
|
||||
CGColorSpaceRef aCGColorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
#else
|
||||
CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace;
|
||||
#endif
|
||||
CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst;
|
||||
|
||||
// convert data into something accepted by CGBitmapContextCreate()
|
||||
@ -206,14 +268,28 @@ bool QuartzSalBitmap::CreateContext()
|
||||
sal_uInt32 nContextBytesPerRow = mnBytesPerRow;
|
||||
if( (mnBits == 16) || (mnBits == 32) )
|
||||
{
|
||||
// no conversion needed for truecolor
|
||||
maContextBuffer = maUserBuffer;
|
||||
if (!maExternalData)
|
||||
{
|
||||
// no conversion needed for truecolor
|
||||
maContextBuffer = maUserBuffer;
|
||||
}
|
||||
}
|
||||
else if( (mnBits == 8) && maPalette.IsGreyPalette() )
|
||||
else if( mnBits == 8
|
||||
#ifndef IOS
|
||||
&& maPalette.IsGreyPalette()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// no conversion needed for grayscale
|
||||
maContextBuffer = maUserBuffer;
|
||||
if (!maExternalData)
|
||||
{
|
||||
maContextBuffer = maUserBuffer;
|
||||
}
|
||||
#ifdef IOS
|
||||
aCGColorSpace = CGColorSpaceCreateDeviceGray();
|
||||
#else
|
||||
aCGColorSpace = GetSalData()->mxGraySpace;
|
||||
#endif
|
||||
aCGBmpInfo = kCGImageAlphaNone;
|
||||
bitsPerComponent = mnBits;
|
||||
}
|
||||
@ -237,9 +313,14 @@ bool QuartzSalBitmap::CreateContext()
|
||||
}
|
||||
}
|
||||
|
||||
if( maContextBuffer.get() )
|
||||
if(maExternalData)
|
||||
{
|
||||
mxGraphicContext = CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
|
||||
mxGraphicContext = ::CGBitmapContextCreate( maExternalData, mnWidth, mnHeight,
|
||||
bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
|
||||
}
|
||||
else if( maContextBuffer.get() )
|
||||
{
|
||||
mxGraphicContext = ::CGBitmapContextCreate( maContextBuffer.get(), mnWidth, mnHeight,
|
||||
bitsPerComponent, nContextBytesPerRow, aCGColorSpace, aCGBmpInfo );
|
||||
}
|
||||
|
||||
@ -280,7 +361,7 @@ bool QuartzSalBitmap::AllocateUserData()
|
||||
catch( const std::bad_alloc& )
|
||||
{
|
||||
OSL_FAIL( "vcl::QuartzSalBitmap::AllocateUserData: bad alloc" );
|
||||
maUserBuffer.reset();
|
||||
maUserBuffer.reset( static_cast<sal_uInt8*>(NULL) );
|
||||
mnBytesPerRow = 0;
|
||||
}
|
||||
|
||||
@ -771,7 +852,7 @@ CGImageRef QuartzSalBitmap::CreateWithMask( const QuartzSalBitmap& rMask,
|
||||
|
||||
// CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
|
||||
// TODO: isolate in an extra method?
|
||||
if( !CGImageIsMask(xMask) || (CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
|
||||
if( !CGImageIsMask(xMask) || rMask.GetBitCount() != 8)//(CGImageGetColorSpace(xMask) != GetSalData()->mxGraySpace) )
|
||||
{
|
||||
const CGRect xImageRect=CGRectMake( 0, 0, nWidth, nHeight );//the rect has no offset
|
||||
|
||||
|
@ -806,6 +806,8 @@ bool SvpSalGraphics::CheckContext()
|
||||
{
|
||||
if (mbForeignContext)
|
||||
return true;
|
||||
if(m_aDevice == NULL) // fix tiledrendering crash when changing content size
|
||||
return false;
|
||||
|
||||
const basegfx::B2IVector size = m_aDevice->getSize();
|
||||
const basegfx::B2IVector bufferSize = m_aDevice->getBufferSize();
|
||||
@ -829,32 +831,14 @@ bool SvpSalGraphics::CheckContext()
|
||||
kCGImageAlphaNone);
|
||||
break;
|
||||
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_RGBA:
|
||||
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
|
||||
bufferSize.getX(), bufferSize.getY(),
|
||||
8, scanlineStride,
|
||||
CGColorSpaceCreateDeviceRGB(),
|
||||
kCGImageAlphaNoneSkipLast);
|
||||
break;
|
||||
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ARGB:
|
||||
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
|
||||
bufferSize.getX(), bufferSize.getY(),
|
||||
8, scanlineStride,
|
||||
CGColorSpaceCreateDeviceRGB(),
|
||||
kCGImageAlphaNoneSkipFirst);
|
||||
break;
|
||||
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ABGR:
|
||||
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_BGRA:
|
||||
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
|
||||
bufferSize.getX(), bufferSize.getY(),
|
||||
8, scanlineStride,
|
||||
CGColorSpaceCreateDeviceRGB(),
|
||||
kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
|
||||
break;
|
||||
case basebmp::FORMAT_THIRTYTWO_BIT_TC_MASK_ABGR:
|
||||
mrContext = CGBitmapContextCreate(pixelBuffer.get(),
|
||||
bufferSize.getX(), bufferSize.getY(),
|
||||
8, scanlineStride,
|
||||
CGColorSpaceCreateDeviceRGB(),
|
||||
kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Little);
|
||||
kCGImageAlphaNoneSkipFirst);//kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
|
||||
break;
|
||||
default:
|
||||
SAL_WARN( "vcl.ios", "CheckContext: unsupported color format " << basebmp::formatName( m_aDevice->getScanlineFormat() ) );
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
#ifdef IOS
|
||||
#include "saldatabasic.hxx"
|
||||
#include "headless/svpbmp.hxx"
|
||||
#include <basegfx/range/b2ibox.hxx>
|
||||
#endif
|
||||
|
||||
using namespace vcl;
|
||||
@ -285,12 +287,6 @@ static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_
|
||||
|
||||
void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGraphics )
|
||||
{
|
||||
#ifdef IOS
|
||||
// Horrible horrible this is all crack, mxLayer is always NULL on iOS,
|
||||
// all this stuff should be rewritten anyway for iOS
|
||||
if( !mxLayer )
|
||||
return;
|
||||
#endif
|
||||
|
||||
if( !pSrcGraphics )
|
||||
{
|
||||
@ -335,12 +331,9 @@ void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSrcGrap
|
||||
const CGPoint aDstPoint = CGPointMake(+rPosAry.mnDestX - rPosAry.mnSrcX, rPosAry.mnDestY - rPosAry.mnSrcY);
|
||||
if( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth &&
|
||||
rPosAry.mnSrcHeight == rPosAry.mnDestHeight) &&
|
||||
(!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher
|
||||
(!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth)
|
||||
&& pSrc->mxLayer ) // workaround a Quartz crasher
|
||||
{
|
||||
#ifdef IOS
|
||||
if( !CheckContext() )
|
||||
return;
|
||||
#endif
|
||||
// in XOR mode the drawing context is redirected to the XOR mask
|
||||
// if source and target are identical then copyBits() paints onto the target context though
|
||||
CGContextRef xCopyContext = mrContext;
|
||||
@ -895,6 +888,25 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol
|
||||
// #i97317# workaround for Quartz having problems with drawing small polygons
|
||||
if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) )
|
||||
{
|
||||
// prepare drawing mode
|
||||
CGPathDrawingMode eMode;
|
||||
if( IsBrushVisible() && IsPenVisible() )
|
||||
{
|
||||
eMode = kCGPathEOFillStroke;
|
||||
}
|
||||
else if( IsPenVisible() )
|
||||
{
|
||||
eMode = kCGPathStroke;
|
||||
}
|
||||
else if( IsBrushVisible() )
|
||||
{
|
||||
eMode = kCGPathEOFill;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// use the path to prepare the graphics context
|
||||
CGContextSaveGState( mrContext );
|
||||
CGContextBeginPath( mrContext );
|
||||
@ -903,7 +915,7 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol
|
||||
// draw path with antialiased polygon
|
||||
CGContextSetShouldAntialias( mrContext, true );
|
||||
CGContextSetAlpha( mrContext, 1.0 - fTransparency );
|
||||
CGContextDrawPath( mrContext, kCGPathEOFillStroke );
|
||||
CGContextDrawPath( mrContext, eMode );
|
||||
CGContextRestoreGState( mrContext );
|
||||
|
||||
// mark modified rectangle as updated
|
||||
@ -1145,18 +1157,56 @@ sal_uInt16 AquaSalGraphics::GetBitCount() const
|
||||
|
||||
SalBitmap* AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
|
||||
{
|
||||
DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" );
|
||||
|
||||
ApplyXorContext();
|
||||
|
||||
QuartzSalBitmap* pBitmap = new QuartzSalBitmap;
|
||||
if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY) )
|
||||
if (!mbForeignContext && m_aDevice != NULL)
|
||||
{
|
||||
delete pBitmap;
|
||||
pBitmap = NULL;
|
||||
}
|
||||
// on ios virtual device are Svp so use Svp bitmap to get the content
|
||||
basegfx::B2IBox aRect( nX, nY, nX+nDX, nY+nDY );
|
||||
basebmp::BitmapDeviceSharedPtr aSubSet = basebmp::subsetBitmapDevice(m_aDevice , aRect );
|
||||
|
||||
return pBitmap;
|
||||
SvpSalBitmap* pSalBitmap = new SvpSalBitmap;
|
||||
pSalBitmap->setBitmap(aSubSet);
|
||||
BitmapBuffer* pBuffer = pSalBitmap->AcquireBuffer(true);
|
||||
QuartzSalBitmap* pBitmap = new QuartzSalBitmap;
|
||||
if( !pBitmap->Create(*pBuffer))
|
||||
{
|
||||
delete pBitmap;
|
||||
pBitmap = NULL;
|
||||
}
|
||||
pSalBitmap->ReleaseBuffer(pBuffer, true);
|
||||
delete pSalBitmap;
|
||||
return pBitmap;
|
||||
}
|
||||
else if (mbForeignContext)
|
||||
{
|
||||
//if using external context like on ios, check if we can get a backing image and copy it
|
||||
CGImageRef backImage = CGBitmapContextCreateImage(mrContext);
|
||||
if (backImage)
|
||||
{
|
||||
QuartzSalBitmap* pBitmap = new QuartzSalBitmap;
|
||||
if( !pBitmap->Create(backImage, mnBitmapDepth, nX, nY, nDX, nDY))
|
||||
{
|
||||
delete pBitmap;
|
||||
pBitmap = NULL;
|
||||
}
|
||||
CGImageRelease(backImage);
|
||||
return pBitmap;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_ASSERT( mxLayer, "AquaSalGraphics::getBitmap() with no layer" );
|
||||
|
||||
ApplyXorContext();
|
||||
|
||||
QuartzSalBitmap* pBitmap = new QuartzSalBitmap;
|
||||
if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY) )
|
||||
{
|
||||
delete pBitmap;
|
||||
pBitmap = NULL;
|
||||
}
|
||||
return pBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IOS
|
||||
|
Loading…
x
Reference in New Issue
Block a user